Skip to content

SupportedUnderstudyAction Enum validation for 'method' on act/observe#1613

Merged
miguelg719 merged 5 commits intomainfrom
miguelgonzalez/stg-1212-enforce-enum-for-method-selection-in-actobserve
Jan 27, 2026
Merged

SupportedUnderstudyAction Enum validation for 'method' on act/observe#1613
miguelg719 merged 5 commits intomainfrom
miguelgonzalez/stg-1212-enforce-enum-for-method-selection-in-actobserve

Conversation

@miguelg719
Copy link
Collaborator

@miguelg719 miguelg719 commented Jan 26, 2026

why

act and observe don't fail on validation if the LLM generates an action with a non-supported method

what changed

  • Added z.enum(supportedUnderstudyAction) to the act and observe inference schemas

test plan

  • Evals (act/observe)

Summary by cubic

Enforces SupportedUnderstudyAction enum for the method field in act and observe so invalid actions are rejected during schema validation. Prevents unsupported methods from slipping through when the LLM generates actions and supports Linear STG-1212.

  • Bug Fixes

    • Use z.enum(Object.values(SupportedUnderstudyAction)) for act/observe; unsupported methods fail fast across Zod v3/v4.
    • Added tests confirming enum validation works in both Zod v3 and v4.
    • Updated method description to reference Understudy interaction methods instead of Playwright.
  • Refactors

    • Migrated enum compatibility tests from Playwright to Vitest and moved them to packages/core/tests.

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

@changeset-bot
Copy link

changeset-bot bot commented Jan 26, 2026

🦋 Changeset detected

Latest commit: 4aa2573

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

This PR includes changesets to release 3 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch
@browserbasehq/stagehand-server 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

@miguelg719 miguelg719 marked this pull request as ready for review January 26, 2026 22:36
@miguelg719 miguelg719 added act These changes pertain to the act function observe These changes pertain to the observe function combination These changes affect multiple Stagehand functions labels Jan 26, 2026
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.

1 issue found across 2 files

Confidence score: 2/5

  • SupportedUnderstudyAction is passed to z.enum in packages/core/lib/inference.ts, which will throw at runtime because z.enum expects a string literal tuple, making this a likely break in schema construction
  • Given the 7/10 severity and direct runtime failure risk, this change carries high merge risk until the enum handling is corrected
  • Pay close attention to packages/core/lib/inference.ts - fix the enum usage (e.g., z.nativeEnum or Object.values(...)) to avoid runtime schema errors.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/lib/inference.ts">

<violation number="1" location="packages/core/lib/inference.ts:258">
P1: `SupportedUnderstudyAction` is a TS enum, but `z.enum` expects a string literal tuple. This will fail schema construction at runtime; use `z.nativeEnum` (or pass `Object.values(...)`) for enums.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant User as User Code
    participant Core as Stagehand Core
    participant LLM as LLM Client
    participant Zod as Zod Validator

    User->>Core: act() / observe()
    
    Note over Core: CHANGED: Schema definition now uses<br/>z.enum(SupportedUnderstudyAction)<br/>instead of z.string()

    Core->>LLM: Generate completion (prompt + schema)
    LLM-->>Core: JSON Response (proposed action)

    Core->>Zod: Validate response against schema

    alt Valid Method (e.g. "click", "type")
        Zod-->>Core: Parsed Object
        Core->>Core: Proceed to execution
        Core-->>User: Success
    else NEW: Invalid Method (e.g. "hover", "unknown")
        Note over Zod: Validation fails immediately<br/>(Value not in Enum)
        Zod--xCore: ZodError
        Core--xUser: Throw Validation Error
    end
Loading

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

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 26, 2026

Greptile Overview

Greptile Summary

This PR adds enum validation to the method field in both act and observe inference schemas to prevent LLM-generated actions with unsupported methods from passing validation.

