Skip to content

Commit 2a0eacd

Browse files
speedstorm1copybara-github
authored andcommitted
feat: Support the list method in the Dotnet SDK Tunings module
PiperOrigin-RevId: 835381806
1 parent dce6173 commit 2a0eacd

File tree

10 files changed

+1465
-16
lines changed

10 files changed

+1465
-16
lines changed

Google.GenAI.E2E.Tests/Recordings/ListTuningsTest.ListTuningsGeminiTest.json

Lines changed: 580 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
{
2+
"recordID": "ListTuningsTest.ListTuningsVertexTest",
3+
"interactions": [
4+
{
5+
"request": {
6+
"method": "POST",
7+
"url": "/v1beta1/projects/REDACTED/locations/us-central1/tuningJobs",
8+
"request": "POST /v1beta1/projects/REDACTED/locations/us-central1/tuningJobs HTTP/1.1",
9+
"headers": {
10+
"Content-Length": "202",
11+
"Content-Type": "application/json; charset=utf-8",
12+
"Test-Name": "ListTuningsTest.ListTuningsVertexTest"
13+
},
14+
"bodySegments": [
15+
{
16+
"baseModel": "gemini-2.5-flash",
17+
"supervisedTuningSpec": {
18+
"hyperParameters": {
19+
"epochCount": 1
20+
},
21+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
22+
}
23+
}
24+
],
25+
"previousRequest": "b4d6e60a9b97e7b98c63df9308728c5c88c0b40c398046772c63447b94608b4d",
26+
"serverAddress": "us-central1-aiplatform.googleapis.com",
27+
"port": 443,
28+
"protocol": "https"
29+
},
30+
"shaSum": "71f90e1fcbf48a4ea00982fdc596ef6abbf6cc124e9b0b059c62e665004c4c31",
31+
"response": {
32+
"statusCode": 200,
33+
"headers": {
34+
"Content-Type": "application/json; charset=UTF-8",
35+
"Date": "Sat, 22 Nov 2025 00:02:58 GMT",
36+
"Server": "ESF",
37+
"Vary": "Origin, X-Origin, Referer",
38+
"X-Content-Type-Options": "nosniff",
39+
"X-Frame-Options": "SAMEORIGIN",
40+
"X-Xss-Protection": "0"
41+
},
42+
"bodySegments": [
43+
{
44+
"baseModel": "gemini-2.5-flash",
45+
"createTime": "2025-11-22T00:02:58.116228Z",
46+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/7531394117549424640",
47+
"state": "JOB_STATE_PENDING",
48+
"supervisedTuningSpec": {
49+
"hyperParameters": {
50+
"epochCount": "1"
51+
},
52+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
53+
},
54+
"tunedModelDisplayName": "gemini-2.5-flash-412043df-9870-4922-bc1d-544ee4b70b5c",
55+
"updateTime": "2025-11-22T00:02:58.116228Z"
56+
}
57+
]
58+
}
59+
},
60+
{
61+
"request": {
62+
"method": "POST",
63+
"url": "/v1beta1/projects/REDACTED/locations/us-central1/tuningJobs",
64+
"request": "POST /v1beta1/projects/REDACTED/locations/us-central1/tuningJobs HTTP/1.1",
65+
"headers": {
66+
"Content-Length": "202",
67+
"Content-Type": "application/json; charset=utf-8",
68+
"Test-Name": "ListTuningsTest.ListTuningsVertexTest"
69+
},
70+
"bodySegments": [
71+
{
72+
"baseModel": "gemini-2.5-flash",
73+
"supervisedTuningSpec": {
74+
"hyperParameters": {
75+
"epochCount": 1
76+
},
77+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
78+
}
79+
}
80+
],
81+
"previousRequest": "71f90e1fcbf48a4ea00982fdc596ef6abbf6cc124e9b0b059c62e665004c4c31",
82+
"serverAddress": "us-central1-aiplatform.googleapis.com",
83+
"port": 443,
84+
"protocol": "https"
85+
},
86+
"shaSum": "345578fc7f06a62b119fb1d17c452a60ef3cfeb4b431696481f8c1f303423bf3",
87+
"response": {
88+
"statusCode": 200,
89+
"headers": {
90+
"Content-Type": "application/json; charset=UTF-8",
91+
"Date": "Sat, 22 Nov 2025 00:02:58 GMT",
92+
"Server": "ESF",
93+
"Vary": "Origin, X-Origin, Referer",
94+
"X-Content-Type-Options": "nosniff",
95+
"X-Frame-Options": "SAMEORIGIN",
96+
"X-Xss-Protection": "0"
97+
},
98+
"bodySegments": [
99+
{
100+
"baseModel": "gemini-2.5-flash",
101+
"createTime": "2025-11-22T00:02:58.515210Z",
102+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/7857905090533785600",
103+
"state": "JOB_STATE_PENDING",
104+
"supervisedTuningSpec": {
105+
"hyperParameters": {
106+
"epochCount": "1"
107+
},
108+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
109+
},
110+
"tunedModelDisplayName": "gemini-2.5-flash-8773c6a0-e8b5-40f2-b5e8-ae5660613a11",
111+
"updateTime": "2025-11-22T00:02:58.515210Z"
112+
}
113+
]
114+
}
115+
},
116+
{
117+
"request": {
118+
"method": "GET",
119+
"url": "/v1beta1/projects/REDACTED/locations/us-central1/tuningJobs",
120+
"request": "GET /v1beta1/projects/REDACTED/locations/us-central1/tuningJobs HTTP/1.1",
121+
"headers": {
122+
"Test-Name": "ListTuningsTest.ListTuningsVertexTest"
123+
},
124+
"bodySegments": [
125+
null
126+
],
127+
"previousRequest": "345578fc7f06a62b119fb1d17c452a60ef3cfeb4b431696481f8c1f303423bf3",
128+
"serverAddress": "us-central1-aiplatform.googleapis.com",
129+
"port": 443,
130+
"protocol": "https"
131+
},
132+
"shaSum": "b06bbefbda2e324df65c38481045660b7180f88b40ab501ec53988cf7b598362",
133+
"response": {
134+
"statusCode": 200,
135+
"headers": {
136+
"Content-Type": "application/json; charset=UTF-8",
137+
"Date": "Sat, 22 Nov 2025 00:02:58 GMT",
138+
"Server": "ESF",
139+
"Vary": "Origin, X-Origin, Referer",
140+
"X-Content-Type-Options": "nosniff",
141+
"X-Frame-Options": "SAMEORIGIN",
142+
"X-Xss-Protection": "0"
143+
},
144+
"bodySegments": [
145+
{
146+
"tuningJobs": [
147+
{
148+
"baseModel": "gemini-2.5-flash",
149+
"createTime": "2025-11-22T00:02:58.515210Z",
150+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/7857905090533785600",
151+
"state": "JOB_STATE_PENDING",
152+
"supervisedTuningSpec": {
153+
"hyperParameters": {
154+
"epochCount": "1"
155+
},
156+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
157+
},
158+
"tunedModelDisplayName": "gemini-2.5-flash-8773c6a0-e8b5-40f2-b5e8-ae5660613a11",
159+
"updateTime": "2025-11-22T00:02:58.515210Z"
160+
},
161+
{
162+
"baseModel": "gemini-2.5-flash",
163+
"createTime": "2025-11-22T00:02:58.116228Z",
164+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/7531394117549424640",
165+
"state": "JOB_STATE_PENDING",
166+
"supervisedTuningSpec": {
167+
"hyperParameters": {
168+
"epochCount": "1"
169+
},
170+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
171+
},
172+
"tunedModelDisplayName": "gemini-2.5-flash-412043df-9870-4922-bc1d-544ee4b70b5c",
173+
"updateTime": "2025-11-22T00:02:58.116228Z"
174+
},
175+
{
176+
"baseModel": "gemini-2.5-flash",
177+
"createTime": "2025-11-22T00:02:56.033228Z",
178+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/1966070878026334208",
179+
"state": "JOB_STATE_PENDING",
180+
"supervisedTuningSpec": {
181+
"hyperParameters": {
182+
"epochCount": "1"
183+
},
184+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
185+
},
186+
"tunedModelDisplayName": "gemini-2.5-flash-02d3cc27-f8cd-430c-91d9-f0dbaa4675d7",
187+
"updateTime": "2025-11-22T00:02:56.033228Z"
188+
},
189+
{
190+
"baseModel": "gemini-2.5-flash",
191+
"createTime": "2025-11-22T00:02:55.758789Z",
192+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/2919708099122036736",
193+
"state": "JOB_STATE_PENDING",
194+
"supervisedTuningSpec": {
195+
"hyperParameters": {
196+
"epochCount": "1"
197+
},
198+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
199+
},
200+
"tunedModelDisplayName": "gemini-2.5-flash-66651d07-cf50-4374-8e91-f4d7aabf3584",
201+
"updateTime": "2025-11-22T00:02:55.758789Z"
202+
},
203+
{
204+
"baseModel": "gemini-2.5-flash",
205+
"createTime": "2025-11-22T00:02:25.119511Z",
206+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/118469130897588224",
207+
"state": "JOB_STATE_PENDING",
208+
"supervisedTuningSpec": {
209+
"hyperParameters": {
210+
"epochCount": "1"
211+
},
212+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
213+
},
214+
"tunedModelDisplayName": "gemini-2.5-flash-f4100899-1d1f-4bba-b705-2be893b6dcfd",
215+
"updateTime": "2025-11-22T00:02:25.119511Z"
216+
},
217+
{
218+
"baseModel": "gemini-2.5-flash",
219+
"createTime": "2025-11-22T00:02:24.883552Z",
220+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/3685320035775021056",
221+
"state": "JOB_STATE_PENDING",
222+
"supervisedTuningSpec": {
223+
"hyperParameters": {
224+
"epochCount": "1"
225+
},
226+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
227+
},
228+
"tunedModelDisplayName": "gemini-2.5-flash-5ca5e843-5f3d-49ab-978d-c4768719fc69",
229+
"updateTime": "2025-11-22T00:02:24.883552Z"
230+
},
231+
{
232+
"baseModel": "gemini-2.5-flash",
233+
"createTime": "2025-11-22T00:02:22.766189Z",
234+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/8465891040228802560",
235+
"state": "JOB_STATE_PENDING",
236+
"supervisedTuningSpec": {
237+
"hyperParameters": {
238+
"epochCount": "1"
239+
},
240+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
241+
},
242+
"tunedModelDisplayName": "gemini-2.5-flash-c548fe1a-72a9-4a46-bae2-f1d717dbde8d",
243+
"updateTime": "2025-11-22T00:02:22.766189Z"
244+
},
245+
{
246+
"baseModel": "gemini-2.5-flash",
247+
"createTime": "2025-11-22T00:02:22.514582Z",
248+
"name": "projects/REDACTED/locations/us-central1/tuningJobs/6215780076403818496",
249+
"state": "JOB_STATE_PENDING",
250+
"supervisedTuningSpec": {
251+
"hyperParameters": {
252+
"epochCount": "1"
253+
},
254+
"trainingDatasetUri": "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
255+
},
256+
"tunedModelDisplayName": "gemini-2.5-flash-149b1016-97ee-434e-a9e3-40e9bfa2a491",
257+
"updateTime": "2025-11-22T00:02:22.514582Z"
258+
}
259+
]
260+
}
261+
]
262+
}
263+
}
264+
]
265+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using System;
18+
using System.Collections.Generic;
19+
using System.Linq;
20+
using System.Threading.Tasks;
21+
22+
using Google.GenAI;
23+
using Google.GenAI.Types;
24+
25+
using Microsoft.VisualStudio.TestTools.UnitTesting;
26+
27+
using TestServerSdk;
28+
29+
[TestClass]
30+
public class ListTuningsTest
31+
{
32+
private static TestServerProcess? _server;
33+
private Client vertexClient;
34+
private Client geminiClient;
35+
private string modelName;
36+
public TestContext TestContext { get; set; }
37+
38+
[ClassInitialize]
39+
public static void ClassInit(TestContext _)
40+
{
41+
_server = TestServer.StartTestServer();
42+
}
43+
44+
[ClassCleanup]
45+
public static void ClassCleanup()
46+
{
47+
TestServer.StopTestServer(_server);
48+
}
49+
50+
[TestInitialize]
51+
public void TestInit()
52+
{
53+
// Test server specific setup.
54+
if (_server == null)
55+
{
56+
throw new InvalidOperationException("Test server is not initialized.");
57+
}
58+
var geminiClientHttpOptions = new HttpOptions {
59+
Headers = new Dictionary<string, string> { { "Test-Name",
60+
$"{GetType().Name}.{TestContext.TestName}" } },
61+
BaseUrl = "http://localhost:1453"
62+
};
63+
var vertexClientHttpOptions = new HttpOptions {
64+
Headers = new Dictionary<string, string> { { "Test-Name",
65+
$"{GetType().Name}.{TestContext.TestName}" } },
66+
BaseUrl = "http://localhost:1454"
67+
};
68+
69+
// Common setup for both clients.
70+
string project = System.Environment.GetEnvironmentVariable("GOOGLE_CLOUD_PROJECT");
71+
string location =
72+
System.Environment.GetEnvironmentVariable("GOOGLE_CLOUD_LOCATION") ?? "us-central1";
73+
string apiKey = System.Environment.GetEnvironmentVariable("GOOGLE_API_KEY");
74+
vertexClient = new Client(project: project, location: location, vertexAI: true,
75+
credential: TestServer.GetCredentialForTestMode(),
76+
httpOptions: vertexClientHttpOptions);
77+
geminiClient =
78+
new Client(apiKey: apiKey, vertexAI: false, httpOptions: geminiClientHttpOptions);
79+
80+
// Specific setup for this test class
81+
modelName = "gemini-2.5-flash";
82+
}
83+
84+
[TestMethod]
85+
public async Task ListTuningsVertexTest()
86+
{
87+
// Create two tuning jobs.
88+
var trainingDataset = new TuningDataset {
89+
GcsUri = "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
90+
};
91+
var config = new CreateTuningJobConfig {
92+
EpochCount = 1
93+
};
94+
var firstTuningJob = await vertexClient.Tunings.TuneAsync(modelName, trainingDataset, config);
95+
var secondTuningJob = await vertexClient.Tunings.TuneAsync(modelName, trainingDataset, config);
96+
97+
var pager = await vertexClient.Tunings.ListAsync(new ListTuningJobsConfig { PageSize = 1 });
98+
99+
int count = 0;
100+
await foreach(var item in pager)
101+
{
102+
count++;
103+
if (count >= 2)
104+
{
105+
break;
106+
}
107+
}
108+
109+
Assert.IsTrue(count >= 2);
110+
Assert.AreEqual(1, pager.PageSize);
111+
}
112+
113+
[TestMethod]
114+
public async Task ListTuningsGeminiTest()
115+
{
116+
var pager = await geminiClient.Tunings.ListAsync(new ListTuningJobsConfig { PageSize = 1 });
117+
118+
int count = 0;
119+
await foreach(var item in pager)
120+
{
121+
count++;
122+
if (count >= 2)
123+
{
124+
break;
125+
}
126+
}
127+
128+
Assert.IsTrue(count >= 0);
129+
Assert.AreEqual(1, pager.PageSize);
130+
}
131+
}

0 commit comments

Comments
 (0)