Skip to content

feat(tools): add TwelveLabs video analysis tool#6336

Open
mohit-twelvelabs wants to merge 1 commit into
crewAIInc:mainfrom
mohit-twelvelabs:feat/twelvelabs-integration
Open

feat(tools): add TwelveLabs video analysis tool#6336
mohit-twelvelabs wants to merge 1 commit into
crewAIInc:mainfrom
mohit-twelvelabs:feat/twelvelabs-integration

Conversation

@mohit-twelvelabs

@mohit-twelvelabs mohit-twelvelabs commented Jun 25, 2026

Copy link
Copy Markdown

Hi! I'm Mohit, I work at TwelveLabs (@mohit-twelvelabs).

What this adds

A new opt-in TwelveLabsAnalyzeTool in crewai-tools that analyzes video content with TwelveLabs' Pegasus video-understanding model. Given a video — either a public URL or an already-indexed video_id — and a natural-language prompt, it returns a text answer generated from the video's visuals, speech, and on-screen text. Useful for video summarization, Q&A over video, content moderation, and metadata extraction.

from crewai_tools import TwelveLabsAnalyzeTool

tool = TwelveLabsAnalyzeTool()
result = tool.run(
    prompt="Summarize this video in three bullet points.",
    video_url="https://example.com/my-video.mp4",
)

Why it helps crewAI

crewAI agents can already reason over text, images (VisionTool), and web content, but there's no first-class way to give an agent an understanding of video. This tool closes that gap, letting agents answer questions about, summarize, or moderate video content as part of a crew.

Opt-in / non-breaking

  • New tool only — no existing behavior, defaults, or imports are changed.
  • The twelvelabs SDK is added as an optional dependency ([project.optional-dependencies] twelvelabs); the base package still imports without it (lazy import inside __init__, mirroring ScrapegraphScrapeTool and other SDK-backed tools).
  • Registered in both crewai_tools/__init__.py and crewai_tools/tools/__init__.py, with package_dependencies and env_vars (TWELVELABS_API_KEY) declared the same way as sibling tools.

How it was tested

  • Added lib/crewai-tools/tests/tools/twelvelabs_analyze_tool_test.py: no-network unit tests (SDK client mocked) covering API-key validation, required-input validation, video_id and video_url request wiring, plus a live integration test gated on TWELVELABS_API_KEY (skipped without it).
  • uv run ruff check and uv run ruff format clean on all changed files; uv run mypy passes on the new tool.
  • Regenerated tool.specs.json so the new tool's spec is included.
  • Verified the Pegasus analyze wiring end-to-end against the live API (auth, model_name, prompt, max_tokens all validated server-side).

Notes

Per CONTRIBUTING.md, this PR was prepared with AI assistance, so it should carry the llm-generated label — I'm disclosing that here and will add the label.

You can grab a free API key at https://twelvelabs.io — there's a generous free tier.

Summary by CodeRabbit

  • New Features

    • Added a new video analysis tool powered by TwelveLabs, usable with either a public video URL or an indexed video ID.
    • Exposed the tool in the package so it can be imported directly by users.
  • Documentation

    • Added usage guides and reference docs for setup, configuration, and example workflows.
    • Updated the tools catalog to include the new AI-powered option.
  • Tests

    • Added automated coverage for input validation and core usage paths, plus an optional live integration check.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new TwelveLabsAnalyzeTool implementation with package exports and dependency metadata, plus docs, README entries, and tests covering credential handling and analysis requests.

Changes

TwelveLabs video analysis

Layer / File(s) Summary
Tool contract and package wiring
lib/crewai-tools/tool.specs.json, lib/crewai-tools/pyproject.toml, lib/crewai-tools/src/crewai_tools/__init__.py, lib/crewai-tools/src/crewai_tools/tools/__init__.py
Adds the TwelveLabs tool spec, the twelvelabs optional dependency extra, and exports for TwelveLabsAnalyzeTool and TwelveLabsAnalyzeToolSchema.
Tool schema and runtime
lib/crewai-tools/src/crewai_tools/tools/twelvelabs_analyze_tool/twelvelabs_analyze_tool.py
Defines the input schema, resolves TwelveLabs credentials, instantiates the client, and sends analyze requests using video_url or video_id.
Tests and documentation
lib/crewai-tools/tests/tools/twelvelabs_analyze_tool_test.py, docs/docs.json, docs/edge/en/tools/ai-ml/twelvelabsanalyzetool.mdx, lib/crewai-tools/src/crewai_tools/tools/twelvelabs_analyze_tool/README.md, lib/crewai-tools/README.md
Adds unit and integration tests plus documentation pages and READMEs for the new tool.

