Skip to content

feat: add Novita AI as an LLM provider#1869

Open
Alex-wuhu wants to merge 1 commit intobrowserbase:mainfrom
Alex-wuhu:novita-integration
Open

feat: add Novita AI as an LLM provider#1869
Alex-wuhu wants to merge 1 commit intobrowserbase:mainfrom
Alex-wuhu:novita-integration

Conversation

@Alex-wuhu
Copy link

@Alex-wuhu Alex-wuhu commented Mar 22, 2026

Summary

Adds Novita AI as a supported LLM provider via the existing Vercel AI SDK / OpenAI-compatible path.

  • Provider key: novita
  • Base URL: https://api.novita.ai/openai (OpenAI-compatible)
  • Auth: NOVITA_API_KEY environment variable
  • Usage: novita/<model-id> format (e.g. novita/moonshotai/kimi-k2.5)

Supported models

Model ID Notes
novita/moonshotai/kimi-k2.5 Default — 262k context, vision, function calling
novita/zai-org/glm-5 202k context, function calling
novita/minimax/minimax-m2.5 204k context, function calling

Changes

packages/core/lib/v3/llm/LLMProvider.ts

  • Creates a novita static provider and createNovita factory using createOpenAI with baseURL: "https://api.novita.ai/openai"
  • Registers both in AISDKProviders and AISDKProvidersWithAPIKey

packages/core/lib/utils.ts

  • Adds novita: "NOVITA_API_KEY" to providerEnvVarMap

packages/core/tests/unit/llm-provider.test.ts

  • Adds unit tests for the novita provider (with API key, without options, with baseURL override)

Notes

  • Kimi models already have temperature-clamp (= 1) and prompt-JSON-fallback handling in aisdk.ts (patterns "kimi" and "glm" are already in PROMPT_JSON_FALLBACK_PATTERNS)
  • No new packages required — reuses @ai-sdk/openai already present

Summary by cubic

Adds Novita as a first-class LLM provider via the OpenAI-compatible endpoint. Use provider key novita with NOVITA_API_KEY against https://api.novita.ai/openai.

  • New Features
    • Supports novita/<model-id>: moonshotai/kimi-k2.5, zai-org/glm-5, minimax/minimax-m2.5.
    • Implements a static provider and factory using @ai-sdk/openai; supports API key and baseURL override.
    • Adds unit tests for API key usage, static provider path, and baseURL override.

Written for commit 1860060. Summary will update on new commits. Review in cubic

Registers Novita AI (OpenAI-compatible endpoint) via `@ai-sdk/openai`
with a fixed `baseURL` of `https://api.novita.ai/openai`. Supports all
three Novita chat models (kimi-k2.5, glm-5, minimax-m2.5) using the
`novita/<model-id>` format. API key is read from `NOVITA_API_KEY`.

- Add `novita` static provider and `createNovita` factory to
  `LLMProvider.ts` (both `AISDKProviders` and `AISDKProvidersWithAPIKey`)
- Add `novita: "NOVITA_API_KEY"` to `providerEnvVarMap` in `utils.ts`
- Add unit tests for the novita provider in `llm-provider.test.ts`
@changeset-bot
Copy link

changeset-bot bot commented Mar 22, 2026

⚠️ No Changeset found

Latest commit: 1860060

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.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

@github-actions
Copy link
Contributor

This PR is from an external contributor and must be approved by a stagehand team member with write access before CI can run.
Approving the latest commit mirrors it into an internal PR owned by the approver.
If new commits are pushed later, the internal PR stays open but is marked stale until someone approves the latest external commit and refreshes it.

@github-actions github-actions bot added external-contributor Tracks PRs mirrored from external contributor forks. external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. labels Mar 22, 2026
@Alex-wuhu Alex-wuhu marked this pull request as ready for review March 22, 2026 09:40
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 3 files

Confidence score: 3/5

  • There is a concrete user-impact risk in packages/core/lib/v3/llm/LLMProvider.ts: Novita’s reachable no-options/static provider path does not bind a Novita-specific API key, which could cause authentication failures or use an unintended credential source.
  • The test gap in packages/core/tests/unit/llm-provider.test.ts lowers confidence in this area—the custom baseURL override case currently uses Novita’s default URL and only checks that a value is defined, so override regressions may slip through.
  • Given the high-severity provider-path issue (7/10) with strong confidence, this is moderate merge risk rather than a merge-blocker, but it should be addressed soon.
  • Pay close attention to packages/core/lib/v3/llm/LLMProvider.ts, packages/core/tests/unit/llm-provider.test.ts - provider credential binding and baseURL override behavior need validation.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/tests/unit/llm-provider.test.ts">

<violation number="1" location="packages/core/tests/unit/llm-provider.test.ts:78">
P2: The "custom baseURL override" test is ineffective because it uses Novita’s default URL and only asserts definition, so regressions in override handling would go undetected.</violation>
</file>

<file name="packages/core/lib/v3/llm/LLMProvider.ts">

<violation number="1" location="packages/core/lib/v3/llm/LLMProvider.ts:38">
P1: Novita’s no-options/static provider path is reachable and does not bind a Novita-specific API key, risking wrong/default credential source or auth failure.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Client as User/Application
    participant Provider as LLMProvider.ts
    participant Env as Environment/Utils
    participant AISDK as @ai-sdk/openai
    participant Novita as Novita AI API

    Note over Client,Novita: Request Flow for "novita" Provider

    Client->>Provider: getAISDKLanguageModel("novita", modelId, options)
    
    Provider->>Env: NEW: Lookup "novita" in providerEnvVarMap
    Env-->>Provider: Return "NOVITA_API_KEY"

    alt NEW: options.apiKey provided OR process.env.NOVITA_API_KEY set
        Provider->>Provider: createNovita(options)
        Provider->>AISDK: NEW: createOpenAI({ baseURL: "https://api.novita.ai/openai", ...options })
    else Use default instance
        Provider->>Provider: Use static novita provider
        Note right of Provider: Pre-initialized with Novita Base URL
    end

    Provider-->>Client: Return LanguageModel instance

    Client->>AISDK: generateText() / streamText()
    
    AISDK->>Novita: CHANGED: POST to https://api.novita.ai/openai
    Note right of AISDK: Standard OpenAI-compatible payload

    alt Success
        Novita-->>AISDK: 200 OK (Model Response)
        AISDK-->>Client: Result object
    else Error (e.g. Invalid Key)
        Novita-->>AISDK: 401 Unauthorized
        AISDK-->>Client: Throw Error
    end
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

import { AISDKProvider, AISDKCustomProvider } from "../types/public/model.js";

const NOVITA_BASE_URL = "https://api.novita.ai/openai";
const novita = createOpenAI({ baseURL: NOVITA_BASE_URL });
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 22, 2026

Choose a reason for hiding this comment

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

P1: Novita’s no-options/static provider path is reachable and does not bind a Novita-specific API key, risking wrong/default credential source or auth failure.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/lib/v3/llm/LLMProvider.ts, line 38:

<comment>Novita’s no-options/static provider path is reachable and does not bind a Novita-specific API key, risking wrong/default credential source or auth failure.</comment>

<file context>
@@ -34,6 +34,11 @@ import { ollama, createOllama } from "ollama-ai-provider-v2";
 import { AISDKProvider, AISDKCustomProvider } from "../types/public/model.js";
 
+const NOVITA_BASE_URL = "https://api.novita.ai/openai";
+const novita = createOpenAI({ baseURL: NOVITA_BASE_URL });
+const createNovita: AISDKCustomProvider = (options) =>
+  createOpenAI({ baseURL: NOVITA_BASE_URL, ...options });
</file context>
Suggested change
const novita = createOpenAI({ baseURL: NOVITA_BASE_URL });
const novita = createOpenAI({
baseURL: NOVITA_BASE_URL,
apiKey: process.env.NOVITA_API_KEY,
});
Fix with Cubic

it("works with custom baseURL override", () => {
const model = getAISDKLanguageModel("novita", "minimax/minimax-m2.5", {
apiKey: "test-novita-key",
baseURL: "https://api.novita.ai/openai",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 22, 2026

Choose a reason for hiding this comment

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

P2: The "custom baseURL override" test is ineffective because it uses Novita’s default URL and only asserts definition, so regressions in override handling would go undetected.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/tests/unit/llm-provider.test.ts, line 78:

<comment>The "custom baseURL override" test is ineffective because it uses Novita’s default URL and only asserts definition, so regressions in override handling would go undetected.</comment>

<file context>
@@ -57,6 +57,30 @@ describe("getAISDKLanguageModel", () => {
+    it("works with custom baseURL override", () => {
+      const model = getAISDKLanguageModel("novita", "minimax/minimax-m2.5", {
+        apiKey: "test-novita-key",
+        baseURL: "https://api.novita.ai/openai",
+      });
+      expect(model).toBeDefined();
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. external-contributor Tracks PRs mirrored from external contributor forks.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant