Skip to content

feat: add vercel-ai-sdk.mdc rule to prevent v6 hallucinations#2727

Open
cubaseuser123 wants to merge 2 commits intogiselles-ai:mainfrom
cubaseuser123:feat/vercel-ai-sdk-rule
Open

feat: add vercel-ai-sdk.mdc rule to prevent v6 hallucinations#2727
cubaseuser123 wants to merge 2 commits intogiselles-ai:mainfrom
cubaseuser123:feat/vercel-ai-sdk-rule

Conversation

@cubaseuser123
Copy link

@cubaseuser123 cubaseuser123 commented Feb 12, 2026

Summary

I started using the Vercel AI SDK when version 6 was released. I've noticed that when I ask an agent (Cursor, Antigravity, Claude) to write code, it often defaults to version 4 or 5 patterns.

These agents frequently confuse toolContext with experimental_context, use the wrong generateObject syntax, and get execute signatures wrong.

To address this, I created a Cursor rule that teaches agents how to avoid these hallucinations. This approach completely stopped the errors for me.

Related Issue

vercel-labs/agent-skills#133

Changes

Added .cursor/rules/vercel-ai-sdk.mdc — a companion to the existing update-ai-sdk.mdc that focuses on writing correct v6 code. It covers 7 hallucination-prone API changes:

  1. toolContextexperimental_context
  2. generateObjectOutput.object() (Legacy)
  3. parametersinputSchema
  4. .strict() on Zod → strict: true on tool
  5. toDataStreamResponse()toUIMessageStreamResponse()
  6. maxStepsstopWhen: stepCountIs(N)
  7. Raw messages → UIMessage + convertToModelMessages()

All patterns are sourced from official Vercel AI SDK docs.

Testing

N/A — documentation-only change, no runtime code affected.

Other Information

Every code example includes a ✅ CORRECT / ❌ WRONG comparison with links to official docs. A canonical Route Handler reference is included at the end as a quick-copy template.

Summary by CodeRabbit

  • Documentation
    • Added comprehensive Vercel AI SDK v6 usage guidelines covering updated patterns for tool calls, input handling, and streaming.
    • Included migration notes for deprecated APIs and recommended replacements to ensure compatibility with the pinned SDK.
    • Added canonical examples and a route handler walkthrough to demonstrate correct, production-ready integration.

@cubaseuser123 cubaseuser123 requested a review from shige as a code owner February 12, 2026 18:39
@vercel
Copy link

vercel bot commented Feb 12, 2026

@cubaseuser123 is attempting to deploy a commit to the Giselle Team on Vercel.

A member of the Team first needs to authorize it.

@giselles-ai
Copy link

giselles-ai bot commented Feb 12, 2026

Finished running flow.

Step 1
🟢
On Pull Request OpenedStatus: Success Updated: Feb 12, 2026 6:39pm
Step 2
🟢
Manual QAStatus: Success Updated: Feb 12, 2026 6:41pm
🟢
Prompt for AI AgentsStatus: Success Updated: Feb 12, 2026 6:41pm
Step 3
🟢
Create a Comment for PRStatus: Success Updated: Feb 12, 2026 6:44pm
Step 4
🟢
Create Pull Request CommentStatus: Success Updated: Feb 12, 2026 6:44pm

@changeset-bot
Copy link

changeset-bot bot commented Feb 12, 2026

⚠️ No Changeset found

Latest commit: 8ddc93f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

💥 An error occurred when fetching the changed packages and changesets in this PR
Some errors occurred when validating the changesets config:
The package or glob expression "giselles-ai" is specified in the `ignore` option but it is not found in the project. You may have misspelled the package name or provided an invalid glob expression. Note that glob expressions must be defined according to https://www.npmjs.com/package/micromatch.

@qodo-free-for-open-source-projects

Review Summary by Qodo

Add Vercel AI SDK v6 Cursor rule to prevent common hallucinations

📝 Documentation

Grey Divider

Walkthroughs

Description
• Adds comprehensive Cursor rule for Vercel AI SDK v6 patterns
• Documents 7 common API hallucinations with correct/incorrect examples
• Includes official documentation links for each pattern
• Provides canonical Route Handler template for reference
Diagram
flowchart LR
  A["Vercel AI SDK v6<br/>Common Hallucinations"] -->|toolContext| B["experimental_context"]
  A -->|generateObject| C["Output.object()"]
  A -->|parameters| D["inputSchema"]
  A -->|Zod.strict()| E["tool strict option"]
  A -->|toDataStreamResponse| F["toUIMessageStreamResponse"]
  A -->|maxSteps| G["stopWhen: stepCountIs"]
  A -->|Raw messages| H["UIMessage + conversion"]
  B --> I["Cursor Rule<br/>vercel-ai-sdk.mdc"]
  C --> I
  D --> I
  E --> I
  F --> I
  G --> I
  H --> I
