Skip to content

fix(v3): set additionalProperties false on nullable act action schema - #3150

Open
miguelg719 wants to merge 2 commits into
v3from
miguelgonzalez/v3-act-schema-additional-properties
Open

miguelg719 wants to merge 2 commits into
v3from
miguelgonzalez/v3-act-schema-additional-properties

Conversation

@miguelg719

@miguelg719 miguelg719 commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Why

act fails on OpenAI models routed through the AI SDK client (for example openai/gpt-4.1-nano) with:

Invalid schema for response_format 'response': In context=('properties', 'action', 'anyOf', '0'),
'additionalProperties' is required to be supplied and to be false.

AISdkClient sends OpenAI requests with strictJsonSchema: true, and OpenAI strict mode requires additionalProperties: false on every object. generateObject converts the Zod schema with the AI SDK's own converter, which leaves that field off the object inside the nullable action's anyOf. The direct provider clients use toJsonSchema and already emit it.

This is what fails server/v3/integration/v3/act and server/v3/integration/v3/agentExecute (the variables tests return an empty field because the agent's act tool call 400s). See #3114.

What changed

  • Mark the action object with .meta({ additionalProperties: false }) when running on Zod 4. zod is a peer dependency (^3.25 || ^4) and Zod 3 has no .meta(); its converter already emits the field, so the call is skipped there. This changes only the generated JSON schema. Parsing still strips unknown keys, so clients that validate locally (Google, AI SDK providers without strict mode, custom clients) keep accepting responses with extra fields. .strict() was considered and rejected because it would make those responses fail validation.
  • Unit tests check both converters, that parsing still strips unknown keys, and that act() builds its schema under a Zod 3 peer.

Test plan

  • New act-response-schema unit tests pass; the AI SDK converter test fails without the fix.
  • act-response-schema-zod3 (mocks zod with zod/v3) passes; without the guard it fails with actionSchema.meta is not a function.
  • inference-temperature unit tests pass.
  • Live generateObject call with @ai-sdk/openai gpt-4.1-nano and strictJsonSchema: true: without the fix it returns the 400 above; with the fix it returns a valid action.
  • ESLint and Prettier clean.

Summary by cubic

Fixes act calls failing on OpenAI models routed through the AI SDK client. OpenAI strict mode requires additionalProperties: false on every object, and the AI SDK schema converter omitted it inside the nullable action's anyOf, producing an invalid_json_schema 400.

  • Sets additionalProperties: false via .meta() so only the generated JSON schema changes; parsing still strips unknown keys, so clients that validate locally keep accepting responses with extra fields.
  • Calls .meta() only under Zod 4 since zod is a peer dependency (^3.25 || ^4) and its Zod 3 import lacks the method; the Zod 3 converter already emits the field.
  • Adds unit tests for the AI SDK and toJsonSchema converters, including the Zod 3 path.

Written for commit 8c3658a. Summary will update on new commits.

View guided diff Turn on auto-fix

OpenAI strict structured outputs require additionalProperties: false on
every object. The AI SDK converter used by generateObject omits it for the
object inside the nullable action's anyOf, so act requests through AI SDK
OpenAI models fail with invalid_json_schema. Set it via .meta() so only the
JSON schema changes; parsing still strips unknown keys.
@changeset-bot

changeset-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8c3658a

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-v3 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

@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 3 files

Architecture diagram
sequenceDiagram
    participant C as Client
    participant A as act() (inference.ts)
    participant S as Zod Schema
    participant AI as AI SDK converter
    participant O as OpenAI API

    Note over C,O: Act Tool Schema Generation Flow

    C->>A: call act() with instruction
    A->>A: Build Zod schema with nullable action

    A->>S: Apply .meta() with additionalProperties: false
    Note over A,S: Only affects JSON schema output,<br/>not runtime parsing

    alt AI SDK client (strictJsonSchema: true)
        A->>AI: Convert schema
        AI->>S: Generate JSON schema
        S-->>AI: Schema with additionalProperties: false
        AI->>O: Send request
        Note over O: OpenAI validates schema
        alt Valid schema
            O-->>AI: 200 OK with generated content
            AI->>A: Return content
            A->>A: Parse with original Zod schema
            Note over A: Parsing strips unknown keys<br/>(does not reject them)
            A-->>C: Return parsed action
        end
    else Direct provider client
        A->>S: Convert with toJsonSchema
        S-->>A: Schema with additionalProperties: false
        Note over A: Schema already includes the flag
    end
Loading

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

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/core/lib/inference.ts Outdated
zod is a peer dependency (^3.25 || ^4). Under Zod 3 the root import has no
.meta(), so act() threw while building its schema. The Zod 3 converter
already emits additionalProperties: false, so skip .meta() there.

This branch has not been deployed

No deployments
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.

1 participant