Skip to content

fix: add allowSystemInMessages to all AI SDK call sites#2141

Open
thelinuxkid wants to merge 1 commit into
browserbase:mainfrom
enricai:fix/allow-system-in-messages
Open

fix: add allowSystemInMessages to all AI SDK call sites#2141
thelinuxkid wants to merge 1 commit into
browserbase:mainfrom
enricai:fix/allow-system-in-messages

Conversation

@thelinuxkid
Copy link
Copy Markdown

@thelinuxkid thelinuxkid commented May 17, 2026

Problem

@browserbasehq/stagehand@3.4.0 declares "ai": "^5.0.133" as a peer dependency. The Vercel AI SDK introduced a breaking change in PR #14752 (merged April 28, 2026): passing a role: "system" message inside the messages array now throws an InvalidPromptError by default:

System messages are not allowed in the prompt or messages fields.
Use the instructions option instead.

The repo lockfile pins ai@5.0.133 (pre-break, October 2025), so developers working directly in this repo don't see the error. However, end users installing @browserbasehq/stagehand resolve ^5.0.133ai@5.0.188 (the latest stable 5.x, published May 12 2026, post-break), and hit the error on every LLM call.

Why Stagehand passes system messages in messages

Stagehand intentionally passes system messages inside the messages array (rather than using the system parameter) in order to attach Anthropic prompt-caching directives via providerOptions:

{
  role: "system",
  content: systemPrompt,
  providerOptions: {
    anthropic: { cacheControl: { type: "ephemeral" } },
  },
}

This pattern is deliberate and correct — it cannot be replaced by the system parameter in the current AI SDK version without losing caching support.

Fix

The AI SDK provides allowSystemInMessages: true as an explicit opt-in for exactly this use case. This PR adds it to all 8 affected call sites across 4 files:

File Call sites
packages/core/lib/v3/llm/aisdk.ts generateObject, generateText
packages/core/lib/v3/external_clients/aisdk.ts generateObject, generateText
packages/core/lib/v3/handlers/v3AgentHandler.ts generateText (non-streaming), streamText
packages/evals/lib/AISdkClientWrapped.ts generateObject, generateText

packages/core/lib/v3/agent/utils/handleDoneToolCall.ts is correctly excluded — it already uses the system: parameter and does not put system messages in the messages array.

Test plan

  • Install ai@5.0.188 (or latest ^5.0.133) and run any Stagehand script that exercises act, extract, or agent — confirm no InvalidPromptError is thrown
  • Confirm Anthropic prompt caching still works (system message providerOptions are preserved)

Summary by cubic

Opt in to allowSystemInMessages at all AI SDK call sites to prevent InvalidPromptError with newer ai versions. Keeps system prompts in the messages array so Anthropic caching continues to work for @browserbasehq/stagehand users.

  • Bug Fixes
    • Added allowSystemInMessages: true to generateObject, generateText, and streamText paths (8 sites across 4 files), excluding code that already uses the system param.
    • Compatible with ai@>=5.0.168 and older ^5.x.
    • No prompt behavior changes; Anthropic cache-control directives are preserved.

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

ai@>=5.0.168 throws InvalidPromptError when role:"system" appears in
the messages array without allowSystemInMessages:true. Stagehand
intentionally passes system messages via the messages array (to support
Anthropic cache control via providerOptions), so opt in explicitly at
all 8 affected call sites.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 17, 2026

⚠️ No Changeset found

Latest commit: 9a4bb32

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
Copy Markdown
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 May 17, 2026
Copy link
Copy Markdown
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.

No issues found across 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant UserApp as User Application
    participant Stagehand as Stagehand Core
    participant AISdk as AI SDK (^5.x)
    participant Anthropic as Anthropic API
    
    Note over UserApp,Anthropic: LLM Call Flow with allowSystemInMessages: true
    
    UserApp->>Stagehand: act() / extract() / agent()
    
    Note over Stagehand: Three entry points
    
    Stagehand->>Stagehand: Build messages array
    
    Note over Stagehand: System prompt placed in messages[]<br/>with providerOptions for caching
    
    alt Core LLM calls (v3/llm/aisdk.ts)
        Stagehand->>AISdk: generateObject(messages, allowSystemInMessages: true)
        Stagehand->>AISdk: generateText(messages, allowSystemInMessages: true)
    else External client calls (v3/external_clients/aisdk.ts)
        Stagehand->>AISdk: generateObject(messages, allowSystemInMessages: true)
        Stagehand->>AISdk: generateText(messages, allowSystemInMessages: true)
    else Agent handler (v3/handlers/v3AgentHandler.ts)
        Stagehand->>AISdk: generateText(messages, allowSystemInMessages: true)
        Stagehand->>AISdk: streamText(messages, allowSystemInMessages: true)
    else Evals client (evals/lib/AISdkClientWrapped.ts)
        Stagehand->>AISdk: generateObject(messages, allowSystemInMessages: true)
        Stagehand->>AISdk: generateText(messages, allowSystemInMessages: true)
    end
    
    Note over AISdk: allowSystemInMessages: true<br/>prevents InvalidPromptError
    
    AISdk->>Anthropic: API call with system message + cacheControl
    Anthropic-->>AISdk: Response with cached prompt
    AISdk-->>Stagehand: LLM result
    
    Stagehand-->>UserApp: Action result / extracted data
    
    Note over Stagehand,Anthropic: handleDoneToolCall.ts (excluded)<br/>uses system: param instead of messages[]
Loading

Re-trigger 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