Skip to content

feat(ai-twelvelabs): add TwelveLabs Pegasus video understanding adapter#841

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

feat(ai-twelvelabs): add TwelveLabs Pegasus video understanding adapter#841
mohit-twelvelabs wants to merge 1 commit into
TanStack: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).

🎯 Changes

This PR adds @tanstack/ai-twelvelabs, a new opt-in provider adapter that brings TwelveLabs Pegasus video understanding to TanStack AI's multimodal path.

Pegasus is a video-native model: give it a video and a prompt, and it returns prompt-guided text (summaries, Q&A, chapters, highlights). The adapter plugs into the existing chat() activity using the framework's standard video content part — no new activity type, no changes to defaults.

import { chat } from '@tanstack/ai'
import { twelvelabsText } from '@tanstack/ai-twelvelabs'

const stream = chat({
  adapter: twelvelabsText('pegasus1.5'),
  messages: [{
    role: 'user',
    content: [
      { type: 'text', content: 'Summarize this video in one paragraph.' },
      { type: 'video', source: { type: 'url', value: 'https://example.com/clip.mp4' } },
    ],
  }],
})

What's included, mirroring the existing adapter conventions (ai-gemini, ai-elevenlabs):

  • Streaming via TwelveLabs' native NDJSON analyzeStream, mapped to the standard RUN_STARTEDTEXT_MESSAGE_*RUN_FINISHED AG-UI lifecycle, with token usage on RUN_FINISHED.
  • Structured output via the non-streaming analyze call with a json_schema response format (outputSchema is honored).
  • Provider options: temperature, maxTokens, clip windowing (startTime/endTime), and assetId (analyze a pre-uploaded asset).
  • Video supplied as a URL, inline base64, or a pre-uploaded asset id.
  • model-meta.ts for pegasus1.5 / pegasus1.2 (plus marengo3.0 exported for reference).
  • README + a docs page (docs/adapters/twelvelabs), registered in docs/config.json and the root README adapter table.
  • A changeset.

Why this helps

TanStack AI is provider-agnostic and multimodal-friendly, but there's currently no first-class video understanding provider. TwelveLabs fills that gap — the adapter slots video reasoning into the same chat()/structured-output surface developers already use for text models. It's free to try: you can grab a free API key at https://twelvelabs.io — there's a generous free tier.

Opt-in / non-breaking

This is a brand-new package. It changes no existing defaults and touches no existing adapter. Nothing imports it unless you ask for it.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally (see Test plan).

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

🧪 Test plan

Run from the repo root (or cd packages/ai-twelvelabs):

  • pnpm --filter @tanstack/ai-twelvelabs test:types — passes.
  • pnpm --filter @tanstack/ai-twelvelabs test:lib — 7 deterministic unit tests pass (1 live test skipped without a key). The unit tests mock twelvelabs-js and assert request mapping (URL/base64/assetId video extraction, prompt concatenation, provider options), the streamed event lifecycle + usage, the missing-video error, and the json_schema structured-output path.
  • pnpm --filter @tanstack/ai-twelvelabs test:eslint / test:build (publint) / build — pass.
  • Root gates run green: test:sherif, test:knip, test:docs.
  • Live: with a real TWELVELABS_API_KEY, the gated test (tests/live.test.ts) analyzes a short public video through Pegasus 1.5 and asserts non-empty streamed text. I verified this end-to-end locally (Pegasus returned a coherent description; Marengo embed.create returned a 512-dim vector).

