stagehand icon indicating copy to clipboard operation
stagehand copied to clipboard

Can't get Stagehand instance with custom LLMClient

Open AndresCardonaDev opened this issue 2 months ago • 3 comments

Environment Information

Please provide the following information to help us reproduce and resolve your issue:

Stagehand:

  • Language/SDK: Typescript
  • Stagehand version: 3.0.1

AI Provider:

  • Provider: Open AI, trying to use Langchain
  • Model: gpt-5-mini

Issue Description

Can't even initialize Stagehand, despite sending the llmClient parameter demands the modelApiKey i need it to use the client only

Steps to Reproduce

  1. Pass a custom LLMClient (Used the one you implemented in examples for langchain
  2. Try to initialize with Stagehand constructor and llmClient parameter
  3. You get this error:
 "type": "StagehandAPIError",
 "message": "modelApiKey is required",

Minimal Reproduction Code

I'm including my actual set of parameters

import { Stagehand } from '@browserbase/stagehand';

const stagehand = new Stagehand({
{
    verbose: 1 /* Verbosity level for logging: 0 = silent, 1 = info, 2 = all */,
    domSettleTimeoutMs: 30_000 /* Timeout for DOM to settle in milliseconds */,
    // Browser configuration
    env: 'BROWSERBASE' /* Environment to run in: LOCAL or BROWSERBASE */,
    apiKey: config.browserBase.apiKey /* API key for authentication */,
    projectId: config.browserBase.projectId /* Project identifier */,
    browserbaseSessionID: undefined /* Session ID for resuming Browserbase sessions */,
    llmClient: new LangchainClient(new ChatOpenAI({
      apiKey: process.env.OPENAI_API_KEY,
      model: 'gpt-5-mini',
      modelName: 'gpt-5-mini',
      reasoning: { effort: 'low' },
      verbose: config.langchain.verbose,
    })),
    systemPrompt: SYSTEM_PROMPT_FOR_AGENT,
    browserbaseSessionCreateParams: {
      projectId: config.browserBase.projectId,
      keepAlive: true,
      browserSettings: {
        blockAds: true,
        // Dev note: https://docs.browserbase.com/features/viewports Can't be custom, check for documented supported ones
        viewport: isInteractingFromMobile
          ? {
            width: 390,
            height: 844,
          }
          : {
            width: 1024,
            height: 768,
          },
        ...(isInteractingFromMobile
          ? {
            fingerprint: {
              devices: ['mobile'],
              locales: ['en-US'],
              operatingSystems: ['android'],
            },
          }
          : {}
        ),
      },
      // dev advice: https://docs.browserbase.com/guides/using-session-metadata Doesn't allow anything but simple strings, not longer than 256
      userMetadata: _.omitBy({
        chatId: telemetry?.chatId?.toString(),
        nurseId: telemetry?.nurseId?.toString(),
        jobId: telemetry?.jobId?.toString(),
        disciplineId: telemetry?.disciplineId?.toString(),
        specialtyId: telemetry?.specialtyId?.toString(),
      }, (v) => !v),
    },
  }
});

// Steps that reproduce the issue

Error Messages / Log trace

 "type": "StagehandAPIError",
"message": "modelApiKey is required",

Screenshots / Videos

[Attach screenshots or videos here]

Related Issues

Are there any related issues or PRs?

  • Related to: #[issue number]
  • Duplicate of: #[issue number]
  • Blocks: #[issue number]

AndresCardonaDev avatar Nov 06 '25 13:11 AndresCardonaDev

I found a fix (at least for the AISDK):

import "dotenv/config";
import { Stagehand, AISdkClient } from "@browserbasehq/stagehand";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";

const openrouter = createOpenRouter({
    apiKey: process.env.OPENROUTER_API_KEY!,
});

const modelName = "moonshotai/kimi-k2-thinking";

class AISdkClientWithLanguageModel extends AISdkClient {
    private modelInstance: any;

    constructor(config: { model: any }) {
        super(config);
        this.modelInstance = config.model;
    }

    getLanguageModel() {
        return this.modelInstance;
    }
}

const stagehand = new Stagehand({
    env: "LOCAL",
    llmClient: new AISdkClientWithLanguageModel({
        model: openrouter(modelName),
    }),
});

await stagehand.init();

const agent = await stagehand.agent();

const result = await agent.execute("Tell me the github repository browserbase/stagehand has how many stars?");

console.log(result);

await stagehand.close();

kalil0321 avatar Nov 06 '25 23:11 kalil0321

I found a fix (at least for the AISDK):

import "dotenv/config"; import { Stagehand, AISdkClient } from "@browserbasehq/stagehand"; import { createOpenRouter } from "@openrouter/ai-sdk-provider";

const openrouter = createOpenRouter({ apiKey: process.env.OPENROUTER_API_KEY!, });

const modelName = "moonshotai/kimi-k2-thinking";

class AISdkClientWithLanguageModel extends AISdkClient { private modelInstance: any;

constructor(config: { model: any }) {
    super(config);
    this.modelInstance = config.model;
}

getLanguageModel() {
    return this.modelInstance;
}

}

const stagehand = new Stagehand({ env: "LOCAL", llmClient: new AISdkClientWithLanguageModel({ model: openrouter(modelName), }), });

await stagehand.init();

const agent = await stagehand.agent();

const result = await agent.execute("Tell me the github repository browserbase/stagehand has how many stars?");

console.log(result);

await stagehand.close();

Can this work?

JerryWu1234 avatar Nov 18 '25 07:11 JerryWu1234

太谢谢你了 折腾一天了 有效

Quadra-Kill avatar Nov 29 '25 06:11 Quadra-Kill