Skip to content

fix: enable structured outputs for all providers that support it#1944

Merged
monadoid merged 1 commit intoeconnrefusedfixfrom
stg-1555
Apr 8, 2026
Merged

fix: enable structured outputs for all providers that support it#1944
monadoid merged 1 commit intoeconnrefusedfixfrom
stg-1555

Conversation

@monadoid
Copy link
Copy Markdown
Contributor

@monadoid monadoid commented Apr 1, 2026

Why

This PR is meant to add structured-output support across the provider paths we use, while preserving the existing model-facing act/observe identifier shape.

What Changed

  • Kept the existing model-facing elementId / encoded ID format for act and observe, including the existing ^\\d+-\\d+$ validation.
  • Kept the structured-output provider configuration changes across the supported clients and AI SDK paths.
  • Continued resolving encoded IDs against the existing xpath map at the handler boundary.
  • Updated the unit regression coverage to assert the encoded-ID structured-output path.

Test Plan

Added passing tests

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 1, 2026

🦋 Changeset detected

Latest commit: 256bafd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch
@browserbasehq/stagehand-server-v3 Patch
@browserbasehq/stagehand-server-v4 Patch

Not sure what this means? Click here to learn what changesets are.

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

@monadoid monadoid marked this pull request as ready for review April 3, 2026 18:27
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.

1 issue found across 13 files

Confidence score: 4/5

  • This PR looks safe to merge overall, with a focused moderate-risk issue in a test file rather than production runtime code.
  • In packages/core/tests/unit/element-id-regression.test.ts, the vi.mock specifier missing .js may not match the ESM import, which can cause the mock to silently not apply and weaken regression protection.
  • Given severity 5/10 (with high confidence), this is a real correctness concern for test behavior, but it appears limited in scope and not strongly merge-blocking.
  • Pay close attention to packages/core/tests/unit/element-id-regression.test.ts - align mock/import specifiers (including .js) so ESM mocking applies reliably.
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/element-id-regression.test.ts">

<violation number="1" location="packages/core/tests/unit/element-id-regression.test.ts:10">
P2: The `vi.mock` path is missing the `.js` extension, inconsistent with the actual import on line 7 and the other `vi.mock` on line 15. In ESM mode, mismatched specifiers can cause the mock to silently not apply.

(Based on your team's feedback about requiring explicit .js extensions on all relative ESM import specifiers.) [FEEDBACK_USED]</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Handler as Act/Observe Handler
    participant Inf as Inference Layer
    participant LLM as LLM Client (OpenAI/AISDK)
    participant External as External LLM API
    participant Resolver as NEW: Model Action Resolver
    participant Snap as Snapshot Storage

    Note over Handler,Snap: Runtime Flow for Element Interaction

    Handler->>Snap: captureHybridSnapshot()
    Snap-->>Handler: combinedTree, xpathMap (encoded keys)

    Handler->>Inf: act() / observe()
    
    Note over Inf,LLM: Uses modelActResponseSchema / modelActionSchema

    Inf->>LLM: createChatCompletion(schema)
    
    LLM->>External: POST /completions (Strict JSON Mode)
    Note right of External: CHANGED: Returns structured target<br/>{frameOrdinal, backendNodeId}
    External-->>LLM: JSON Response
    
    LLM-->>Inf: Typed ModelAction
    Inf-->>Handler: Typed ModelAction

    Handler->>Resolver: NEW: resolveModelAction(action, xpathMap)
    
    rect rgb(240, 240, 240)
        Note over Resolver: Internal Mapping Logic
        Resolver->>Resolver: NEW: Encode target ref to "frame-node" string
        Resolver->>Resolver: Lookup XPath in map via encoded string
        
        alt method is dragAndDrop
            Resolver->>Resolver: NEW: Resolve destination ref to XPath
        end
    end

    Resolver-->>Handler: Resolved Action (with XPath selector)

    alt Action valid
        Handler->>Handler: performUnderstudyMethod(selector)
    else Element/XPath not found
        Handler-->>Handler: Handle missing element (Self-heal/Retry)
    end
Loading

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

@monadoid monadoid changed the title fix: use typed model refs for malformed element ids fix: Tighten required shape of frameOrdinal/backendNodeID Apr 6, 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.

1 issue found across 18 files (changes from recent commits).

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/lib/v3/external_clients/aisdk.ts">

<violation number="1" location="packages/core/lib/v3/external_clients/aisdk.ts:140">
P1: `response.output` can be `undefined` when `Output.object()` parsing fails, but it's returned directly as `data` without a null check. Unlike `generateObject` (which throws on schema mismatch), `generateText` with `Output.object` returns `undefined` on parse failure. This silently passes `undefined` to callers that expect a valid object, undermining the PR's goal of stricter schema enforcement.</violation>
</file>

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

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.

3 issues found across 18 files (changes from recent commits).

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/lib/v3/external_clients/aisdk.ts">

<violation number="1">
P2: Generation parameters (`temperature`, `maxOutputTokens`, `topP`, `frequencyPenalty`, `presencePenalty`) are no longer forwarded to `generateObject`. Any caller-specified values for these options will be silently ignored, potentially producing non-deterministic or unexpectedly long outputs.</violation>

<violation number="2">
P1: Removed null safety on `options.tools`. Since `tools` is optional in `ChatCompletionOptions`, this will throw `TypeError: options.tools is not iterable` when no tools are provided.</violation>
</file>

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

<violation number="1" location="packages/core/lib/v3/llm/aisdk.ts:167">
P1: Regression: `azure`, `vertex`, and `cerebras` provider options were dropped when replacing `buildStructuredProviderOptions` with the inline switch. These three providers will no longer receive their structured-output flags (`strictJsonSchema`/`structuredOutputs`), which can cause `generateObject` to fail for users on those providers.</violation>
</file>

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

@cubic-dev-ai
Copy link
Copy Markdown
Contributor

cubic-dev-ai bot commented Apr 7, 2026

You're iterating quickly on this pull request. To help protect your rate limits, cubic has paused automatic reviews on new pushes for now—when you're ready for another review, comment @cubic-dev-ai review.

@monadoid monadoid changed the base branch from main to temp/ci-local-browser-diagnostics April 7, 2026 12:47
@monadoid monadoid changed the base branch from temp/ci-local-browser-diagnostics to econnrefusedfix April 7, 2026 12:58
@monadoid monadoid changed the title fix: Tighten required shape of frameOrdinal/backendNodeID fix: enable structured outputs without changing elementId shape Apr 7, 2026
@monadoid monadoid changed the title fix: enable structured outputs without changing elementId shape fix: enable structured outputs for all providers that support it Apr 7, 2026
@monadoid
Copy link
Copy Markdown
Contributor Author

monadoid commented Apr 7, 2026

@cubic-dev-ai rerun pls

@cubic-dev-ai
Copy link
Copy Markdown
Contributor

cubic-dev-ai bot commented Apr 7, 2026

@cubic-dev-ai rerun pls

@monadoid I have started the AI code review. It will take a few minutes to complete.

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 Core as Stagehand / Core
    participant Client as AISdkClient
    participant AISDK as Vercel AI SDK
    participant API as LLM Provider API

    Note over Core,API: Structured Output Request Flow

    Core->>Client: createChatCompletion(options)
    
    Client->>Client: NEW: inferProviderName(modelId)
    
    Note over Client: NEW: Map provider-specific <br/>structured output flags
    
    alt provider is openai | azure | cerebras
        Client->>Client: Set strictJsonSchema: true
    else provider is google | vertex | groq
        Client->>Client: Set structuredOutputs: true
    else provider is mistral
        Client->>Client: Set structuredOutputs: true & strictJsonSchema: true
    else provider is anthropic
        Client->>Client: Set structuredOutputMode: "auto"
    end

    opt provider is openai
        Client->>Client: CHANGED: Merge reasoningEffort & textVerbosity <br/>into providerOptions.openai
    end

    Client->>AISDK: CHANGED: generateObject() with providerOptions
    
    AISDK->>API: Request with native structured output parameters
    
    alt Provider Success
        API-->>AISDK: Valid JSON response
        AISDK-->>Client: Typed Object
        Client-->>Core: Chat Completion Result
    else Provider Error / Validation Failure
        API-->>AISDK: Error response
        AISDK-->>Client: Error
        Client-->>Core: Throw Error / Fallback
    end
Loading

@monadoid monadoid merged commit 316f2c0 into econnrefusedfix Apr 8, 2026
204 checks passed
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