Skip to content

Commit ce002ec

Browse files
authored
[FirebaseAI] Remove custom exceptions (#1250)
1 parent 4a09083 commit ce002ec

File tree

9 files changed

+63
-149
lines changed

9 files changed

+63
-149
lines changed

firebaseai/src/Chat.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ internal static Chat InternalCreateChat(GenerativeModel model, IEnumerable<Model
6464
/// <param name="content">The input given to the model as a prompt.</param>
6565
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
6666
/// <returns>The model's response if no error occurred.</returns>
67-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
67+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
6868
public Task<GenerateContentResponse> SendMessageAsync(
6969
ModelContent content, CancellationToken cancellationToken = default) {
7070
return SendMessageAsync(new[] { content }, cancellationToken);
@@ -76,7 +76,7 @@ public Task<GenerateContentResponse> SendMessageAsync(
7676
/// <param name="text">The text given to the model as a prompt.</param>
7777
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
7878
/// <returns>The model's response if no error occurred.</returns>
79-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
79+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
8080
public Task<GenerateContentResponse> SendMessageAsync(
8181
string text, CancellationToken cancellationToken = default) {
8282
return SendMessageAsync(new ModelContent[] { ModelContent.Text(text) }, cancellationToken);
@@ -88,7 +88,7 @@ public Task<GenerateContentResponse> SendMessageAsync(
8888
/// <param name="content">The input given to the model as a prompt.</param>
8989
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
9090
/// <returns>The model's response if no error occurred.</returns>
91-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
91+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
9292
public Task<GenerateContentResponse> SendMessageAsync(
9393
IEnumerable<ModelContent> content, CancellationToken cancellationToken = default) {
9494
return SendMessageAsyncInternal(content, cancellationToken);
@@ -101,7 +101,7 @@ public Task<GenerateContentResponse> SendMessageAsync(
101101
/// <param name="content">The input given to the model as a prompt.</param>
102102
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
103103
/// <returns>A stream of generated content responses from the model.</returns>
104-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
104+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
105105
public IAsyncEnumerable<GenerateContentResponse> SendMessageStreamAsync(
106106
ModelContent content, CancellationToken cancellationToken = default) {
107107
return SendMessageStreamAsync(new[] { content }, cancellationToken);
@@ -113,7 +113,7 @@ public IAsyncEnumerable<GenerateContentResponse> SendMessageStreamAsync(
113113
/// <param name="text">The text given to the model as a prompt.</param>
114114
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
115115
/// <returns>A stream of generated content responses from the model.</returns>
116-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
116+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
117117
public IAsyncEnumerable<GenerateContentResponse> SendMessageStreamAsync(
118118
string text, CancellationToken cancellationToken = default) {
119119
return SendMessageStreamAsync(new ModelContent[] { ModelContent.Text(text) }, cancellationToken);
@@ -125,7 +125,7 @@ public IAsyncEnumerable<GenerateContentResponse> SendMessageStreamAsync(
125125
/// <param name="content">The input given to the model as a prompt.</param>
126126
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
127127
/// <returns>A stream of generated content responses from the model.</returns>
128-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
128+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
129129
public IAsyncEnumerable<GenerateContentResponse> SendMessageStreamAsync(
130130
IEnumerable<ModelContent> content, CancellationToken cancellationToken = default) {
131131
return SendMessageStreamAsyncInternal(content, cancellationToken);

firebaseai/src/FirebaseAI.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ public static Backend GoogleAI() {
6868
/// for a list of supported regions.</param>
6969
public static Backend VertexAI(string location = "us-central1") {
7070
if (string.IsNullOrWhiteSpace(location) || location.Contains("/")) {
71-
throw new FirebaseAIInvalidLocationException(location);
71+
throw new ArgumentException(
72+
$"The location argument must be non-empty, and not contain special characters like '/'");
7273
}
7374

7475
return new Backend(InternalProvider.VertexAI, location);

firebaseai/src/FirebaseAIException.cs

Lines changed: 0 additions & 82 deletions
This file was deleted.

firebaseai/src/FirebaseAIException.cs.meta

Lines changed: 0 additions & 11 deletions
This file was deleted.

firebaseai/src/GenerativeModel.cs

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ internal GenerativeModel(FirebaseApp firebaseApp,
8686
/// <param name="content">The input given to the model as a prompt.</param>
8787
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
8888
/// <returns>The generated content response from the model.</returns>
89-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
89+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
9090
public Task<GenerateContentResponse> GenerateContentAsync(
9191
ModelContent content, CancellationToken cancellationToken = default) {
9292
return GenerateContentAsync(new[] { content }, cancellationToken);
@@ -97,7 +97,7 @@ public Task<GenerateContentResponse> GenerateContentAsync(
9797
/// <param name="text">The text given to the model as a prompt.</param>
9898
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
9999
/// <returns>The generated content response from the model.</returns>
100-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
100+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
101101
public Task<GenerateContentResponse> GenerateContentAsync(
102102
string text, CancellationToken cancellationToken = default) {
103103
return GenerateContentAsync(new[] { ModelContent.Text(text) }, cancellationToken);
@@ -108,7 +108,7 @@ public Task<GenerateContentResponse> GenerateContentAsync(
108108
/// <param name="content">The input given to the model as a prompt.</param>
109109
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
110110
/// <returns>The generated content response from the model.</returns>
111-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
111+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
112112
public Task<GenerateContentResponse> GenerateContentAsync(
113113
IEnumerable<ModelContent> content, CancellationToken cancellationToken = default) {
114114
return GenerateContentAsyncInternal(content, cancellationToken);
@@ -120,7 +120,7 @@ public Task<GenerateContentResponse> GenerateContentAsync(
120120
/// <param name="content">The input given to the model as a prompt.</param>
121121
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
122122
/// <returns>A stream of generated content responses from the model.</returns>
123-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
123+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
124124
public IAsyncEnumerable<GenerateContentResponse> GenerateContentStreamAsync(
125125
ModelContent content, CancellationToken cancellationToken = default) {
126126
return GenerateContentStreamAsync(new[] { content }, cancellationToken);
@@ -131,7 +131,7 @@ public IAsyncEnumerable<GenerateContentResponse> GenerateContentStreamAsync(
131131
/// <param name="text">The text given to the model as a prompt.</param>
132132
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
133133
/// <returns>A stream of generated content responses from the model.</returns>
134-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
134+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
135135
public IAsyncEnumerable<GenerateContentResponse> GenerateContentStreamAsync(
136136
string text, CancellationToken cancellationToken = default) {
137137
return GenerateContentStreamAsync(new[] { ModelContent.Text(text) }, cancellationToken);
@@ -142,7 +142,7 @@ public IAsyncEnumerable<GenerateContentResponse> GenerateContentStreamAsync(
142142
/// <param name="content">The input given to the model as a prompt.</param>
143143
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
144144
/// <returns>A stream of generated content responses from the model.</returns>
145-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during content generation.</exception>
145+
/// <exception cref="HttpRequestException">Thrown when an error occurs during content generation.</exception>
146146
public IAsyncEnumerable<GenerateContentResponse> GenerateContentStreamAsync(
147147
IEnumerable<ModelContent> content, CancellationToken cancellationToken = default) {
148148
return GenerateContentStreamAsyncInternal(content, cancellationToken);
@@ -153,7 +153,7 @@ public IAsyncEnumerable<GenerateContentResponse> GenerateContentStreamAsync(
153153
/// </summary>
154154
/// <param name="content">The input given to the model as a prompt.</param>
155155
/// <returns>The `CountTokensResponse` of running the model's tokenizer on the input.</returns>
156-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during the request.</exception>
156+
/// <exception cref="HttpRequestException">Thrown when an error occurs during the request.</exception>
157157
public Task<CountTokensResponse> CountTokensAsync(
158158
ModelContent content, CancellationToken cancellationToken = default) {
159159
return CountTokensAsync(new[] { content }, cancellationToken);
@@ -164,7 +164,7 @@ public Task<CountTokensResponse> CountTokensAsync(
164164
/// <param name="text">The text input given to the model as a prompt.</param>
165165
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
166166
/// <returns>The `CountTokensResponse` of running the model's tokenizer on the input.</returns>
167-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during the request.</exception>
167+
/// <exception cref="HttpRequestException">Thrown when an error occurs during the request.</exception>
168168
public Task<CountTokensResponse> CountTokensAsync(
169169
string text, CancellationToken cancellationToken = default) {
170170
return CountTokensAsync(new[] { ModelContent.Text(text) }, cancellationToken);
@@ -175,7 +175,7 @@ public Task<CountTokensResponse> CountTokensAsync(
175175
/// <param name="content">The input given to the model as a prompt.</param>
176176
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
177177
/// <returns>The `CountTokensResponse` of running the model's tokenizer on the input.</returns>
178-
/// <exception cref="FirebaseAIException">Thrown when an error occurs during the request.</exception>
178+
/// <exception cref="HttpRequestException">Thrown when an error occurs during the request.</exception>
179179
public Task<CountTokensResponse> CountTokensAsync(
180180
IEnumerable<ModelContent> content, CancellationToken cancellationToken = default) {
181181
return CountTokensAsyncInternal(content, cancellationToken);
@@ -213,16 +213,8 @@ private async Task<GenerateContentResponse> GenerateContentAsyncInternal(
213213
UnityEngine.Debug.Log("Request:\n" + bodyJson);
214214
#endif
215215

216-
HttpResponseMessage response;
217-
try {
218-
response = await _httpClient.SendAsync(request, cancellationToken);
219-
response.EnsureSuccessStatusCode();
220-
} catch (TaskCanceledException e) when (e.InnerException is TimeoutException) {
221-
throw new FirebaseAIRequestTimeoutException("Request timed out.", e);
222-
} catch (HttpRequestException e) {
223-
// TODO: Convert to a more precise exception when possible.
224-
throw new FirebaseAIException("HTTP request failed.", e);
225-
}
216+
var response = await _httpClient.SendAsync(request, cancellationToken);
217+
await ValidateHttpResponse(response);
226218

227219
string result = await response.Content.ReadAsStringAsync();
228220

@@ -233,6 +225,33 @@ private async Task<GenerateContentResponse> GenerateContentAsyncInternal(
233225
return GenerateContentResponse.FromJson(result, _backend.Provider);
234226
}
235227

228+
// Helper function to throw an exception if the Http Response indicates failure.
229+
// Useful as EnsureSuccessStatusCode can leave out relevant information.
230+
private async Task ValidateHttpResponse(HttpResponseMessage response) {
231+
if (response.IsSuccessStatusCode) {
232+
return;
233+
}
234+
235+
// Status code indicates failure, try to read the content for more details
236+
string errorContent = "No error content available.";
237+
if (response.Content != null) {
238+
try {
239+
errorContent = await response.Content.ReadAsStringAsync();
240+
} catch (Exception readEx) {
241+
// Handle being unable to read the content
242+
errorContent = $"Failed to read error content: {readEx.Message}";
243+
}
244+
}
245+
246+
// Construct the exception with as much information as possible.
247+
var ex = new HttpRequestException(
248+
$"HTTP request failed with status code: {(int)response.StatusCode} ({response.ReasonPhrase}).\n" +
249+
$"Error Content: {errorContent}"
250+
);
251+
252+
throw ex;
253+
}
254+
236255
private async IAsyncEnumerable<GenerateContentResponse> GenerateContentStreamAsyncInternal(
237256
IEnumerable<ModelContent> content,
238257
[EnumeratorCancellation] CancellationToken cancellationToken) {
@@ -249,16 +268,8 @@ private async IAsyncEnumerable<GenerateContentResponse> GenerateContentStreamAsy
249268
UnityEngine.Debug.Log("Request:\n" + bodyJson);
250269
#endif
251270

252-
HttpResponseMessage response;
253-
try {
254-
response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
255-
response.EnsureSuccessStatusCode();
256-
} catch (TaskCanceledException e) when (e.InnerException is TimeoutException) {
257-
throw new FirebaseAIRequestTimeoutException("Request timed out.", e);
258-
} catch (HttpRequestException e) {
259-
// TODO: Convert to a more precise exception when possible.
260-
throw new FirebaseAIException("HTTP request failed.", e);
261-
}
271+
var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
272+
await ValidateHttpResponse(response);
262273

263274
// We are expecting a Stream as the response, so handle that.
264275
using var stream = await response.Content.ReadAsStreamAsync();
@@ -293,16 +304,8 @@ private async Task<CountTokensResponse> CountTokensAsyncInternal(
293304
UnityEngine.Debug.Log("CountTokensRequest:\n" + bodyJson);
294305
#endif
295306

296-
HttpResponseMessage response;
297-
try {
298-
response = await _httpClient.SendAsync(request, cancellationToken);
299-
response.EnsureSuccessStatusCode();
300-
} catch (TaskCanceledException e) when (e.InnerException is TimeoutException) {
301-
throw new FirebaseAIRequestTimeoutException("Request timed out.", e);
302-
} catch (HttpRequestException e) {
303-
// TODO: Convert to a more precise exception when possible.
304-
throw new FirebaseAIException("HTTP request failed.", e);
305-
}
307+
var response = await _httpClient.SendAsync(request, cancellationToken);
308+
await ValidateHttpResponse(response);
306309

307310
string result = await response.Content.ReadAsStringAsync();
308311

0 commit comments

Comments
 (0)