Sequence Diagram(s)

sequenceDiagram
  participant CrewAIAgent as CrewAI agent
  participant TwelveLabsAnalyzeTool
  participant TWELVELABS_API_KEY as TWELVELABS_API_KEY env var
  participant TwelveLabsSDKClient as TwelveLabs SDK client
  participant TwelveLabsAPI as TwelveLabs API

  CrewAIAgent->>TwelveLabsAnalyzeTool: __init__(api_key or env lookup)
  TwelveLabsAnalyzeTool->>TWELVELABS_API_KEY: read api_key when needed
  TWELVELABS_API_KEY-->>TwelveLabsAnalyzeTool: api_key
  TwelveLabsAnalyzeTool->>TwelveLabsSDKClient: create client
  CrewAIAgent->>TwelveLabsAnalyzeTool: run(prompt, video_url or video_id)
  TwelveLabsAnalyzeTool->>TwelveLabsSDKClient: analyze(model_name, prompt, max_tokens, temperature, video)
  TwelveLabsSDKClient->>TwelveLabsAPI: send analyze request
  TwelveLabsAPI-->>TwelveLabsSDKClient: response.data
  TwelveLabsSDKClient-->>TwelveLabsAnalyzeTool: response
  TwelveLabsAnalyzeTool-->>CrewAIAgent: response.data or ""
Loading

Suggested reviewers

  • vinibrsl
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% 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 clearly matches the main change: adding the TwelveLabs video analysis tool.
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.

@corridor-security corridor-security 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.

Security Issues

  • Server-Side Request Forgery
    The new TwelveLabsAnalyzeTool accepts a caller-supplied video_url and forwards it to the TwelveLabs SDK without validate_url, allowing restricted schemes or hosts such as loopback, link-local, metadata, or private-network addresses to be submitted through the video analysis integration.

Summary: This PR adds a new TwelveLabs video-analysis tool that sends user-provided prompts and either video IDs or video URLs to an external SDK/API.

Risk: Medium risk. The new tool introduces an external URL-processing attack surface, and the added URL path lacks the repository-required SSRF validation before handing caller-controlled URLs to the integration.

Recommendations:

  • Validate video_url with crewai_tools.security.safe_path.validate_url before constructing VideoContext_Url, and use only the validated URL for the SDK call.

if video_id:
analyze_kwargs["video_id"] = video_id
else:
from twelvelabs.types.video_context import VideoContext_Url

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The video_url parameter is caller-controlled and is passed into the TwelveLabs URL context without the repository's SSRF guardrail:

from twelvelabs.types.video_context import VideoContext_Url

analyze_kwargs["video"] = VideoContext_Url(url=video_url)

An attacker who can invoke this tool can supply loopback, link-local/cloud-metadata, private-network, or non-HTTP(S) URLs and cause the video analysis integration to process restricted locations.

Remediation: Import validate_url from crewai_tools.security.safe_path, call it before constructing VideoContext_Url, and pass only the validated URL to the SDK.

For more details, see the finding in Corridor.

Provide feedback: Reply with whether this is a valid vulnerability or false positive to help improve Corridor's accuracy.

@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/twelvelabs_analyze_tool/twelvelabs_analyze_tool.py (1)

64-66: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Optional: validate max_tokens >= 512.

The docstring states Pegasus requires at least 512 tokens, but a caller can override max_tokens to a smaller value, which would surface as an opaque API error inside _run. Consider validating early for a clearer message. Low priority since the default (2048) is already valid.

🤖 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/twelvelabs_analyze_tool/twelvelabs_analyze_tool.py`
around lines 64 - 66, Add early validation in TwelveLabsAnalyzeTool so
overridden max_tokens values below 512 are rejected before _run makes the API
call. Update the class field handling around model_name, max_tokens, and
temperature to enforce the Pegasus minimum with a clear error message, keeping
the existing default of 2048 unchanged.
🤖 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/twelvelabs_analyze_tool/twelvelabs_analyze_tool.py`:
- Around line 130-142: The TwelveLabs import in the fallback path of
TwelvelabsAnalyzeTool.analyze uses an internal module path, so update the
VideoContext_Url import to the public stable SDK API exposed by
twelvelabs.types. Keep the existing analyze_kwargs logic in
TwelvelabsAnalyzeTool.analyze, but change the import used when video_id is
absent so the `video` keyword is still passed a VideoContext_Url instance while
relying on the supported import surface.