Loading

Grey Divider

File Changes

1. .cursor/rules/vercel-ai-sdk.mdc 📝 Documentation +242/-0

Vercel AI SDK v6 hallucination prevention guide

• New Cursor rule file documenting 7 Vercel AI SDK v6 API pattern corrections
• Each pattern includes ✅ CORRECT and ❌ WRONG code examples with explanations
• Covers: toolContextexperimental_context, generateObjectOutput.object(), parametersinputSchema, Zod .strict() → tool strict option, toDataStreamResponse()toUIMessageStreamResponse(), maxStepsstopWhen: stepCountIs(), and raw messages →
 UIMessage + convertToModelMessages()
• Includes canonical Route Handler template demonstrating all patterns in practice
• All examples link to official Vercel AI SDK documentation

.cursor/rules/vercel-ai-sdk.mdc


Grey Divider

Qodo Logo

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

New documentation file added that documents Vercel AI SDK v6 usage patterns and replacements for deprecated APIs, with code examples and a canonical streaming route handler. No executable code changes.

Changes

Cohort / File(s) Summary
Documentation
.cursor/rules/vercel-ai-sdk.mdc
Added a new reference guide describing v6 API patterns: replace toolContext with experimental_context, use inputSchema, treat strict as a top-level Tool option, prefer toUIMessageStream over toDataStreamResponse, switch maxStepsstopWhen with stepCountIs, clarify UIMessage vs ModelMessage with convertToModelMessages, note generateObject deprecation, and provide canonical streaming examples and sources.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Poem

🐇 I hopped through docs to tidy the trail,
V6 whispers in code and in tale,
Streams now hum the canonical tune,
Schemas and context aligned by the moon,
✨📜

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding a Vercel AI SDK rule file to prevent version 6 hallucinations in agent-generated code.
Description check ✅ Passed The PR description is comprehensive and follows the template structure with all major sections complete: Summary explains the problem and solution, Related Issue links to the issue, Changes lists the seven API patterns covered, Testing acknowledges it's documentation-only, and Other Information provides additional context about code examples.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

@giselles-ai
Copy link

giselles-ai bot commented Feb 12, 2026

🔍 QA Testing Assistant by Giselle

📋 Manual QA Checklist

Based on the changes in this PR, here are the key areas to test manually:

  • Test 1: Verify experimental_context Usage: Ask the AI to create a Vercel AI SDK tool requiring context. Expect the execute function to use async (input, { experimental_context }) => { ... } and not toolContext.
  • Test 2: Verify Structured Data Generation with Output.object(): Prompt the AI to generate a structured JSON object for a user profile. Expect generateText with output: Output.object(...) and not legacy generateObject.
  • Test 3: Verify Tool Schema with inputSchema: Request the AI to create a tool with Zod input parameters. Expect the tool definition to use inputSchema and not the old parameters property.
  • Test 4: Verify strict: true Tool Option: Ask the AI to create a strict tool where input must exactly match the Zod schema. Expect strict: true as a top-level property and not .strict() chained to the schema.
  • Test 5: Verify toUIMessageStreamResponse() Usage: Prompt the AI to create a basic streaming route handler. Expect the handler to return using result.toUIMessageStreamResponse() and not toDataStreamResponse().
  • Test 6: Verify Multi-Step Tool Calls with stopWhen: Request the AI to create a tool call that stops after 5 steps. Expect stopWhen: stepCountIs(5) and not deprecated maxSteps: 5.
  • Test 7: Verify UIMessage and convertToModelMessages Usage: Ask the AI to create a route handler taking chat messages. Expect incoming messages typed as UIMessage[] and passed through await convertToModelMessages(messages).
  • Test 8: Comprehensive "Canonical" Route Handler Generation: Prompt the AI to create a complete Next.js chat route handler using a weather tool. Expect the code to be a fully functional handler incorporating multiple correct patterns, resembling the vercel-ai-sdk.mdc reference.

✨ Prompt for AI Agents

Use the following prompts with Cursor or Claude Code to automate E2E testing:

📝 E2E Test Generation Prompt
## **Prompt for AI Agent: Generate E2E Tests for Vercel AI SDK Rule**

You are an expert QA engineer. Your task is to write an E2E test suite for a Pull Request that introduces a new documentation rule file. Since the PR does not change any application runtime code but instead provides "correct code" examples, our test strategy will be to **validate that the primary code example provided in the new rule file is functional and correct**.