Key Changes:

  • Replaced .string() with .enum(Object.values(SupportedUnderstudyAction)) for the method field in both act and observe schemas in packages/core/lib/inference.ts:257-264 and packages/core/lib/inference.ts:398-405
  • Used Object.values() approach for Zod v3/v4 compatibility (Zod v3 doesn't accept TypeScript enums directly in z.enum())
  • Updated method field description from "Playwright interaction methods" to "Understudy interaction methods" for accuracy
  • Added comprehensive test suite validating the approach works in both Zod v3 and v4

How it Works:
The PR validates that LLM-generated method values must match one of the 11 supported actions (click, fill, type, press, scrollTo, nextChunk, prevChunk, selectOptionFromDropdown, hover, doubleClick, dragAndDrop) before being passed to performUnderstudyMethod in packages/core/lib/v3/handlers/handlerUtils/actHandlerUtils.ts:84-110, which throws UnderstudyCommandException for unsupported methods. This change shifts validation earlier in the pipeline, providing faster feedback.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The change adds validation without breaking existing functionality. The implementation correctly handles Zod v3/v4 compatibility using Object.values(), which is verified by comprehensive test coverage. The validation aligns perfectly with the actual supported methods in performUnderstudyMethod.
  • No files require special attention

Important Files Changed

Filename Overview
.changeset/floppy-zebras-lie.md Adds standard changeset file documenting the patch-level change
packages/core/lib/inference.ts Adds enum validation for method field in act/observe schemas, compatible with both Zod v3 and v4
packages/core/lib/v3/tests/zod-enum-compatibility.spec.ts Comprehensive test suite verifying Zod v3/v4 compatibility with Object.values() approach

Sequence Diagram

sequenceDiagram
    participant LLM as LLM Client
    participant Inference as act/observe inference
    participant Zod as Zod Schema Validator
    participant Handler as ActHandler/ObserveHandler
    participant Understudy as performUnderstudyMethod
    
    LLM->>Inference: Generate action with method field
    Inference->>Zod: Validate against schema with enum
    alt Invalid method (e.g., "invalidMethod")
        Zod-->>Inference: ❌ Validation fails
        Inference-->>LLM: Reject early - unsupported method
    else Valid method (e.g., "click")
        Zod-->>Inference: ✅ Validation passes
        Inference->>Handler: Return validated action
        Handler->>Understudy: performUnderstudyMethod(method, xpath, args)
        Understudy->>Understudy: Check METHOD_HANDLER_MAP or switch
        Understudy-->>Handler: Execute method handler
        Handler-->>LLM: Action completed
    end
Loading

Copy link
Contributor

@greptile-apps greptile-apps 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 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

),
method: z
.string()
.enum(SupportedUnderstudyAction)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should use z.nativeEnum(SupportedUnderstudyAction) instead of z.enum(SupportedUnderstudyAction). The z.enum() function expects a tuple of string literals like ["value1", "value2"], while z.nativeEnum() is designed for TypeScript enums.

Suggested change
.enum(SupportedUnderstudyAction)
.nativeEnum(SupportedUnderstudyAction)
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/lib/inference.ts
Line: 258:258

Comment:
Should use `z.nativeEnum(SupportedUnderstudyAction)` instead of `z.enum(SupportedUnderstudyAction)`. The `z.enum()` function expects a tuple of string literals like `["value1", "value2"]`, while `z.nativeEnum()` is designed for TypeScript enums.

```suggestion
            .nativeEnum(SupportedUnderstudyAction)
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Outdated for Zod 4. According to the documentation:
"This replaces the z.nativeEnum() API in Zod 3"

Docs:

In Zod 4, z.enum() now accepts TypeScript enums directly:

  enum Fish {                                                                                                                    
    Salmon = 0,                                                                                                                  
    Tuna = 1                                                                                                                     
  }                                                                                                                              
                                                                                                                               
  const FishEnum = z.enum(Fish);  // ✅ Works in Zod 4  

.describe("a description of the accessible element and its purpose"),
method: z
.string()
.enum(SupportedUnderstudyAction)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same issue - should use z.nativeEnum(SupportedUnderstudyAction) instead of z.enum(SupportedUnderstudyAction).

Suggested change
.enum(SupportedUnderstudyAction)
.nativeEnum(SupportedUnderstudyAction)
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/lib/inference.ts
Line: 393:393

Comment:
Same issue - should use `z.nativeEnum(SupportedUnderstudyAction)` instead of `z.enum(SupportedUnderstudyAction)`.

```suggestion
      .nativeEnum(SupportedUnderstudyAction)
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Outdated for Zod 4. According to the documentation:
"This replaces the z.nativeEnum() API in Zod 3"

Docs:

In Zod 4, z.enum() now accepts TypeScript enums directly:

  enum Fish {                                                                                                                    
    Salmon = 0,                                                                                                                  
    Tuna = 1                                                                                                                     
  }                                                                                                                              
                                                                                                                               
  const FishEnum = z.enum(Fish);  // ✅ Works in Zod 4  

@miguelg719
Copy link
Collaborator Author

Addresses follow up on #1608

chromiebot pushed a commit to chromiebot/stagehand that referenced this pull request Jan 27, 2026
Add comprehensive tests for SupportedUnderstudyAction enum validation
with both Zod v3 and v4. These tests verify that:

1. Object.values(SupportedUnderstudyAction) produces correct array for z.enum()
2. z.enum() with Object.values() works correctly in both Zod v3 and v4
3. z.enum() with raw TypeScript enum throws error on parse in Zod v3
4. z.enum() with raw TypeScript enum works in Zod v4 (but not v3 compatible)
5. All SupportedUnderstudyAction values are valid enum options

This test demonstrates that the current implementation in PR browserbase#1613 would
break for users running Zod v3, since z.enum() in v3 does NOT accept
TypeScript enums directly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
chromiebot and others added 3 commits January 26, 2026 20:26
# why

# what changed

# test plan


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes Zod v3 enum handling for method selection in act() and observe()
to prevent v3 runtime errors and keep validation consistent across Zod
v3 and v4.

- **Bug Fixes**
- Use Object.values(SupportedUnderstudyAction) with z.enum() in
inference.ts for act() and observe().
- Add tests verifying enum validation works in both Zod v3 and v4,
including invalid method rejection.
- Supports Linear STG-1212 by enforcing enum-based method selection in
act/observe.

<sup>Written for commit f827712.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browserbase/stagehand/pull/1618">Review in
cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Chromie Bot <chromie@browserbase.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
@miguelg719
Copy link
Collaborator Author

@greptileai @cubic-dev-ai

@cubic-dev-ai
Copy link
Contributor

cubic-dev-ai bot commented Jan 27, 2026

@greptileai @cubic-dev-ai

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

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 27, 2026

I can see the AI code review has been initiated for this PR. The changes look focused on adding proper enum validation for the method field in act/observe operations to prevent invalid actions from being accepted.

The implementation appears to address an important validation gap where unsupported methods could slip through without proper validation. Using z.enum(Object.values(SupportedUnderstudyAction)) is the correct approach for ensuring type safety across different Zod versions.

Feel free to ask any questions about the changes or share the AI review results when they're ready!

Copy link
Contributor

@greptile-apps greptile-apps 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 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

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.

No issues found across 3 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant Client
    participant Inference as Inference (act/observe)
    participant Zod as Zod Validator
    participant LLM as LLM Provider

    Note over Client, LLM: Flow applies to both act() and observe()

    Client->>Inference: Call act() or observe()
    
    Note over Inference: CHANGED: Schema Definition
    Inference->>Inference: Define 'method' using z.enum(Object.values(Enum))<br/>(Ensures Zod v3/v4 compatibility)

    Inference->>LLM: Prompt with updated schema description
    LLM-->>Inference: Return JSON response

    Inference->>Zod: Validate response against schema
    
    alt NEW: Invalid "method" (not in SupportedUnderstudyAction)
        Note right of LLM: e.g. { method: "non_existent_action" }
        Zod-->>Inference: Validation Error (Invalid Enum Value)
        Inference-->>Client: Throw Error (Fail Fast)
    else Valid "method"
        Note right of LLM: e.g. { method: "click" }
        Zod-->>Inference: Success (Parsed Action)
        Inference->>Inference: Execute Action / Return Observation
        Inference-->>Client: Result
    end
Loading

#1623)

… to Vitest

- Migrate test file from packages/core/lib/v3/tests/ to
packages/core/tests/
- Replace @playwright/test imports with vitest (describe, expect, it)
- Update test.describe() -> describe() and test() -> it()
- Adjust import path for SupportedUnderstudyAction enum

# why

# what changed

# test plan


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Migrated the Zod enum compatibility tests from Playwright to Vitest and
moved them to packages/core/tests. This consolidates on Vitest and keeps
Zod v3/v4 enum compatibility coverage for SupportedUnderstudyAction.

- **Refactors**
  - Replaced @playwright/test with vitest (describe, expect, it).
  - Updated test.describe/test() to describe/it.
- Adjusted SupportedUnderstudyAction import to
../lib/v3/types/private/handlers.

<sup>Written for commit 9f58557.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browserbase/stagehand/pull/1623">Review in
cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

Co-authored-by: Chromie Bot <chromie@browserbase.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
@miguelg719 miguelg719 merged commit aa4d981 into main Jan 27, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

act These changes pertain to the act function combination These changes affect multiple Stagehand functions observe These changes pertain to the observe function

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants