Skip to content

Commit b37b827

Browse files
feat: [STG-1756] forward Vertex model config
1 parent 043d138 commit b37b827

15 files changed

Lines changed: 21343 additions & 2165 deletions

File tree

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 8
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-80502d74c1be605e77d45ff2b54297fe34ce85dbad1e8f2dfa30ba6d09601219.yml
3-
openapi_spec_hash: fd62f768756a400c3ecd695bfcf3845a
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-c7910965e66e73ad8b65b6cc391d431094b2a6c6577c3e9d82feaa8138e74cff.yml
3+
openapi_spec_hash: 37748bb69c22a9ce721d9b5a5861f964
44
config_hash: 1fb12ae9b478488bc1e56bfbdc210b01

stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt

Lines changed: 2553 additions & 1229 deletions
Large diffs are not rendered by default.

stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt

Lines changed: 3246 additions & 21 deletions
Large diffs are not rendered by default.

stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt

Lines changed: 6746 additions & 300 deletions
Large diffs are not rendered by default.

stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt

Lines changed: 3247 additions & 21 deletions
Large diffs are not rendered by default.

stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt

Lines changed: 3247 additions & 21 deletions
Large diffs are not rendered by default.

stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt

Lines changed: 148 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,24 @@ package com.browserbase.api.models.sessions
44

55
import com.browserbase.api.core.JsonValue
66
import com.browserbase.api.core.jsonMapper
7+
import com.browserbase.api.errors.StagehandInvalidDataException
78
import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
89
import org.assertj.core.api.Assertions.assertThat
910
import org.junit.jupiter.api.Test
11+
import org.junit.jupiter.api.assertThrows
12+
import org.junit.jupiter.params.ParameterizedTest
13+
import org.junit.jupiter.params.provider.EnumSource
1014

1115
internal class ModelConfigTest {
1216

1317
@Test
14-
fun create() {
15-
val modelConfig =
16-
ModelConfig.builder()
17-
.modelName("openai/gpt-5.4-mini")
18-
.apiKey("sk-some-openai-api-key")
19-
.baseUrl("https://api.openai.com/v1")
20-
.googleAuthOptions(
21-
ModelConfig.GoogleAuthOptions.builder()
18+
fun ofVertexModelConfigObject() {
19+
val vertexModelConfigObject =
20+
ModelConfig.VertexModelConfigObject.builder()
21+
.auth(
22+
ModelConfig.VertexModelConfigObject.Auth.builder()
2223
.credentials(
23-
ModelConfig.GoogleAuthOptions.Credentials.builder()
24+
ModelConfig.VertexModelConfigObject.Auth.Credentials.builder()
2425
.clientEmail("client_email")
2526
.privateKey("private_key")
2627
.authProviderX509CertUrl("https://example.com")
@@ -31,7 +32,8 @@ internal class ModelConfigTest {
3132
.projectId("project_id")
3233
.tokenUri("https://example.com")
3334
.type(
34-
ModelConfig.GoogleAuthOptions.Credentials.Type.SERVICE_ACCOUNT
35+
ModelConfig.VertexModelConfigObject.Auth.Credentials.Type
36+
.SERVICE_ACCOUNT
3537
)
3638
.universeDomain("universe_domain")
3739
.build()
@@ -41,95 +43,148 @@ internal class ModelConfigTest {
4143
.universeDomain("universeDomain")
4244
.build()
4345
)
46+
.modelName("openai/gpt-5.4-mini")
47+
.providerOptions(
48+
ModelConfig.VertexModelConfigObject.ProviderOptions.builder()
49+
.vertex(
50+
ModelConfig.VertexModelConfigObject.ProviderOptions.Vertex.builder()
51+
.location("us-central1")
52+
.project("my-gcp-project")
53+
.baseUrl("https://example.com")
54+
.headers(
55+
ModelConfig.VertexModelConfigObject.ProviderOptions.Vertex
56+
.Headers
57+
.builder()
58+
.putAdditionalProperty("foo", JsonValue.from("string"))
59+
.build()
60+
)
61+
.build()
62+
)
63+
.build()
64+
)
65+
.apiKey("sk-some-openai-api-key")
66+
.baseUrl("https://api.openai.com/v1")
4467
.headers(
45-
ModelConfig.Headers.builder()
68+
ModelConfig.VertexModelConfigObject.Headers.builder()
4669
.putAdditionalProperty("foo", JsonValue.from("string"))
4770
.build()
4871
)
49-
.location("us-central1")
50-
.project("my-gcp-project")
51-
.provider(ModelConfig.Provider.OPENAI)
5272
.build()
5373

54-
assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5.4-mini")
55-
assertThat(modelConfig.apiKey()).contains("sk-some-openai-api-key")
56-
assertThat(modelConfig.baseUrl()).contains("https://api.openai.com/v1")
57-
assertThat(modelConfig.googleAuthOptions())
58-
.contains(
59-
ModelConfig.GoogleAuthOptions.builder()
60-
.credentials(
61-
ModelConfig.GoogleAuthOptions.Credentials.builder()
62-
.clientEmail("client_email")
63-
.privateKey("private_key")
64-
.authProviderX509CertUrl("https://example.com")
65-
.authUri("https://example.com")
66-
.clientId("client_id")
67-
.clientX509CertUrl("https://example.com")
68-
.privateKeyId("private_key_id")
69-
.projectId("project_id")
70-
.tokenUri("https://example.com")
71-
.type(ModelConfig.GoogleAuthOptions.Credentials.Type.SERVICE_ACCOUNT)
72-
.universeDomain("universe_domain")
74+
val modelConfig = ModelConfig.ofVertexModelConfigObject(vertexModelConfigObject)
75+
76+
assertThat(modelConfig.vertexModelConfigObject()).contains(vertexModelConfigObject)
77+
assertThat(modelConfig.genericModelConfigObject()).isEmpty
78+
}
79+
80+
@Test
81+
fun ofVertexModelConfigObjectRoundtrip() {
82+
val jsonMapper = jsonMapper()
83+
val modelConfig =
84+
ModelConfig.ofVertexModelConfigObject(
85+
ModelConfig.VertexModelConfigObject.builder()
86+
.auth(
87+
ModelConfig.VertexModelConfigObject.Auth.builder()
88+
.credentials(
89+
ModelConfig.VertexModelConfigObject.Auth.Credentials.builder()
90+
.clientEmail("client_email")
91+
.privateKey("private_key")
92+
.authProviderX509CertUrl("https://example.com")
93+
.authUri("https://example.com")
94+
.clientId("client_id")
95+
.clientX509CertUrl("https://example.com")
96+
.privateKeyId("private_key_id")
97+
.projectId("project_id")
98+
.tokenUri("https://example.com")
99+
.type(
100+
ModelConfig.VertexModelConfigObject.Auth.Credentials.Type
101+
.SERVICE_ACCOUNT
102+
)
103+
.universeDomain("universe_domain")
104+
.build()
105+
)
106+
.projectId("projectId")
107+
.scopes("string")
108+
.universeDomain("universeDomain")
109+
.build()
110+
)
111+
.modelName("openai/gpt-5.4-mini")
112+
.providerOptions(
113+
ModelConfig.VertexModelConfigObject.ProviderOptions.builder()
114+
.vertex(
115+
ModelConfig.VertexModelConfigObject.ProviderOptions.Vertex.builder()
116+
.location("us-central1")
117+
.project("my-gcp-project")
118+
.baseUrl("https://example.com")
119+
.headers(
120+
ModelConfig.VertexModelConfigObject.ProviderOptions.Vertex
121+
.Headers
122+
.builder()
123+
.putAdditionalProperty("foo", JsonValue.from("string"))
124+
.build()
125+
)
126+
.build()
127+
)
128+
.build()
129+
)
130+
.apiKey("sk-some-openai-api-key")
131+
.baseUrl("https://api.openai.com/v1")
132+
.headers(
133+
ModelConfig.VertexModelConfigObject.Headers.builder()
134+
.putAdditionalProperty("foo", JsonValue.from("string"))
73135
.build()
74136
)
75-
.projectId("projectId")
76-
.scopes("string")
77-
.universeDomain("universeDomain")
78137
.build()
79138
)
80-
assertThat(modelConfig.headers())
81-
.contains(
82-
ModelConfig.Headers.builder()
83-
.putAdditionalProperty("foo", JsonValue.from("string"))
84-
.build()
139+
140+
val roundtrippedModelConfig =
141+
jsonMapper.readValue(
142+
jsonMapper.writeValueAsString(modelConfig),
143+
jacksonTypeRef<ModelConfig>(),
85144
)
86-
assertThat(modelConfig.location()).contains("us-central1")
87-
assertThat(modelConfig.project()).contains("my-gcp-project")
88-
assertThat(modelConfig.provider()).contains(ModelConfig.Provider.OPENAI)
145+
146+
assertThat(roundtrippedModelConfig).isEqualTo(modelConfig)
89147
}
90148

91149
@Test
92-
fun roundtrip() {
93-
val jsonMapper = jsonMapper()
94-
val modelConfig =
95-
ModelConfig.builder()
150+
fun ofGenericModelConfigObject() {
151+
val genericModelConfigObject =
152+
ModelConfig.GenericModelConfigObject.builder()
96153
.modelName("openai/gpt-5.4-mini")
97154
.apiKey("sk-some-openai-api-key")
98155
.baseUrl("https://api.openai.com/v1")
99-
.googleAuthOptions(
100-
ModelConfig.GoogleAuthOptions.builder()
101-
.credentials(
102-
ModelConfig.GoogleAuthOptions.Credentials.builder()
103-
.clientEmail("client_email")
104-
.privateKey("private_key")
105-
.authProviderX509CertUrl("https://example.com")
106-
.authUri("https://example.com")
107-
.clientId("client_id")
108-
.clientX509CertUrl("https://example.com")
109-
.privateKeyId("private_key_id")
110-
.projectId("project_id")
111-
.tokenUri("https://example.com")
112-
.type(
113-
ModelConfig.GoogleAuthOptions.Credentials.Type.SERVICE_ACCOUNT
114-
)
115-
.universeDomain("universe_domain")
116-
.build()
117-
)
118-
.projectId("projectId")
119-
.scopes("string")
120-
.universeDomain("universeDomain")
121-
.build()
122-
)
123156
.headers(
124-
ModelConfig.Headers.builder()
157+
ModelConfig.GenericModelConfigObject.Headers.builder()
125158
.putAdditionalProperty("foo", JsonValue.from("string"))
126159
.build()
127160
)
128-
.location("us-central1")
129-
.project("my-gcp-project")
130-
.provider(ModelConfig.Provider.OPENAI)
161+
.provider(ModelConfig.GenericModelConfigObject.Provider.OPENAI)
131162
.build()
132163

164+
val modelConfig = ModelConfig.ofGenericModelConfigObject(genericModelConfigObject)
165+
166+
assertThat(modelConfig.vertexModelConfigObject()).isEmpty
167+
assertThat(modelConfig.genericModelConfigObject()).contains(genericModelConfigObject)
168+
}
169+
170+
@Test
171+
fun ofGenericModelConfigObjectRoundtrip() {
172+
val jsonMapper = jsonMapper()
173+
val modelConfig =
174+
ModelConfig.ofGenericModelConfigObject(
175+
ModelConfig.GenericModelConfigObject.builder()
176+
.modelName("openai/gpt-5.4-mini")
177+
.apiKey("sk-some-openai-api-key")
178+
.baseUrl("https://api.openai.com/v1")
179+
.headers(
180+
ModelConfig.GenericModelConfigObject.Headers.builder()
181+
.putAdditionalProperty("foo", JsonValue.from("string"))
182+
.build()
183+
)
184+
.provider(ModelConfig.GenericModelConfigObject.Provider.OPENAI)
185+
.build()
186+
)
187+
133188
val roundtrippedModelConfig =
134189
jsonMapper.readValue(
135190
jsonMapper.writeValueAsString(modelConfig),
@@ -138,4 +193,21 @@ internal class ModelConfigTest {
138193

139194
assertThat(roundtrippedModelConfig).isEqualTo(modelConfig)
140195
}
196+
197+
enum class IncompatibleJsonShapeTestCase(val value: JsonValue) {
198+
BOOLEAN(JsonValue.from(false)),
199+
STRING(JsonValue.from("invalid")),
200+
INTEGER(JsonValue.from(-1)),
201+
FLOAT(JsonValue.from(3.14)),
202+
ARRAY(JsonValue.from(listOf("invalid", "array"))),
203+
}
204+
205+
@ParameterizedTest
206+
@EnumSource
207+
fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) {
208+
val modelConfig = jsonMapper().convertValue(testCase.value, jacksonTypeRef<ModelConfig>())
209+
210+
val e = assertThrows<StagehandInvalidDataException> { modelConfig.validate() }
211+
assertThat(e).hasMessageStartingWith("Unknown ")
212+
}
141213
}

0 commit comments

Comments
 (0)