We will create an API-level test using Playwright's `request` context to verify the "Canonical Route Handler" example. This test will confirm that the recommended code pattern works as expected when integrated into a real application.

### 1. Context Summary

*   **PR Goal:** The PR adds a new file, `.cursor/rules/vercel-ai-sdk.mdc`, which contains documentation and code examples to guide AI agents in generating correct code for the Vercel AI SDK v6. It aims to prevent the generation of outdated or "hallucinated" code patterns.
*   **Key Change:** A new markdown file (`.mdc`) with "✅ CORRECT" and "❌ WRONG" code snippets. The most important piece is the final "Canonical Route Handler" example, which combines all the correct patterns.
*   **Critical Test Path:** We must verify that the "Canonical Route Handler" example is fully functional. This involves setting up a minimal Next.js API route with that code and then sending a request to it to ensure it processes correctly and returns a valid streaming response. This is an **API test**, not a UI test.

### 2. Test Scenarios

#### Scenario 1: Validate the "Canonical Route Handler" Example

*   **Objective:** Confirm that the complete route handler example from `vercel-ai-sdk.mdc` can be deployed in a Next.js API route and successfully handles a POST request.
*   **Setup:**
    1.  Assume a minimal Next.js project structure.
    2.  The code from the "Canonical Route Handler" example will be placed in `app/api/chat/route.ts`.
    3.  The test will run a local dev server (`npm run dev`) to serve this API route.
*   **User Flow (Test Steps):**
    1.  Initiate a `POST` request to the `/api/chat` endpoint.
    2.  The request body should contain a sample `messages` array, simulating a user query that would trigger the `weather` tool. For example: `[{ role: 'user', content: 'What is the weather in London?' }]`.
*   **Expected Behavior (Assertions):**
    1.  The API should respond with a `200 OK` status.
    2.  The `Content-Type` header of the response should be `text/plain; charset=utf-8`, which is characteristic of the Vercel AI SDK stream.
    3.  The response body, when read as text, should contain structured data indicating that the `weather` tool was called. We can check for the presence of strings like `"tool_calls"`, `"weather"`, and `"location"`.

### 3. Playwright Implementation Instructions

Use Playwright's API testing features. Do not use a browser.

*   **Test File:** Create a new test file at `tests/api/vercel-ai-sdk-validation.spec.ts`.
*   **Dependencies:** The test will need `@playwright/test`. The minimal Next.js app will need `next`, `react`, `react-dom`, `ai`, and `zod`.
*   **Selectors:** Not applicable (API test).
*   **User Interactions (API Requests):**
    *   Use `request.newContext()` to set up the base URL for the local server (e.g., `http://localhost:3000`).
    *   Use `apiContext.post()` to send the request to `/api/chat`.

*   **Code Structure and Assertions:**
    Please generate the test file using the following structure.

    ```typescript
    // tests/api/vercel-ai-sdk-validation.spec.ts
    import { test, expect, request } from '@playwright/test';

    // Define the type for the message payload based on the Vercel AI SDK `UIMessage`
    type UIMessage = {
      id?: string;
      role: 'user' | 'assistant' | 'system' | 'function' | 'data' | 'tool';
      content: string;
      tool_calls?: any; // Simplified for testing
    };

    test.describe('Vercel AI SDK v6 Rule Validation', () => {
      // This test assumes a Next.js dev server is running with the canonical route handler
      // at `app/api/chat/route.ts`. The CI environment must start this server before running tests.
      const baseURL = process.env.BASE_URL || 'http://localhost:3000';

      test('should correctly process a request using the canonical route handler', async () => {
        const apiContext = await request.newContext({ baseURL });

        const payload: { messages: UIMessage[] } = {
          messages: [
            { role: 'user', content: 'What is the weather in London?' },
          ],
        };

        const response = await apiContext.post('/api/chat', {
          data: payload,
        });

        // 1. Verify the response status is OK
        expect(response.ok(), 'Response status should be 200 OK').toBeTruthy();

        // 2. Verify the Content-Type header indicates a stream
        const contentType = response.headers()['content-type'];
        expect(contentType, 'Content-Type should be for a text stream').toContain(
          'text/plain; charset=utf-8'
        );

        // 3. Verify the streamed response body contains the expected tool call information
        const responseBody = await response.text();
        console.log('API Response Body:', responseBody);

        // The Vercel SDK streams data chunks. We can assert that the complete
        // buffered text contains evidence of the tool call.
        expect(responseBody, 'Response should contain tool_calls indicator').toContain('0:"tool_calls"');
        expect(responseBody, 'Response should contain the tool name "weather"').toContain('"toolName":"weather"');
        expect(responseBody, 'Response should contain the argument "location" with "London"').toContain('"location":"London"');
      });
    });
    ```