A note on E2E: the repo's E2E suite is driven by aimock, which doesn't yet mock TwelveLabs' analyze endpoints, so I didn't add twelvelabs to feature-support.ts/test-matrix.ts (doing so would require an aimock fixture that doesn't exist and could make the provider-coverage tests flap). Coverage here is the deterministic unit tests plus the gated live test — the same approach ai-fal uses for paths aimock doesn't model yet. Happy to wire it into the matrix if/when aimock gains TwelveLabs support, or to adjust anything to your preference.

Summary by CodeRabbit

  • New Features

    • Added a new TwelveLabs video understanding adapter with streaming chat, structured output, video input by URL/base64/asset ID, and clip window controls.
    • Introduced package exports, model metadata, and configurable provider options for Pegasus models.
  • Documentation

    • Added a new adapter guide and updated the main README and docs navigation to include TwelveLabs.
  • Tests

    • Added coverage for streaming behavior, structured output, model metadata, and a live integration check.

Adds @tanstack/ai-twelvelabs, an opt-in provider adapter that brings
TwelveLabs Pegasus video understanding to the chat() activity. A video
content part (URL, inline base64, or a pre-uploaded asset id) plus a text
prompt is analyzed by Pegasus and streamed back as text.

- Native streaming via TwelveLabs analyzeStream (NDJSON), mapped to the
  standard RUN_STARTED / TEXT_MESSAGE_* / RUN_FINISHED event lifecycle.
- Structured output via the non-streaming analyze call with a json_schema
  response format.
- Provider options for temperature, maxTokens, clip windowing
  (startTime/endTime), and assetId.
- model-meta for pegasus1.5 / pegasus1.2 (and marengo3.0 for reference).
- Deterministic no-network unit tests plus a TWELVELABS_API_KEY-gated live
  test. Non-breaking; no existing defaults change.
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new @tanstack/ai-twelvelabs package for TwelveLabs video understanding, including provider types, model metadata, streaming and structured-output adapters, package wiring, tests, and documentation.

Changes

TwelveLabs adapter package

Layer / File(s) Summary
Public contracts and utilities
packages/ai-twelvelabs/src/text/text-provider-options.ts, packages/ai-twelvelabs/src/message-types.ts, packages/ai-twelvelabs/src/model-meta.ts, packages/ai-twelvelabs/src/utils/client.ts, packages/ai-twelvelabs/src/utils/index.ts, packages/ai-twelvelabs/src/index.ts
TwelveLabs provider options, message metadata, model metadata, API-key helpers, and barrel exports define the package surface.
Package setup and build wiring
packages/ai-twelvelabs/package.json, packages/ai-twelvelabs/tsconfig.json, packages/ai-twelvelabs/vite.config.ts, packages/ai-twelvelabs/LICENSE
Package metadata, TypeScript settings, Vitest settings, and license text configure the new package.
Adapter streaming and structured output
packages/ai-twelvelabs/src/adapters/text.ts
The TwelveLabs text adapter builds analyze requests from video messages, streams chat events, parses structured output from JSON schema responses, and exposes explicit and environment-based factories.
Tests and live validation
packages/ai-twelvelabs/tests/*
Adapter tests and a gated live stream test verify request mapping, error handling, structured output, and exported model metadata.
Docs and release metadata
packages/ai-twelvelabs/README.md, docs/adapters/twelvelabs.md, README.md, docs/config.json, .changeset/twelvelabs-adapter.md
Package and repo documentation, navigation, and the changeset entry describe the new adapter.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • TanStack/ai#673: The new adapter’s RUN_ERROR handling uses toRunErrorRawEvent, which is directly related to the raw-event error plumbing introduced there.

Suggested reviewers

  • tombeckenham

Poem

I nibbled bytes beneath the moon,
and sang with streams in Pegasus tune.
From video hops to JSON bright,
my whiskers twitch with code delight.
🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% 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
Title check ✅ Passed The title clearly summarizes the main change: adding a TwelveLabs Pegasus video understanding adapter.
Description check ✅ Passed The description follows the required template and covers changes, checklist, release impact, and testing details.
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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/ai-twelvelabs/vite.config.ts

Parsing error: "parserOptions.project" has been provided for @typescript-eslint/parser.
The file was not found in any of the provided project(s): packages/ai-twelvelabs/vite.config.ts


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.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedtwelvelabs-js@​1.2.88710010094100

View full report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@packages/ai-twelvelabs/package.json`:
- Line 4: The package description is advertising Marengo multimodal embeddings
even though the adapter only ships Pegasus-based chat support and exports
marengo3.0 for reference. Update the package.json description in the TwelveLabs
adapter to remove the embeddings/Marengo claim and keep it aligned with the
actual public surface exposed by the adapter.

In `@packages/ai-twelvelabs/src/adapters/text.ts`:
- Around line 227-253: The structured output parse error in text adapter should
not include raw model output, since it can leak user/video content. Update the
JSON.parse failure path in the text adapter’s structured output handling to
throw a generic parse error without embedding rawText, and keep diagnostics in
the final catch around logger.errors('twelvelabs.structuredOutput fatal', ...)
metadata-only (error/source only). Use the structured output flow in the text
adapter and the logger.errors call as the main places to adjust.
- Around line 96-117: The run lifecycle starts too late in the text adapter,
because buildAnalyzeRequest, logger.request, and client.analyzeStream can fail
before RUN_STARTED is yielded. Move the RUN_STARTED emission in TextAdapter’s
analyze/stream flow to the beginning of the try block, before request
construction and provider setup, so every execution path opens the run before
any possible error and still allows later failures to emit RUN_ERROR correctly.

In `@packages/ai-twelvelabs/tests/text-adapter.test.ts`:
- Around line 5-15: The test setup in text-adapter.test.ts is failing because
vi.mock is hoisted before the mock variables are initialized, so the TwelveLabs
factory cannot safely reference analyzeStreamMock and analyzeMock. Move the
source import for createTwelveLabsText to the top and declare the mock functions
with vi.hoisted so they exist before the vi.mock factory runs. Keep the mocked
TwelveLabs class using those hoisted symbols to avoid the initialization error
and satisfy import/first ordering.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: cb7279b5-70f0-4f1d-8400-0dc51fee9ffc

📥 Commits

Reviewing files that changed from the base of the PR and between fbd3762 and 778641a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • .changeset/twelvelabs-adapter.md
  • README.md
  • docs/adapters/twelvelabs.md
  • docs/config.json
  • packages/ai-twelvelabs/LICENSE
  • packages/ai-twelvelabs/README.md
  • packages/ai-twelvelabs/package.json
  • packages/ai-twelvelabs/src/adapters/text.ts
  • packages/ai-twelvelabs/src/index.ts
  • packages/ai-twelvelabs/src/message-types.ts
  • packages/ai-twelvelabs/src/model-meta.ts
  • packages/ai-twelvelabs/src/text/text-provider-options.ts
  • packages/ai-twelvelabs/src/utils/client.ts
  • packages/ai-twelvelabs/src/utils/index.ts
  • packages/ai-twelvelabs/tests/live.test.ts
  • packages/ai-twelvelabs/tests/model-meta.test.ts
  • packages/ai-twelvelabs/tests/text-adapter.test.ts
  • packages/ai-twelvelabs/tsconfig.json
  • packages/ai-twelvelabs/vite.config.ts

{
"name": "@tanstack/ai-twelvelabs",
"version": "0.0.1",
"description": "TwelveLabs adapter for TanStack AI — video understanding with Pegasus (analyze/summarize) and multimodal embeddings with Marengo.",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Description overstates embeddings support.

The description advertises "multimodal embeddings with Marengo", but per the PR objective the adapter only implements Pegasus video understanding through chat(); marengo3.0 is exported "for reference" and no embeddings flow is shipped. This is the public npm description, so it may mislead consumers. Consider trimming the embeddings/Marengo claim until that surface exists.

🤖 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 `@packages/ai-twelvelabs/package.json` at line 4, The package description is
advertising Marengo multimodal embeddings even though the adapter only ships
Pegasus-based chat support and exports marengo3.0 for reference. Update the
package.json description in the TwelveLabs adapter to remove the
embeddings/Marengo claim and keep it aligned with the actual public surface
exposed by the adapter.

Comment on lines +96 to +117
try {
const request = this.buildAnalyzeRequest(options)
logger.request(
`activity=chat provider=twelvelabs model=${model} messages=${options.messages.length} stream=true`,
{ provider: 'twelvelabs', model },
)

const stream = await this.client.analyzeStream(request)

let accumulatedContent = ''
let hasEmittedTextStart = false
let usage: TokenUsage | undefined
let finishReason: 'stop' | 'length' = 'stop'

yield {
type: EventType.RUN_STARTED,
runId,
threadId,
model,
timestamp: Date.now(),
parentRunId: options.parentRunId,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Emit RUN_STARTED before request construction/provider setup.

Line 97 or Line 103 can throw before Line 110 emits RUN_STARTED, so error paths produce RUN_ERROR without opening the run lifecycle.

Proposed fix
     try {
-      const request = this.buildAnalyzeRequest(options)
-      logger.request(
-        `activity=chat provider=twelvelabs model=${model} messages=${options.messages.length} stream=true`,
-        { provider: 'twelvelabs', model },
-      )
-
-      const stream = await this.client.analyzeStream(request)
-
-      let accumulatedContent = ''
-      let hasEmittedTextStart = false
-      let usage: TokenUsage | undefined
-      let finishReason: 'stop' | 'length' = 'stop'
-
       yield {
         type: EventType.RUN_STARTED,
         runId,
         threadId,
         model,
@@
         parentRunId: options.parentRunId,
       }
+
+      const request = this.buildAnalyzeRequest(options)
+      logger.request(
+        `activity=chat provider=twelvelabs model=${model} messages=${options.messages.length} stream=true`,
+        { provider: 'twelvelabs', model },
+      )
+
+      const stream = await this.client.analyzeStream(request)
+
+      let accumulatedContent = ''
+      let hasEmittedTextStart = false
+      let usage: TokenUsage | undefined
+      let finishReason: 'stop' | 'length' = 'stop'
📝 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
try {
const request = this.buildAnalyzeRequest(options)
logger.request(
`activity=chat provider=twelvelabs model=${model} messages=${options.messages.length} stream=true`,
{ provider: 'twelvelabs', model },
)
const stream = await this.client.analyzeStream(request)
let accumulatedContent = ''
let hasEmittedTextStart = false
let usage: TokenUsage | undefined
let finishReason: 'stop' | 'length' = 'stop'
yield {
type: EventType.RUN_STARTED,
runId,
threadId,
model,
timestamp: Date.now(),
parentRunId: options.parentRunId,
}
try {
yield {
type: EventType.RUN_STARTED,
runId,
threadId,
model,
timestamp: Date.now(),
parentRunId: options.parentRunId,
}
const request = this.buildAnalyzeRequest(options)
logger.request(
`activity=chat provider=twelvelabs model=${model} messages=${options.messages.length} stream=true`,
{ provider: 'twelvelabs', model },
)
const stream = await this.client.analyzeStream(request)
let accumulatedContent = ''
let hasEmittedTextStart = false
let usage: TokenUsage | undefined
let finishReason: 'stop' | 'length' = 'stop'
🤖 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 `@packages/ai-twelvelabs/src/adapters/text.ts` around lines 96 - 117, The run
lifecycle starts too late in the text adapter, because buildAnalyzeRequest,
logger.request, and client.analyzeStream can fail before RUN_STARTED is yielded.
Move the RUN_STARTED emission in TextAdapter’s analyze/stream flow to the
beginning of the try block, before request construction and provider setup, so
every execution path opens the run before any possible error and still allows
later failures to emit RUN_ERROR correctly.

Comment on lines +227 to +253
const rawText = result.data ?? ''
let parsed: unknown
try {
parsed = JSON.parse(rawText)
} catch {
throw new Error(
`Failed to parse structured output as JSON. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,
)
}

return {
data: parsed,
rawText,
...(result.usage && {
usage: buildBaseUsage({
promptTokens: result.usage.inputTokens ?? 0,
completionTokens: result.usage.outputTokens,
totalTokens:
(result.usage.inputTokens ?? 0) + result.usage.outputTokens,
}),
}),
}
} catch (error) {
logger.errors('twelvelabs.structuredOutput fatal', {
error,
source: 'twelvelabs.structuredOutput',
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not include raw model output in parse errors.

Lines 232-234 put generated content into the error message, and Lines 250-253 log that error. Keep diagnostics metadata-only to avoid leaking video-derived/user content.

Proposed fix
       try {
         parsed = JSON.parse(rawText)
       } catch {
         throw new Error(
-          `Failed to parse structured output as JSON. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,
+          'Failed to parse structured output as JSON.',
         )
       }
📝 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
const rawText = result.data ?? ''
let parsed: unknown
try {
parsed = JSON.parse(rawText)
} catch {
throw new Error(
`Failed to parse structured output as JSON. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,
)
}
return {
data: parsed,
rawText,
...(result.usage && {
usage: buildBaseUsage({
promptTokens: result.usage.inputTokens ?? 0,
completionTokens: result.usage.outputTokens,
totalTokens:
(result.usage.inputTokens ?? 0) + result.usage.outputTokens,
}),
}),
}
} catch (error) {
logger.errors('twelvelabs.structuredOutput fatal', {
error,
source: 'twelvelabs.structuredOutput',
})
const rawText = result.data ?? ''
let parsed: unknown
try {
parsed = JSON.parse(rawText)
} catch {
throw new Error(
'Failed to parse structured output as JSON.',
)
}
return {
data: parsed,
rawText,
...(result.usage && {
usage: buildBaseUsage({
promptTokens: result.usage.inputTokens ?? 0,
completionTokens: result.usage.outputTokens,
totalTokens:
(result.usage.inputTokens ?? 0) + result.usage.outputTokens,
}),
}),
}
} catch (error) {
logger.errors('twelvelabs.structuredOutput fatal', {
error,
source: 'twelvelabs.structuredOutput',
})
🤖 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 `@packages/ai-twelvelabs/src/adapters/text.ts` around lines 227 - 253, The
structured output parse error in text adapter should not include raw model
output, since it can leak user/video content. Update the JSON.parse failure path
in the text adapter’s structured output handling to throw a generic parse error
without embedding rawText, and keep diagnostics in the final catch around
logger.errors('twelvelabs.structuredOutput fatal', ...) metadata-only
(error/source only). Use the structured output flow in the text adapter and the
logger.errors call as the main places to adjust.

Comment on lines +5 to +15
const analyzeStreamMock = vi.fn()
const analyzeMock = vi.fn()

vi.mock('twelvelabs-js', () => ({
TwelveLabs: class {
analyzeStream = analyzeStreamMock
analyze = analyzeMock
},
}))

import { createTwelveLabsText } from '../src/adapters/text'

Copy link
Copy Markdown
Contributor

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 Vitest, can a vi.mock factory reference module-scoped variables whose names are suffixed with "Mock" (e.g. analyzeStreamMock) rather than prefixed with "mock", or does it throw due to hoisting? Is vi.hoisted required?

💡 Result:

In Vitest, a vi.mock factory cannot reference arbitrary module-scoped variables because vi.mock is hoisted to the top of the file and executed before module-level code [1][2]. This restriction applies regardless of the variable's naming convention; naming a variable with a "Mock" suffix (e.g., analyzeStreamMock) does not grant it immunity to hoisting or provide access within the factory [1][3]. Because vi.mock is moved to the top of the file during transformation, referencing any variable defined outside of it will result in a ReferenceError (or usage of an uninitialized variable) because that variable has not yet been defined in the execution order [2]. To share variables with a vi.mock factory, you must use vi.hoisted [1][4]. This function explicitly instructs Vitest to hoist the provided code to the top of the file alongside the mock, making the returned values available within the vi.mock factory scope [1][2]. If you prefer not to use vi.hoisted, the alternative is vi.doMock, which is not hoisted [1][4]. However, vi.doMock only affects subsequent imports, meaning it must be called before the target module is imported in your test file [1][4].

Citations:


Fix vi.mock hoisting to prevent test suite initialization failure

The vi.mock factory runs before module-level code because Vitest hoists it to the top of the file. Referencing analyzeStreamMock and analyzeMock inside the factory while they are declared afterward causes a "Cannot access before initialization" error, preventing the tests from running. Variable naming conventions do not bypass this restriction.

Wrap the mock declarations in vi.hoisted and move the source import to the top to resolve the initialization order and ESLint import/first violations.

🔧 Proposed refactor
 import { EventType } from '`@tanstack/ai`'
 import { beforeEach, describe, expect, it, vi } from 'vitest'
 import type { StreamChunk, TextOptions } from '`@tanstack/ai`'
+import { createTwelveLabsText } from '../src/adapters/text'

-const analyzeStreamMock = vi.fn()
-const analyzeMock = vi.fn()
-
 vi.mock('twelvelabs-js', () => ({
   TwelveLabs: class {
     analyzeStream = analyzeStreamMock
     analyze = analyzeMock
   },
 }))
-
-import { createTwelveLabsText } from '../src/adapters/text'
+
+const { analyzeStreamMock, analyzeMock } = vi.hoisted(() => ({
+  analyzeStreamMock: vi.fn(),
+  analyzeMock: vi.fn(),
+}))
📝 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
const analyzeStreamMock = vi.fn()
const analyzeMock = vi.fn()
vi.mock('twelvelabs-js', () => ({
TwelveLabs: class {
analyzeStream = analyzeStreamMock
analyze = analyzeMock
},
}))
import { createTwelveLabsText } from '../src/adapters/text'
import { createTwelveLabsText } from '../src/adapters/text'
const { analyzeStreamMock, analyzeMock } = vi.hoisted(() => ({
analyzeStreamMock: vi.fn(),
analyzeMock: vi.fn(),
}))
vi.mock('twelvelabs-js', () => ({
TwelveLabs: class {
analyzeStream = analyzeStreamMock
analyze = analyzeMock
},
}))
🧰 Tools
🪛 ESLint

[error] 15-15: Import in body of module; reorder to top.

(import/first)


[error] 15-15: ../src/adapters/text import should occur before type import of @tanstack/ai

(import/order)

🤖 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 `@packages/ai-twelvelabs/tests/text-adapter.test.ts` around lines 5 - 15, The
test setup in text-adapter.test.ts is failing because vi.mock is hoisted before
the mock variables are initialized, so the TwelveLabs factory cannot safely
reference analyzeStreamMock and analyzeMock. Move the source import for
createTwelveLabsText to the top and declare the mock functions with vi.hoisted
so they exist before the vi.mock factory runs. Keep the mocked TwelveLabs class
using those hoisted symbols to avoid the initialization error and satisfy
import/first ordering.

Source: Linters/SAST tools

@AlemTuzlak

Copy link
Copy Markdown
Contributor

hey @mohit-twelvelabs , thank you for this contribution, I think it's a much better idea that you own the package on your side and we add it into the community adapters section as a documented community plugin instead of us owning the adapter!

@mohit-twelvelabs

Copy link
Copy Markdown
Author

Thanks @AlemTuzlak — that makes total sense, happy to own it on our side. I'll publish it as a standalone community adapter package, and I'd be glad to open a small docs PR adding it to the community adapters section so it's discoverable for folks. Appreciate the quick look!

— Mohit (@mohit-twelvelabs, TwelveLabs)

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