[STG-1756] forward Vertex model config - #2160
Conversation
🦋 Changeset detectedLatest commit: e1515c5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
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 |
✱ Stainless preview builds for stagehandThis PR will update the ✅ stagehand-go studio · code
|
There was a problem hiding this comment.
2 issues found across 15 files
Confidence score: 3/5
- There is a concrete regression risk in
packages/core/lib/v3/api.ts:goto()does not route per-callmodelthroughprepareModelConfig(), so string models may behave differently thanact/extract/observeand lead to incorrect model resolution at runtime. packages/server-v3/src/lib/header.tshas a medium-severity precedence issue wherebody.modelNamecan leak into requests even when an objectoptions.model/agentConfig.modelis intended to be authoritative, which can cause unintended model selection.- Given the 6–7/10 severity and reasonably high confidence, this is a moderate user-impact risk rather than a merge-blocking failure; merge is possible, but a targeted fix would materially reduce regression chance.
- Pay close attention to
packages/core/lib/v3/api.tsandpackages/server-v3/src/lib/header.ts- model normalization and fallback precedence can silently select the wrong model.
Architecture diagram
sequenceDiagram
participant C as Client App
participant V3 as V3 Core (v3.ts)
participant APIClient as StagehandAPIClient (api.ts)
participant Server as Server-v3 (Fastify)
participant SessionStore as InMemorySessionStore
participant Browser
Note over C,Browser: Constructor Model Config Forwarding (Happy Path)
C->>V3: new Stagehand({ modelName, modelClientOptions... })
V3->>V3: store modelName + clientOptions
C->>V3: stagehand.init()
V3->>APIClient: init({ modelName, modelApiKey, defaultModelConfig })
Note over APIClient: defaultModelConfig = merged modelName + clientOptions
APIClient->>APIClient: store defaultModelConfig internally
C->>V3: stagehand.navigate(url, options?)
V3->>APIClient: goto(url, options)
alt options.model provided per-call
APIClient->>APIClient: use options.model (prepared)
else no per-call model AND defaultModelConfig exists
APIClient->>APIClient: use getDefaultModelConfig()
end
APIClient->>Server: POST /navigate { url, options.model }
Server->>Server: getRequestModelConfig(body)
Note over Server: parse body.options.model or body.agentConfig.model
Server->>Server: delete options.model before page.goto
alt session not yet started
Server->>SessionStore: getOrCreateStagehand(sessionId, requestModelConfig)
SessionStore->>SessionStore: create V3Options from requestModelConfig + modelApiKey fallback
SessionStore-->>Server: stagehand instance
end
Server->>Browser: page.goto(url, strippedOptions)
Browser-->>Server: navigation result
Server-->>APIClient: response
APIClient-->>V3: result
V3-->>C: result
Note over C,Browser: Act/Extract/Observe (same pattern)
C->>V3: stagehand.act({ input, options? })
V3->>APIClient: act({ input, options })
alt options.model provided per-call
APIClient->>APIClient: use options.model (prepared)
else no per-call model AND defaultModelConfig exists
APIClient->>APIClient: use getDefaultModelConfig()
end
APIClient->>Server: POST /act { options.model }
Server->>Server: getRequestModelConfig(body) — extracts model config
Server-->>APIClient: response
APIClient-->>V3: result
V3-->>C: result
Note over C,Browser: Agent Execute (same pattern)
C->>V3: stagehand.agentExecute(agentConfig, input)
V3->>APIClient: agentExecute(agentConfig, input)
alt agentConfig.model provided
APIClient->>APIClient: prepareModelConfig(agentConfig.model)
else no model AND defaultModelConfig exists
APIClient->>APIClient: use getDefaultModelConfig()
end
APIClient->>Server: POST /agentExecute { agentConfig.model }
Server->>Server: getRequestModelConfig(body) — extracts from agentConfig.model
Server-->>APIClient: response
APIClient-->>V3: result
V3-->>C: result
Note over C,Browser: Session Start Flow (Local Server)
C->>Server: POST /sessions/start { modelName }
Server->>Server: getRequestModelConfig(body)
alt body has options.model or agentConfig.model
Server->>Server: extract model config (including Vertex auth fields)
else modelName only
Server->>Server: use modelName + x-model-api-key header fallback
end
Server->>SessionStore: createSession({ modelName, requestModelConfig })
SessionStore->>SessionStore: set ctx.requestModelConfig
SessionStore->>SessionStore: create V3Options from ctx.requestModelConfig + modelApiKey
Server-->>C: session created
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
There was a problem hiding this comment.
No issues found across 12 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant ClientApp as Client Application
participant V3 as V3 Instance
participant APIClient as StagehandAPIClient
participant Fetch as HTTP Client
participant Server as Server-v3
participant SessionStore as InMemorySessionStore
participant LLM as LLMProvider
participant Browser as Browser
Note over ClientApp,Browser: Constructor Model Config Forwarding Flow
ClientApp->>V3: new V3({ modelName: "vertex/...", modelClientOptions: { project, location, googleAuthOptions } })
ClientApp->>V3: init()
V3->>V3: getApiDefaultModelConfig()
V3->>APIClient: init({ modelName, modelApiKey, defaultModelConfig: { modelName, project, location, googleAuthOptions } })
APIClient->>APIClient: store defaultModelConfig
alt navigate(url) called
APIClient->>APIClient: strip model from publicOptions
APIClient->>APIClient: getDefaultModelConfig() → Vertex config
APIClient->>Fetch: POST /navigate { url, options: { model: Vertex config } }
Fetch->>Server: Forward request
Server->>Server: getRequestModelConfig() → parse body.options.model
alt has model config
Server->>SessionStore: bootstrap session with { modelName, project, location, googleAuthOptions }
SessionStore->>LLM: getClient(Vertex model)
SessionStore->>Browser: page.goto(url) – model stripped
else fallback to header
Server->>SessionStore: bootstrap with { modelName, apiKey: x-model-api-key }
end
end
alt act/observe/extract() called
alt per-call model provided
APIClient->>APIClient: prepareModelConfig(per-call model)
APIClient->>Fetch: POST /{act|observe|extract} { options: { model: per-call } }
else no per-call model
APIClient->>APIClient: getDefaultModelConfig() → use constructor config
APIClient->>Fetch: POST /{act|observe|extract} { options: { model: constructor Vertex config } }
end
Fetch->>Server: Forward with model config
Server->>SessionStore: Use request model config for LLM calls
end
alt agentExecute() called
alt agentConfig.model provided
APIClient->>APIClient: prepareModelConfig(agentConfig.model)
else no agentConfig.model
APIClient->>APIClient: getDefaultModelConfig() → use constructor config
end
APIClient->>Fetch: POST /agentExecute { agentConfig: { model: resolved config } }
Fetch->>Server: Forward
end
Note over LLM: No longer throws ExperimentalNotConfiguredError for Vertex<br>Vertex models work without experimental mode
alt constructor provides only modelApiKey (no modelClientOptions)
V3->>V3: getApiDefaultModelConfig() → undefined
APIClient->>APIClient: defaultModelConfig is undefined
APIClient->>Fetch: No model in body, only x-model-api-key header
Server->>SessionStore: bootstrap with { modelName, apiKey: x-model-api-key }
end
There was a problem hiding this comment.
2 issues found across 10 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/server-v3/src/routes/v1/sessions/start.ts">
<violation number="1" location="packages/server-v3/src/routes/v1/sessions/start.ts:218">
P1: Session leak: if model config validation fails here, the session created by `startSession()` above is never cleaned up. Add `await sessionStore.endSession(session.sessionId)` before returning the 400, similar to the error handling in the `catch` block below.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @browserbasehq/stagehand@3.5.0 ### Minor Changes - [#2149](#2149) [`6e75725`](6e75725) Thanks [@miguelg719](https://github.com/miguelg719)! - Added a `screenshot` option to `extract()` that sends the current viewport screenshot with the a11y tree for extraction. - [#2127](#2127) [`78bcde8`](78bcde8) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Add `ignoreDefaultArgs` option to selectively remove chrome-launcher's built-in default flags (e.g. `--disable-extensions`) when running locally - [#2160](#2160) [`49575d6`](49575d6) Thanks [@monadoid](https://github.com/monadoid)! - Forward constructor and request model configuration when initializing API-backed sessions. - [#2171](#2171) [`dc1445d`](dc1445d) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add native clipboard API ### Patch Changes - [#2146](#2146) [`3a53ed4`](3a53ed4) Thanks [@shriyatheunicorn](https://github.com/shriyatheunicorn)! - Pass local browser launch options through when attaching over CDP so explicit viewport settings are respected. - [#2107](#2107) [`8fc16d2`](8fc16d2) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix Anthropic CUA `triple_click` action mapping. - [#2118](#2118) [`3e95a87`](3e95a87) Thanks [@monadoid](https://github.com/monadoid)! - Add Vertex auth parameters to the core and server API schemas. - [#2126](#2126) [`ebbdcd3`](ebbdcd3) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix(core): import ToolSet from ai public export - [#2120](#2120) [`12703a6`](12703a6) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix structuredOutputMode for newer Anthropic models - [#2170](#2170) [`1db5f1c`](1db5f1c) Thanks [@Kylejeong2](https://github.com/Kylejeong2)! - Add Claude Opus 4.8 to the supported CUA model whitelist. - [#2116](#2116) [`cb586a1`](cb586a1) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - include "[selected]" or "[checked]" state in snapshot - [#2129](#2129) [`765861c`](765861c) Thanks [@miguelg719](https://github.com/miguelg719)! - Add a backend-selectable v3 evaluator facade while preserving the legacy evaluator path. - [#2157](#2157) [`2cd60a3`](2cd60a3) Thanks [@miguelg719](https://github.com/miguelg719)! - Add verifier trajectory, rubric, and evaluation-result types with normalized public naming. - [#2131](#2131) [`e102a89`](e102a89) Thanks [@miguelg719](https://github.com/miguelg719)! - Capture verifier trajectory evidence from agent evidence callbacks for offline scoring. ## @browserbasehq/browse-cli@0.6.1 ### Patch Changes - Updated dependencies \[[`3a53ed4`](3a53ed4), [`6e75725`](6e75725), [`8fc16d2`](8fc16d2), [`78bcde8`](78bcde8), [`3e95a87`](3e95a87), [`ebbdcd3`](ebbdcd3), [`12703a6`](12703a6), [`1db5f1c`](1db5f1c), [`cb586a1`](cb586a1), [`765861c`](765861c), [`2cd60a3`](2cd60a3), [`e102a89`](e102a89), [`49575d6`](49575d6), [`dc1445d`](dc1445d)]: - @browserbasehq/stagehand@3.5.0 ## @browserbasehq/stagehand-server-v3@3.7.0 ### Minor Changes - [#2160](#2160) [`49575d6`](49575d6) Thanks [@monadoid](https://github.com/monadoid)! - Forward constructor and request model configuration when initializing API-backed sessions. ### Patch Changes - [#2118](#2118) [`3e95a87`](3e95a87) Thanks [@monadoid](https://github.com/monadoid)! - Add Vertex auth parameters to the core and server API schemas. - [#2167](#2167) [`ce21468`](ce21468) Thanks [@monadoid](https://github.com/monadoid)! - Add SEA binary --version build metadata output. - Updated dependencies \[[`3a53ed4`](3a53ed4), [`6e75725`](6e75725), [`8fc16d2`](8fc16d2), [`78bcde8`](78bcde8), [`3e95a87`](3e95a87), [`ebbdcd3`](ebbdcd3), [`12703a6`](12703a6), [`1db5f1c`](1db5f1c), [`cb586a1`](cb586a1), [`765861c`](765861c), [`2cd60a3`](2cd60a3), [`e102a89`](e102a89), [`49575d6`](49575d6), [`dc1445d`](dc1445d)]: - @browserbasehq/stagehand@3.5.0 ## @browserbasehq/stagehand-evals@2.0.2 ### Patch Changes - Updated dependencies \[[`3a53ed4`](3a53ed4), [`6e75725`](6e75725), [`8fc16d2`](8fc16d2), [`78bcde8`](78bcde8), [`3e95a87`](3e95a87), [`ebbdcd3`](ebbdcd3), [`12703a6`](12703a6), [`1db5f1c`](1db5f1c), [`cb586a1`](cb586a1), [`765861c`](765861c), [`2cd60a3`](2cd60a3), [`e102a89`](e102a89), [`49575d6`](49575d6), [`dc1445d`](dc1445d)]: - @browserbasehq/stagehand@3.5.0 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Why Vertex model credentials need a typed public shape and must be forwarded from the TypeScript client to API-backed Stagehand requests without persisting secrets server-side. ## What changed - Define a canonical Vertex model config shape using `provider: "vertex"`, `auth`, and `providerOptions.vertex`, while preserving existing generic model string/object support. - Forward constructor model config through API-backed act/observe/extract/agentExecute requests, with per-call model config still taking precedence. - Keep navigate/goto from exposing a public per-call model option, while still allowing constructor config to bootstrap API-backed sessions internally. - Sync server-v3 request parsing with the hosted API approach: Zod-first safe parsing, separate request model config from Stagehand init model config, and clean SSE validation errors. - Regenerate server-v3 OpenAPI from the Stagehand Zod source so Stainless can pick up the canonical shape. TODO before final hosted API merge: swap core to the Orca build produced from this Stagehand change. ---------
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @browserbasehq/stagehand@3.5.0 ### Minor Changes - [browserbase#2149](browserbase#2149) [`6e75725`](browserbase@6e75725) Thanks [@miguelg719](https://github.com/miguelg719)! - Added a `screenshot` option to `extract()` that sends the current viewport screenshot with the a11y tree for extraction. - [browserbase#2127](browserbase#2127) [`78bcde8`](browserbase@78bcde8) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Add `ignoreDefaultArgs` option to selectively remove chrome-launcher's built-in default flags (e.g. `--disable-extensions`) when running locally - [browserbase#2160](browserbase#2160) [`49575d6`](browserbase@49575d6) Thanks [@monadoid](https://github.com/monadoid)! - Forward constructor and request model configuration when initializing API-backed sessions. - [browserbase#2171](browserbase#2171) [`dc1445d`](browserbase@dc1445d) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add native clipboard API ### Patch Changes - [browserbase#2146](browserbase#2146) [`3a53ed4`](browserbase@3a53ed4) Thanks [@shriyatheunicorn](https://github.com/shriyatheunicorn)! - Pass local browser launch options through when attaching over CDP so explicit viewport settings are respected. - [browserbase#2107](browserbase#2107) [`8fc16d2`](browserbase@8fc16d2) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix Anthropic CUA `triple_click` action mapping. - [browserbase#2118](browserbase#2118) [`3e95a87`](browserbase@3e95a87) Thanks [@monadoid](https://github.com/monadoid)! - Add Vertex auth parameters to the core and server API schemas. - [browserbase#2126](browserbase#2126) [`ebbdcd3`](browserbase@ebbdcd3) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix(core): import ToolSet from ai public export - [browserbase#2120](browserbase#2120) [`12703a6`](browserbase@12703a6) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix structuredOutputMode for newer Anthropic models - [browserbase#2170](browserbase#2170) [`1db5f1c`](browserbase@1db5f1c) Thanks [@Kylejeong2](https://github.com/Kylejeong2)! - Add Claude Opus 4.8 to the supported CUA model whitelist. - [browserbase#2116](browserbase#2116) [`cb586a1`](browserbase@cb586a1) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - include "[selected]" or "[checked]" state in snapshot - [browserbase#2129](browserbase#2129) [`765861c`](browserbase@765861c) Thanks [@miguelg719](https://github.com/miguelg719)! - Add a backend-selectable v3 evaluator facade while preserving the legacy evaluator path. - [browserbase#2157](browserbase#2157) [`2cd60a3`](browserbase@2cd60a3) Thanks [@miguelg719](https://github.com/miguelg719)! - Add verifier trajectory, rubric, and evaluation-result types with normalized public naming. - [browserbase#2131](browserbase#2131) [`e102a89`](browserbase@e102a89) Thanks [@miguelg719](https://github.com/miguelg719)! - Capture verifier trajectory evidence from agent evidence callbacks for offline scoring. ## @browserbasehq/browse-cli@0.6.1 ### Patch Changes - Updated dependencies \[[`3a53ed4`](browserbase@3a53ed4), [`6e75725`](browserbase@6e75725), [`8fc16d2`](browserbase@8fc16d2), [`78bcde8`](browserbase@78bcde8), [`3e95a87`](browserbase@3e95a87), [`ebbdcd3`](browserbase@ebbdcd3), [`12703a6`](browserbase@12703a6), [`1db5f1c`](browserbase@1db5f1c), [`cb586a1`](browserbase@cb586a1), [`765861c`](browserbase@765861c), [`2cd60a3`](browserbase@2cd60a3), [`e102a89`](browserbase@e102a89), [`49575d6`](browserbase@49575d6), [`dc1445d`](browserbase@dc1445d)]: - @browserbasehq/stagehand@3.5.0 ## @browserbasehq/stagehand-server-v3@3.7.0 ### Minor Changes - [browserbase#2160](browserbase#2160) [`49575d6`](browserbase@49575d6) Thanks [@monadoid](https://github.com/monadoid)! - Forward constructor and request model configuration when initializing API-backed sessions. ### Patch Changes - [browserbase#2118](browserbase#2118) [`3e95a87`](browserbase@3e95a87) Thanks [@monadoid](https://github.com/monadoid)! - Add Vertex auth parameters to the core and server API schemas. - [browserbase#2167](browserbase#2167) [`ce21468`](browserbase@ce21468) Thanks [@monadoid](https://github.com/monadoid)! - Add SEA binary --version build metadata output. - Updated dependencies \[[`3a53ed4`](browserbase@3a53ed4), [`6e75725`](browserbase@6e75725), [`8fc16d2`](browserbase@8fc16d2), [`78bcde8`](browserbase@78bcde8), [`3e95a87`](browserbase@3e95a87), [`ebbdcd3`](browserbase@ebbdcd3), [`12703a6`](browserbase@12703a6), [`1db5f1c`](browserbase@1db5f1c), [`cb586a1`](browserbase@cb586a1), [`765861c`](browserbase@765861c), [`2cd60a3`](browserbase@2cd60a3), [`e102a89`](browserbase@e102a89), [`49575d6`](browserbase@49575d6), [`dc1445d`](browserbase@dc1445d)]: - @browserbasehq/stagehand@3.5.0 ## @browserbasehq/stagehand-evals@2.0.2 ### Patch Changes - Updated dependencies \[[`3a53ed4`](browserbase@3a53ed4), [`6e75725`](browserbase@6e75725), [`8fc16d2`](browserbase@8fc16d2), [`78bcde8`](browserbase@78bcde8), [`3e95a87`](browserbase@3e95a87), [`ebbdcd3`](browserbase@ebbdcd3), [`12703a6`](browserbase@12703a6), [`1db5f1c`](browserbase@1db5f1c), [`cb586a1`](browserbase@cb586a1), [`765861c`](browserbase@765861c), [`2cd60a3`](browserbase@2cd60a3), [`e102a89`](browserbase@e102a89), [`49575d6`](browserbase@49575d6), [`dc1445d`](browserbase@dc1445d)]: - @browserbasehq/stagehand@3.5.0
Why
Vertex model credentials need a typed public shape and must be forwarded from the TypeScript client to API-backed Stagehand requests without persisting secrets server-side.
What changed
provider: "vertex",auth, andproviderOptions.vertex, while preserving existing generic model string/object support.TODO before final hosted API merge: swap core to the Orca build produced from this Stagehand change.