### 4. MCP Integration Guidelines

*   **Execution Command:** The test can be run via Playwright MCP with a standard command.
    ```bash
    mcp playwright test tests/api/vercel-ai-sdk-validation.spec.ts --project=chromium
    ```
*   **Environment Configuration:**
    *   A critical prerequisite is that a web server for the Next.js application must be running before the tests are executed.
    *   In a CI/CD pipeline, this would look like:
        1.  `npm install`
        2.  `npm run dev &` (or `npm run build` and `npm run start &`)
        3.  `mcp playwright test ...`
        4.  (Teardown server)
*   **MCP Parameters:** No special MCP parameters are needed. The default configuration should suffice.

### 5. CI-Ready Code Requirements

*   **Test Organization:** The test is correctly placed in `tests/api/`, separating it from potential UI tests.
*   **Naming Conventions:**
    *   Filename: `vercel-ai-sdk-validation.spec.ts`
    *   Test Description: `Vercel AI SDK v6 Rule Validation`
    *   Test Title: `should correctly process a request using the canonical route handler`
*   **Error Handling:** The test uses standard `expect` assertions. In a CI setup, a `finally` block or `afterAll` hook would be necessary to ensure the server process is terminated, even if tests fail.
*   **Parallelization:** This API test runs against a single server instance. It should be run in a worker that does not conflict with other tests requiring a server. It is safe to mark these API tests to run serially (`test.describe.configure({ mode: 'serial' });`) if there are other dependent API tests.

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Feb 12, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. v6 rule vs repo ai@5 🐞 Bug ✓ Correctness
Description
The rule is labeled as “Vercel AI SDK v6 patterns” and applies to all *.ts/*.tsx, but the repo
catalog pins ai to 5.0.101; this can drive agents to generate APIs/patterns that may not exist in
the installed SDK, leading to compilation/runtime failures when code is added based on this rule.
Code

.cursor/rules/vercel-ai-sdk.mdc[R1-4]

+---
+description: Vercel AI SDK v6 patterns — prevents common hallucinations of legacy APIs
+globs: *.tsx,*.ts
+alwaysApply: false
Evidence
The new rule explicitly targets AI SDK v6 and will be considered for all TS/TSX files. The repo’s
dependency catalog indicates ai is currently pinned to 5.0.101, and existing code uses different
streaming helpers (e.g., toUIMessageStream()), indicating this repo is not demonstrably aligned to
the rule’s claimed v6 surface across the codebase.

.cursor/rules/vercel-ai-sdk.mdc[1-4]
pnpm-workspace.yaml[52-60]
packages/giselle/src/generations/generate-content.ts[300-336]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Cursor rule is presented as “Vercel AI SDK v6 patterns” but the repo pins `ai` to 5.0.101. Since the rule’s `globs` cover all TS/TSX files, agents may generate code using APIs/patterns that don’t exist for the repo’s installed SDK version, causing compile/runtime errors.
## Issue Context
Cursor rules influence generated code. If the rule is version-specific, it should either be scoped to the relevant code areas or clearly gated by the dependency version.
## Fix Focus Areas
- .cursor/rules/vercel-ai-sdk.mdc[1-12]
- pnpm-workspace.yaml[52-60]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. req.json() used without validation 📘 Rule violation ⛨ Security
Description
The added Route Handler examples consume external request JSON without Zod safeParse()
success/error handling, which can lead to runtime errors and unsafe assumptions about input shape.
This conflicts with the requirement to validate/parse external inputs explicitly before use.
Code

.cursor/rules/vercel-ai-sdk.mdc[R181-187]

+export async function POST(req: Request) {
+  const { messages }: { messages: UIMessage[] } = await req.json();
+
+  const result = streamText({
+    model,
+    messages: await convertToModelMessages(messages),
+    // ...
Evidence
PR Compliance ID 16 requires external/input data to be validated via Zod safeParse() with explicit
handling. The new documentation examples destructure messages directly from await req.json()
without any safeParse() or failure handling, encouraging unchecked input consumption.

.cursor/rules/vercel-ai-sdk.mdc[181-187]
.cursor/rules/vercel-ai-sdk.mdc[218-224]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The documentation examples in `.cursor/rules/vercel-ai-sdk.mdc` destructure `messages` from `await req.json()` without validating the external input using Zod `safeParse()` and explicit success/error handling.
## Issue Context
Even though this is documentation, it is presented as a canonical Route Handler template and may be copy-pasted into production code; the compliance requirement expects external inputs to be validated before use.
## Fix Focus Areas
- .cursor/rules/vercel-ai-sdk.mdc[181-191]
- .cursor/rules/vercel-ai-sdk.mdc[218-241]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. experimental_context uses as cast 📘 Rule violation ⛨ Security
Description
The new tool example uses a TypeScript type assertion (as { userId: string }) rather than
validating/parsing the value or typing it safely. This violates the requirement to avoid unsafe type
assertions for input values where explicit validation/handling is feasible.
Code

.cursor/rules/vercel-ai-sdk.mdc[R25-27]

+  execute: async (input, { experimental_context }) => {
+    const ctx = experimental_context as { userId: string };
+    // use ctx.userId
Evidence
PR Compliance ID 16 lists unsafe type assertions (e.g., as SomeType) as a failure mode when
consuming input values without safe parsing/validation. The added example asserts the shape of
experimental_context via as { userId: string }.

.cursor/rules/vercel-ai-sdk.mdc[25-27]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The tool example asserts `experimental_context` using `as { userId: string }`, which is an unsafe type assertion.
## Issue Context
This file is intended to guide agents toward correct patterns; using `as` for input-like values can encourage unchecked assumptions. Prefer typing/validation patterns that align with the compliance rule.
## Fix Focus Areas
- .cursor/rules/vercel-ai-sdk.mdc[20-29]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Snippet missing import 🐞 Bug ✓ Correctness
Description
Section 1’s “✅ CORRECT” example calls generateText(...) but doesn’t import it, so copy/paste will
fail and the rule teaches an incomplete pattern in its primary example.
Code

.cursor/rules/vercel-ai-sdk.mdc[R15-37]

+```typescript
+// ✅ CORRECT
+import { tool } from 'ai';
+import { z } from 'zod';
+
+const myTool = tool({
+  description: 'Do something with user context',
+  inputSchema: z.object({
+    query: z.string().describe('The search query'),
+  }),
+  execute: async (input, { experimental_context }) => {
+    const ctx = experimental_context as { userId: string };
+    // use ctx.userId
+  },
+});
+
+// Pass context at the call site:
+const result = await generateText({
+  model,
+  tools: { myTool },
+  experimental_context: { userId: '123' },
+  // ...
+});
Evidence
Within the same code block, generateText is used but only tool is imported from ai, making the
snippet internally inconsistent.

.cursor/rules/vercel-ai-sdk.mdc[16-37]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The section 1 “✅ CORRECT” snippet uses `generateText(...)` but does not import it, making the example fail if copied and reducing trust in the rule.
## Issue Context
This file is meant to prevent hallucinations; example correctness is important.
## Fix Focus Areas
- .cursor/rules/vercel-ai-sdk.mdc[16-37]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

5. Output name collision 🐞 Bug ⛯ Reliability
Description
The rule recommends import { generateText, Output } from 'ai', but this repo already imports a
type named Output from @giselles-ai/protocol in key files; following the rule can create
confusing name collisions in real code.
Code

.cursor/rules/vercel-ai-sdk.mdc[R54-67]

+// ✅ CORRECT
+import { generateText, Output } from 'ai';
+import { z } from 'zod';
+
+const { output } = await generateText({
+  model,
+  output: Output.object({
+    schema: z.object({
+      name: z.string(),
+      ingredients: z.array(z.object({ name: z.string(), amount: z.string() })),
+    }),
+  }),
+  prompt: 'Generate a lasagna recipe.',
+});
Evidence
The rule’s example introduces Output from ai, while core repo code already uses Output from
the protocol package. This is a predictable naming conflict when writing generation code in this
repo.

.cursor/rules/vercel-ai-sdk.mdc[54-66]
packages/giselle/src/generations/generate-content.ts[20-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The rule’s examples import `Output` from `ai`, but this repo commonly already imports `Output` from `@giselles-ai/protocol`. This can create naming collisions and confusion.
## Issue Context
TypeScript will force a resolution, but the rule should proactively show an aliasing pattern that matches this repo.
## Fix Focus Areas
- .cursor/rules/vercel-ai-sdk.mdc[54-68]
- packages/giselle/src/generations/generate-content.ts[20-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +1 to +4
---
description: Vercel AI SDK v6 patterns — prevents common hallucinations of legacy APIs
globs: *.tsx,*.ts
alwaysApply: false

Choose a reason for hiding this comment

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

Action required

1. V6 rule vs repo ai@5 🐞 Bug ✓ Correctness

The rule is labeled as “Vercel AI SDK v6 patterns” and applies to all *.ts/*.tsx, but the repo
catalog pins ai to 5.0.101; this can drive agents to generate APIs/patterns that may not exist in
the installed SDK, leading to compilation/runtime failures when code is added based on this rule.
Agent Prompt
## Issue description
The new Cursor rule is presented as “Vercel AI SDK v6 patterns” but the repo pins `ai` to 5.0.101. Since the rule’s `globs` cover all TS/TSX files, agents may generate code using APIs/patterns that don’t exist for the repo’s installed SDK version, causing compile/runtime errors.

## Issue Context
Cursor rules influence generated code. If the rule is version-specific, it should either be scoped to the relevant code areas or clearly gated by the dependency version.

## Fix Focus Areas
- .cursor/rules/vercel-ai-sdk.mdc[1-12]
- pnpm-workspace.yaml[52-60]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Member

@shige shige left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! Preventing AI SDK hallucinations is a great idea — we've definitely seen agents generate outdated patterns. However, there are a few issues that need to be addressed before we can merge this.

1. Version mismatch: our project is on AI SDK v5, not v6

We currently pin ai: 5.0.101 in pnpm-workspace.yaml. Several patterns in this rule are v6-specific and would be incorrect guidance for our codebase:

  • generateObjectOutput.object(): generateObject is still valid in v5
  • maxStepsstopWhen: stepCountIs(N): maxSteps is the correct option in v5
  • toDataStreamResponse()toUIMessageStreamResponse(): our codebase actually uses toUIMessageStream() (neither of the two options listed)

Could you verify each pattern against v5 and adjust accordingly?

2. Code style: single quotes → double quotes

Our project uses Biome with double quotes as the standard. All code examples in the rule use single quotes, which would cause agents to generate code that fails our formatter. Please update all examples to use double quotes.

3. Overly broad glob scope

globs: *.tsx,*.ts applies this rule to every TypeScript file, including UI components, tests, and database schemas that never touch the AI SDK. Consider narrowing the glob to relevant directories (e.g., packages/giselle/src/generations/**) or removing it so the rule is only triggered manually.

4. Canonical example doesn't match project patterns

The route handler example uses model: 'anthropic/claude-sonnet-4.5' as a raw string, but we use a language model registry pattern. This could steer agents away from our established conventions.

5. Relationship with existing update-ai-sdk.mdc

We already have .cursor/rules/update-ai-sdk.mdc. Could you clarify how these two rules relate? It might make sense to merge them or clearly differentiate their purposes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
.cursor/rules/vercel-ai-sdk.mdc (1)

3-3: Glob pattern is narrower than actual AI SDK usage across the codebase.

The glob packages/giselle/src/generations/**/*.ts only targets one package. Verification shows AI SDK patterns (streamText, createUIMessageStream, toUIMessageStream) are used in multiple packages outside this glob:

  • packages/react/src/generations/ (createUIMessageStream usage confirmed)
  • packages/protocol/src/generation/
  • packages/rag/src/embedder/
  • packages/langfuse/src/
  • packages/github-tool/src/

Since the rule title states "Correct Patterns for This Project" (emphasis suggesting broad scope), consider expanding the glob pattern to cover all AI SDK usage:

-globs: packages/giselle/src/generations/**/*.ts
+globs: "{packages/**/src/generations/**/*.ts,apps/**/trigger/**/*.ts}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/rules/vercel-ai-sdk.mdc at line 3, The current glob
"packages/giselle/src/generations/**/*.ts" is too narrow and misses AI SDK
usages (e.g., streamText, createUIMessageStream, toUIMessageStream) in other
packages; update the rule in vercel-ai-sdk.mdc to expand the glob to cover all
packages where those symbols appear (for example include patterns like
packages/**/src/generations/**/*.ts and packages/**/src/**/generations/**/*.ts
and/or add explicit package paths such as packages/react/src/generations/**,
packages/protocol/src/generation/**, packages/rag/src/embedder/**,
packages/langfuse/src/**, packages/github-tool/src/**) so the rule will scan all
locations referencing streamText, createUIMessageStream and toUIMessageStream.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.cursor/rules/vercel-ai-sdk.mdc:
- Around line 115-119: Update the documentation so it does not label
toUIMessageStreamResponse as "outdated": explicitly state that
toUIMessageStreamResponse (introduced in the v5 SDK) is a current helper that
wraps a raw stream into a Response object, while toDataStreamResponse is the
removed/outdated helper; locate the example lines showing
result.toDataStreamResponse() and result.toUIMessageStreamResponse() and adjust
the wording to reflect this distinction.
- Around line 194-230: The example stops after creating uiMessageStream (from
streamTextResult.toUIMessageStream) and never returns an HTTP response; update
the canonical Route Handler snippet to return the stream as the route's HTTP
response (take uiMessageStream produced by streamTextResult.toUIMessageStream
and send it back from the handler with appropriate status and
streaming/content-type headers) so a copy-pasteable handler actually returns the
streaming response to the client.
- Around line 153-166: Update the docs/examples to actually show converting
UIMessage[] to ModelMessage[] using convertToModelMessages() before passing
messages into model APIs: replace or augment the “✅ CORRECT” snippet (which
currently just imports UIMessage and ModelMessage) with a short example that
calls convertToModelMessages(messages) and then calls streamText({ messages:
modelMessages, ... }); also fix the canonical pattern that currently passes
messages directly (lines around streamText call) to instead use the converted
modelMessages so the examples consistently demonstrate convertToModelMessages(),
referencing the types UIMessage, ModelMessage, the helper
convertToModelMessages, and the streamText call site.

---

Nitpick comments:
In @.cursor/rules/vercel-ai-sdk.mdc:
- Line 3: The current glob "packages/giselle/src/generations/**/*.ts" is too
narrow and misses AI SDK usages (e.g., streamText, createUIMessageStream,
toUIMessageStream) in other packages; update the rule in vercel-ai-sdk.mdc to
expand the glob to cover all packages where those symbols appear (for example
include patterns like packages/**/src/generations/**/*.ts and
packages/**/src/**/generations/**/*.ts and/or add explicit package paths such as
packages/react/src/generations/**, packages/protocol/src/generation/**,
packages/rag/src/embedder/**, packages/langfuse/src/**,
packages/github-tool/src/**) so the rule will scan all locations referencing
streamText, createUIMessageStream and toUIMessageStream.

Comment on lines +115 to +119
```typescript
// ❌ WRONG — outdated helpers
result.toDataStreamResponse();
result.toUIMessageStreamResponse();
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

toUIMessageStreamResponse() is mislabeled as "outdated."

toUIMessageStreamResponse was introduced in the v5 SDK and is still a valid, current helper — it simply wraps the raw stream into a Response object. Calling it "outdated" alongside the genuinely removed toDataStreamResponse() is factually wrong and may cause an agent to avoid it even in contexts where it's appropriate.

📝 Suggested wording fix
 // ❌ WRONG — outdated helpers
 result.toDataStreamResponse();
-result.toUIMessageStreamResponse();
+// ❌ AVOID in this project — wraps the stream into a Response directly;
+//    use toUIMessageStream() and compose the response via createUIMessageStreamResponse()
+// result.toUIMessageStreamResponse();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/rules/vercel-ai-sdk.mdc around lines 115 - 119, Update the
documentation so it does not label toUIMessageStreamResponse as "outdated":
explicitly state that toUIMessageStreamResponse (introduced in the v5 SDK) is a
current helper that wraps a raw stream into a Response object, while
toDataStreamResponse is the removed/outdated helper; locate the example lines
showing result.toDataStreamResponse() and result.toUIMessageStreamResponse() and
adjust the wording to reflect this distinction.

Comment on lines +153 to +166
## 6. Messages: `UIMessage` + `ModelMessage`

Client messages are `UIMessage` type. Model calls expect `ModelMessage`. Use `convertToModelMessages()` to convert between them.

```typescript
// ✅ CORRECT
import { streamText, type UIMessage, type ModelMessage } from "ai";
```

```typescript
// ❌ WRONG — using untyped message arrays
const { messages } = await req.json();
streamText({ messages, ... }); // Missing type safety
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Rule 6's ✅ CORRECT example never demonstrates convertToModelMessages() usage.

The prose on line 155 says to use convertToModelMessages() to convert between UIMessage[] and ModelMessage[], but the code example shows only type imports — the actual call site is never demonstrated. An agent following this rule won't know where or how to invoke the conversion.

Compounding this, the canonical pattern (lines 211–213) passes messages directly to streamText without any conversion, directly contradicting the advice here.

📝 Proposed example additions
 // ✅ CORRECT
-import { streamText, type UIMessage, type ModelMessage } from "ai";
+import { streamText, convertToModelMessages, type UIMessage } from "ai";
+
+// In your route handler:
+const { messages }: { messages: UIMessage[] } = await req.json();
+
+const result = streamText({
+  model,
+  messages: convertToModelMessages(messages), // UIMessage[] → ModelMessage[]
+  tools: { ... },
+});

And in the canonical pattern (line 213):

-  messages,
+  messages: convertToModelMessages(messages),
📝 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
## 6. Messages: `UIMessage` + `ModelMessage`
Client messages are `UIMessage` type. Model calls expect `ModelMessage`. Use `convertToModelMessages()` to convert between them.
```typescript
// ✅ CORRECT
import { streamText, type UIMessage, type ModelMessage } from "ai";
```
```typescript
// ❌ WRONG — using untyped message arrays
const { messages } = await req.json();
streamText({ messages, ... }); // Missing type safety
```
## 6. Messages: `UIMessage` + `ModelMessage`
Client messages are `UIMessage` type. Model calls expect `ModelMessage`. Use `convertToModelMessages()` to convert between them.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/rules/vercel-ai-sdk.mdc around lines 153 - 166, Update the
docs/examples to actually show converting UIMessage[] to ModelMessage[] using
convertToModelMessages() before passing messages into model APIs: replace or
augment the “✅ CORRECT” snippet (which currently just imports UIMessage and
ModelMessage) with a short example that calls convertToModelMessages(messages)
and then calls streamText({ messages: modelMessages, ... }); also fix the
canonical pattern that currently passes messages directly (lines around
streamText call) to instead use the converted modelMessages so the examples
consistently demonstrate convertToModelMessages(), referencing the types
UIMessage, ModelMessage, the helper convertToModelMessages, and the streamText
call site.

Comment on lines +194 to +230
## Reference: Canonical Streaming Pattern

A correct streaming setup following this project's conventions:

```typescript
import {
streamText,
stepCountIs,
smoothStream,
type UIMessage,
} from "ai";
import { createGateway } from "@ai-sdk/gateway";

const gateway = createGateway({
headers: aiGatewayHeaders,
});

const streamTextResult = streamText({
model: gateway("openai/gpt-4o"),
messages,
tools: toolSet,
stopWhen: stepCountIs(5),
experimental_transform: smoothStream({
delayInMs: 1000,
chunking: "line",
}),
onError: ({ error }) => {
// handle error
},
});

const uiMessageStream = streamTextResult.toUIMessageStream({
onFinish: async ({ messages: generateMessages }) => {
// handle completion
},
});
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Canonical "Route Handler" pattern is incomplete: no HTTP response is returned.

The PR describes this as a "canonical Route Handler reference template for copy-paste," but the snippet ends after creating uiMessageStream (line 225) with no return statement. A copy-pasted route handler would silently return nothing.

It should close with something like:

 const uiMessageStream = streamTextResult.toUIMessageStream({
   onFinish: async ({ messages: generateMessages }) => {
     // handle completion
   },
 });
+
+return new Response(uiMessageStream, {
+  headers: { "Content-Type": "text/plain; charset=utf-8" },
+});
+// — or, using the SDK helper —
+// import { createUIMessageStreamResponse } from "ai";
+// return createUIMessageStreamResponse({ stream: uiMessageStream });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/rules/vercel-ai-sdk.mdc around lines 194 - 230, The example stops
after creating uiMessageStream (from streamTextResult.toUIMessageStream) and
never returns an HTTP response; update the canonical Route Handler snippet to
return the stream as the route's HTTP response (take uiMessageStream produced by
streamTextResult.toUIMessageStream and send it back from the handler with
appropriate status and streaming/content-type headers) so a copy-pasteable
handler actually returns the streaming response to the client.

@cubaseuser123
Copy link
Author

Thanks for the detailed review! I went through your codebase, specifically the files generate-content.ts, both Postgres tools, and biome.json, to ensure every pattern matches what you actually use. Here are the changes:

  1. Version mismatch, fixed.
    I reframed the entire rule from "v6" to "correct patterns for this project." I removed generateObject to Output.object() as a strict rule since generateObject is valid at your pinned version.

One suggestion that I would like to make: Since update-ai-sdk.mdc exists specifically for version upgrades, I added a brief note in Section 7 to mention that generateObject is deprecated upstream in v6. When you upgrade, this rule will already be ready. I can remove this note if you prefer to keep the rule focused only on v5.

  1. Double quotes, fixed.
    All code examples now use double quotes to match your Biome config (quoteStyle: "double").

  2. Globs narrowed, fixed.
    I changed from .tsx,.ts to:

packages/giselle/src/generations/**/*.ts

  1. Canonical example, rewritten.
    I rewrote the reference example to match your actual patterns:
    createGateway() from @ai-sdk/gateway instead of raw model strings,
    toUIMessageStream() instead of toUIMessageStreamResponse(),
    smoothStream() with your line-chunking config,
    Custom stopWhen pattern alongside stepCountIs (both variants from your generate-content.ts).

  2. Relationship with update-ai-sdk.mdc, clarified.
    I added a note at the top of the rule:

How this rule differs from update-ai-sdk.mdc: That rule covers upgrading SDK versions (running pnpm outdated, updating the catalog). This rule is about writing correct code against the current pinned SDK version.

@cubaseuser123 cubaseuser123 requested a review from shige February 22, 2026 08:46
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