In `@lib/crewai-tools/tests/tools/twelvelabs_analyze_tool_test.py`:
- Around line 11-15: The test setup in _make_tool and the related twelvelabs
imports assume the optional SDK package exists, but patching
twelvelabs.TwelveLabs with create=True will not create a missing module. Update
the test fixture to inject fake twelvelabs package modules into sys.modules
before importing or patching TwelveLabsAnalyzeTool, and also stub
twelvelabs.types.video_context.VideoContext_Url so the VideoContext_Url-based
test can run without the real dependency. Use the existing _make_tool helper and
the test that references VideoContext_Url as the main locations to adjust.

---

Nitpick comments:
In
`@lib/crewai-tools/src/crewai_tools/tools/twelvelabs_analyze_tool/twelvelabs_analyze_tool.py`:
- Around line 64-66: Add early validation in TwelveLabsAnalyzeTool so overridden
max_tokens values below 512 are rejected before _run makes the API call. Update
the class field handling around model_name, max_tokens, and temperature to
enforce the Pegasus minimum with a clear error message, keeping the existing
default of 2048 unchanged.
🪄 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: 3f4b8e43-f830-439c-8e34-d2ad643a2274

📥 Commits

Reviewing files that changed from the base of the PR and between 01fc389 and 0423dbf.

📒 Files selected for processing (11)
  • docs/docs.json
  • docs/edge/en/tools/ai-ml/twelvelabsanalyzetool.mdx
  • lib/crewai-tools/README.md
  • lib/crewai-tools/pyproject.toml
  • lib/crewai-tools/src/crewai_tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/twelvelabs_analyze_tool/README.md
  • lib/crewai-tools/src/crewai_tools/tools/twelvelabs_analyze_tool/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/twelvelabs_analyze_tool/twelvelabs_analyze_tool.py
  • lib/crewai-tools/tests/tools/twelvelabs_analyze_tool_test.py
  • lib/crewai-tools/tool.specs.json

Comment on lines +130 to +142
if video_id:
analyze_kwargs["video_id"] = video_id
else:
from twelvelabs.types.video_context import VideoContext_Url

analyze_kwargs["video"] = VideoContext_Url(url=video_url)

try:
response = self._client.analyze(**analyze_kwargs)
except Exception as e:
raise RuntimeError(f"TwelveLabs analysis failed: {e!s}") from e

return response.data or ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

TwelveLabs Python SDK 1.2.8 client analyze method and VideoContext_Url import path twelvelabs.types.video_context

💡 Result:

In the TwelveLabs Python SDK, the analyze method is used for synchronous video analysis [1][2]. The VideoContext_Url class, which allows you to pass a video URL directly into the analysis request, is imported from twelvelabs.types [3][4]. To use these in your code, you can follow this pattern: from twelvelabs import TwelveLabs from twelvelabs.types import VideoContext_Url client = TwelveLabs(api_key="YOUR_API_KEY") # Analyze a video using a URL result = client.analyze( model_name="pegasus1.5", video=VideoContext_Url(url="YOUR_VIDEO_URL"), prompt="Describe this video.") print(result.data) Key details: 1. Method Usage: The analyze method is a synchronous call that returns results immediately [2][5]. It accepts a video parameter which should be an instance of a VideoContext type, such as VideoContext_Url (for URL-based input), VideoContext_AssetId (for previously indexed assets), or VideoContext_Base64String [3][6]. 2. Import Path: The VideoContext variants, including VideoContext_Url, are located within the twelvelabs.types module [3][7][4]. 3. Migration Note: While older versions of the SDK (e.g., v1.2.x) may have used video_id directly in the analyze method, newer implementations for the latest API versions utilize the video parameter with VideoContext objects to provide more flexibility (URL, Asset ID, etc.) [8]. Always ensure you are using the latest SDK version to maintain compatibility with the TwelveLabs API [9].

Citations:


Verify TwelveLabs SDK v1.2.8 import path and API surface.

The code uses from twelvelabs.types.video_context import VideoContext_Url, but the public TwelveLabs Python SDK (v1.2.8 and later) exposes VideoContext_Url under twelvelabs.types. The direct import path twelvelabs.types.video_context is an internal implementation detail and may break with SDK updates or fail if the internal module structure changes.

Update the import to use the public stable API:

from twelvelabs.types import VideoContext_Url

Ensure the analyze method expects the video keyword argument with the VideoContext_Url object, which is consistent with the current usage in the code.

🤖 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/twelvelabs_analyze_tool/twelvelabs_analyze_tool.py`
around lines 130 - 142, The TwelveLabs import in the fallback path of
TwelvelabsAnalyzeTool.analyze uses an internal module path, so update the
VideoContext_Url import to the public stable SDK API exposed by
twelvelabs.types. Keep the existing analyze_kwargs logic in
TwelvelabsAnalyzeTool.analyze, but change the import used when video_id is
absent so the `video` keyword is still passed a VideoContext_Url instance while
relying on the supported import surface.

Comment on lines +11 to +15
def _make_tool() -> TwelveLabsAnalyzeTool:
"""Build a tool with the SDK client stubbed so no network/SDK is needed."""
with patch(
"twelvelabs.TwelveLabs", create=True, return_value=MagicMock()
):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Python unittest.mock, does patch(target, create=True) create a missing module, or does the target module still need to be importable?

💡 Result:

In Python's unittest.mock, the patch(target, create=True) function does not create missing modules [1][2]. The target module must still be importable and exist for patch to successfully locate the namespace where the attribute is being replaced [1][3]. The create=True argument specifically allows you to patch attributes (such as functions, classes, or variables) that do not currently exist within an existing module or class [1][4]. When create=True is used, patch will create the missing attribute on the target object when the patched function is called and delete it again after the function exits [1][2]. If the module itself cannot be imported or found, the patch will fail with an ImportError or AttributeError before the attribute can be created [1].

Citations:


Patch strategy requires the optional SDK module to exist

The patch("twelvelabs.TwelveLabs", create=True) approach at Line 13 and Line 20 is insufficient. In Python unittest.mock, create=True only allows patching non-existent attributes on an existing object; it does not create missing modules. If the twelvelabs package is not installed, the patch target cannot be resolved during the setup phase, causing the test to crash with an AttributeError before the mock is applied.

Additionally, the test at Line 54 relies on twelvelabs.types.video_context.VideoContext_Url, which must also be stubbed to avoid import errors when the optional dependency is absent.

To ensure tests run independently of the twelvelabs package, inject fake modules directly into sys.modules:

Recommended fix
+import sys
+import types
 from unittest.mock import MagicMock, patch
 
 def _make_tool() -> TwelveLabsAnalyzeTool:
     """Build a tool with the SDK client stubbed so no network/SDK is needed."""
-    with patch(
-        "twelvelabs.TwelveLabs", create=True, return_value=MagicMock()
-    ):
+    # Inject fake modules so imports inside the tool resolve without the actual SDK
+    fake_twelvelabs = types.ModuleType("twelvelabs")
+    fake_types = types.ModuleType("twelvelabs.types")
+    fake_video_context = types.ModuleType("twelvelabs.types.video_context")
+
+    fake_client = MagicMock()
+    fake_twelvelabs.TwelveLabs = MagicMock(return_value=fake_client)
+    fake_video_context.VideoContext_Url = MagicMock()
+
+    with patch.dict(
+        sys.modules,
+        {
+            "twelvelabs": fake_twelvelabs,
+            "twelvelabs.types": fake_types,
+            "twelvelabs.types.video_context": fake_video_context,
+        },
+    ):
         return TwelveLabsAnalyzeTool(api_key="test-key")
🤖 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/tests/tools/twelvelabs_analyze_tool_test.py` around lines 11
- 15, The test setup in _make_tool and the related twelvelabs imports assume the
optional SDK package exists, but patching twelvelabs.TwelveLabs with create=True
will not create a missing module. Update the test fixture to inject fake
twelvelabs package modules into sys.modules before importing or patching
TwelveLabsAnalyzeTool, and also stub
twelvelabs.types.video_context.VideoContext_Url so the VideoContext_Url-based
test can run without the real dependency. Use the existing _make_tool helper and
the test that references VideoContext_Url as the main locations to adjust.

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