Skip to content

Use z.strictObject for protocol schemas - #2434

Merged
monadoid merged 1 commit into
v4-spikefrom
use-strict-object
Jul 28, 2026
Merged

Use z.strictObject for protocol schemas#2434
monadoid merged 1 commit into
v4-spikefrom
use-strict-object

Conversation

@monadoid

@monadoid monadoid commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • require every object schema in packages/protocol/schemas.ts to use z.strictObject
  • reserve dynamic data for explicit z.json() and z.record() fields
  • move act, extract, and observe option optionality to their containing RPC parameter schemas
  • remove client-schema .unwrap() calls
  • regenerate the JSON Schema and Python models so unknown fields are forbidden
  • update runtime, locator, and LLM tests for strict object parsing

Summary by cubic

Make all protocol and SDK schemas strict. Unknown fields now error across the wire and in both SDKs, reducing typos and hidden bugs.

  • Refactors

    • Switched all protocol object schemas to z.strictObject(); removed .strict(), .loose(), .passthrough(), and .catchall().
    • JSON Schema: strict objects use additionalProperties: false (e.g., LLM results, Browserbase configs, proxy configs).
    • LLM results are strict; extra fields (e.g., providerMetadata) are rejected. Tests updated.
    • RuntimeDescriptorSchema and PageLocatorSchema are strict; unknown fields and stale locator handles now error.
    • Params: options are optional at call sites (act/observe/extract, page methods); typos in options fail tests.
    • TS SDK: aligned with strict protocol types; CdpBrowserSourceSchema uses z.strictObject; client options extend protocol options.
    • Python SDK: generated models use extra="forbid" (including LLM results) to disallow unknown fields.
    • Added rules/ast-grep/protocol-schema-strictness.test.ts to enforce z.strictObject in protocol schemas.
    • Restored v3 eval tooling under packages/evals (CLI, datasets, core tools); targets stagehand-v3 and is wired into workspace checks without changing v4 runtime.
    • Added opt‑in PR previews: preview label builds the TS package tarball, Python wheel, and extension ZIP as one artifact (no version bumps or releases). README and just _preview added; oxlint override allows console in packages/evals; repo check compiles packages/evals.
    • Docs: replaced stagehand-v4 with stagehand in v4 install and AI‑rules examples.
  • Migration

    • Remove any extra/typo keys in request bodies and options; only documented fields are allowed.
    • Do not include stale locator handles (page, frame, element) in PageLocator.
    • LLM generate results must only include defined fields; extra metadata is rejected.
    • Runtime descriptors must only include documented fields (protocolVersion, serverInfo, status).

Written for commit dbea4f1. Summary will update on new commits.

Review in cubic

@changeset-bot

changeset-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: dbea4f1

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

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 10 files

Architecture diagram
sequenceDiagram
    participant Client
    participant ClientSDK as Client SDK (TypeScript)
    participant Protocol as Protocol Schemas (z.strictObject)
    participant JSONSchema as JSON Schema Validation (Python)
    participant Server as Stagehand Server
    participant LLMProvider as LLM Provider
    participant Runtime as Browser Runtime

    Note over Client,Server: RPC Call Flow (e.g., stagehandAct)

    Client->>ClientSDK: act(input, options)
    ClientSDK->>ClientSDK: Merge with client-specific options (page)
    ClientSDK->>Protocol: parse(StagehandClientActOptionsSchema) -> NEW: strict object rejects unknown keys
    alt Extra field (e.g., "tiemout")
        Protocol-->>ClientSDK: ZodError: unknown field
        ClientSDK-->>Client: throw validation error
    else Known fields
        Protocol-->>ClientSDK: validated options
        ClientSDK->>Server: JSON-RPC request with validated params
        Server->>Protocol: parse(StagehandActParamsSchema) -> NEW: strict object rejects unknown keys
        alt Extra field in options
            Protocol-->>Server: ZodError
            Server-->>ClientSDK: JSON-RPC error response
        else Valid
            Protocol-->>Server: parsed params
            Server->>LLMProvider: generate() with parsed messages/tools
            Note over LLMProvider: LLMGenerateResult schema now rejects extra fields (e.g., providerMetadata)
            LLMProvider-->>Server: LLM generate result
            Server->>Protocol: parse(LLMGenerateResultSchema) -> NEW: strict object, no .catchall()
            alt Contains unknown keys (e.g., providerMetadata)
                Protocol-->>Server: rejection
                Server-->>ClientSDK: error
            else Valid
                Protocol-->>Server: parsed result
                Server-->>ClientSDK: success response
            end
        end
    end

    Note over Runtime,Protocol: Runtime Descriptor Negotiation

    Server->>Runtime: evaluate("__stagehand_runtimeMarker")
    Runtime-->>Server: descriptor object
    Server->>Protocol: parse(RuntimeDescriptorSchema) -> NEW: strict, rejects unknown fields (e.g., "status")
    alt Unknown field present
        Protocol-->>Server: rejection
        Server-->>ClientSDK: unreadable marker -> negotiation fails
    else Known fields only
        Protocol-->>Server: parsed descriptor
        Server-->>ClientSDK: compatible marker
    end

    Note over Client,Server: PageLocator serialization

    ClientSDK->>Protocol: serialize(PageLocatorSchema) -> NEW: strict, rejects stale handles (page, frame, element)
    alt Contains stale handle
        Protocol-->>ClientSDK: error
    else Valid
        Protocol-->>ClientSDK: strict PageLocator
        ClientSDK->>Server: locator in request
    end

    Note over JSONSchema,Python: Python SDK disallows extras

    Client->>JSONSchema: parse with Pydantic (extra="forbid") -> NEW: rejects unknown fields at runtime
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/protocol/stagehand.v4.json
Comment thread packages/protocol/schemas.ts
@monadoid
monadoid force-pushed the simplify-acknowledgement-results branch from 169d61b to e1ed7c8 Compare July 27, 2026 15:34
@monadoid
monadoid force-pushed the use-strict-object branch from 8a390fb to 5f683c0 Compare July 27, 2026 15:34
@monadoid
monadoid force-pushed the simplify-acknowledgement-results branch from e1ed7c8 to dab7665 Compare July 27, 2026 15:35
@monadoid
monadoid force-pushed the use-strict-object branch from 5f683c0 to ad27e80 Compare July 27, 2026 15:35
@monadoid
monadoid force-pushed the use-strict-object branch from ad27e80 to dbea4f1 Compare July 28, 2026 11:03
@monadoid
monadoid requested a review from a team as a code owner July 28, 2026 11:03
@monadoid
monadoid changed the base branch from simplify-acknowledgement-results to v4-spike July 28, 2026 11:04
@monadoid
monadoid merged commit db7dccb into v4-spike Jul 28, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants