Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AbortSignal support #144

Merged
merged 31 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4e033fd
Add RequestOptions to FileManager
DellaBitta May 7, 2024
e706597
Merge branch 'main' into ddb-request-abort-signal
DellaBitta May 15, 2024
a9440ae
Added RequestOptions to FileManager operations.
DellaBitta May 15, 2024
58bdc31
format
DellaBitta May 15, 2024
291f5bc
remove debug output
DellaBitta May 20, 2024
2d19db5
Added FileManager abort integration tests.
DellaBitta May 20, 2024
2f67539
docs
DellaBitta May 20, 2024
c1f6ddf
Update count-tokens.test.ts
DellaBitta May 20, 2024
c5e8b37
RequestOptions parameter changes. Removal of a cat.
DellaBitta May 20, 2024
95083e1
Created SingleRequestOptions sub interface
DellaBitta May 20, 2024
f4f168c
asynchronous typo.
DellaBitta May 20, 2024
2b30a9e
Rename abortSignal to signal.
DellaBitta May 21, 2024
b125380
docs
DellaBitta May 21, 2024
f7b7b6d
predendence -> precedence typo fix
DellaBitta May 22, 2024
fbc68fd
tests timeout config in conjunction with signal
DellaBitta May 22, 2024
1ec0275
merge main
DellaBitta Jun 5, 2024
1e440f4
docs gen
DellaBitta Jun 5, 2024
7ebd83b
Merge branch 'main' into ddb-request-abort-signal
DellaBitta Jul 16, 2024
b73cb1a
merge main
DellaBitta Jul 16, 2024
20b16fb
ChatSession and GenerativeModel implementation
DellaBitta Jul 17, 2024
c4c8426
remove SRO from some FileManager functions
DellaBitta Jul 17, 2024
c61466a
docs
DellaBitta Jul 17, 2024
6e26b0c
format
DellaBitta Jul 17, 2024
bec6f01
GoogleAIFileManager & GenerativeModel tests.
DellaBitta Jul 17, 2024
5bbbcf5
ChatSessionManager tests
DellaBitta Jul 17, 2024
6abb6d4
extra GoogleAIFileManager variables
DellaBitta Jul 17, 2024
4d7121f
Fix utest failure due to signal now appearing in requests
DellaBitta Jul 18, 2024
5e52c28
yarn docs
DellaBitta Jul 18, 2024
0edc918
AbortSignal in buildFetchOptions only if needed.
DellaBitta Jul 19, 2024
1444eb6
docs
DellaBitta Jul 19, 2024
ac4b721
changeset
DellaBitta Jul 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ Constructs a new instance of the `GoogleAIFileManager` class
**Signature:**

```typescript
constructor(apiKey: string, _requestOptions?: RequestOptions);
constructor(apiKey: string, requestOptions?: RequestOptions);
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| apiKey | string | |
| \_requestOptions | [RequestOptions](./generative-ai.requestoptions.md) | _(Optional)_ |
| requestOptions | [RequestOptions](./generative-ai.requestoptions.md) | _(Optional)_ |

Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ Delete file with given ID
**Signature:**

```typescript
deleteFile(fileId: string): Promise<void>;
deleteFile(fileId: string, requestOptions?: RequestOptions): Promise<void>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| fileId | string | |
| requestOptions | [RequestOptions](./generative-ai.requestoptions.md) | _(Optional)_ |

**Returns:**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ Get metadata for file with given ID
**Signature:**

```typescript
getFile(fileId: string): Promise<FileMetadataResponse>;
getFile(fileId: string, requestOptions?: RequestOptions): Promise<FileMetadataResponse>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| fileId | string | |
| requestOptions | [RequestOptions](./generative-ai.requestoptions.md) | _(Optional)_ |

**Returns:**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ List all uploaded files
**Signature:**

```typescript
listFiles(listParams?: ListParams): Promise<ListFilesResponse>;
listFiles(listParams?: ListParams, requestOptions?: RequestOptions): Promise<ListFilesResponse>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| listParams | [ListParams](./generative-ai.listparams.md) | _(Optional)_ |
| requestOptions | [RequestOptions](./generative-ai.requestoptions.md) | _(Optional)_ |

**Returns:**

Expand Down
10 changes: 5 additions & 5 deletions docs/reference/files/generative-ai.googleaifilemanager.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export declare class GoogleAIFileManager

| Constructor | Modifiers | Description |
| --- | --- | --- |
| [(constructor)(apiKey, \_requestOptions)](./generative-ai.googleaifilemanager._constructor_.md) | | Constructs a new instance of the <code>GoogleAIFileManager</code> class |
| [(constructor)(apiKey, requestOptions)](./generative-ai.googleaifilemanager._constructor_.md) | | Constructs a new instance of the <code>GoogleAIFileManager</code> class |

## Properties

Expand All @@ -28,8 +28,8 @@ export declare class GoogleAIFileManager

| Method | Modifiers | Description |
| --- | --- | --- |
| [deleteFile(fileId)](./generative-ai.googleaifilemanager.deletefile.md) | | Delete file with given ID |
| [getFile(fileId)](./generative-ai.googleaifilemanager.getfile.md) | | Get metadata for file with given ID |
| [listFiles(listParams)](./generative-ai.googleaifilemanager.listfiles.md) | | List all uploaded files |
| [uploadFile(filePath, fileMetadata)](./generative-ai.googleaifilemanager.uploadfile.md) | | Upload a file |
| [deleteFile(fileId, requestOptions)](./generative-ai.googleaifilemanager.deletefile.md) | | Delete file with given ID |
| [getFile(fileId, requestOptions)](./generative-ai.googleaifilemanager.getfile.md) | | Get metadata for file with given ID |
| [listFiles(listParams, requestOptions)](./generative-ai.googleaifilemanager.listfiles.md) | | List all uploaded files |
| [uploadFile(filePath, fileMetadata, requestOptions)](./generative-ai.googleaifilemanager.uploadfile.md) | | Upload a file |

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Upload a file
**Signature:**

```typescript
uploadFile(filePath: string, fileMetadata: FileMetadata): Promise<UploadFileResponse>;
uploadFile(filePath: string, fileMetadata: FileMetadata, requestOptions?: RequestOptions): Promise<UploadFileResponse>;
```

## Parameters
Expand All @@ -18,6 +18,7 @@ uploadFile(filePath: string, fileMetadata: FileMetadata): Promise<UploadFileResp
| --- | --- | --- |
| filePath | string | |
| fileMetadata | [FileMetadata](./generative-ai.filemetadata.md) | |
| requestOptions | [RequestOptions](./generative-ai.requestoptions.md) | _(Optional)_ |

**Returns:**

Expand Down
13 changes: 13 additions & 0 deletions docs/reference/files/generative-ai.requestoptions.abortsignal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@google/generative-ai](./generative-ai.md) &gt; [RequestOptions](./generative-ai.requestoptions.md) &gt; [abortSignal](./generative-ai.requestoptions.abortsignal.md)

## RequestOptions.abortSignal property

An object that may be used to abort aynchronous requests. This is only available on a per request basis, and is ignored by models constructed with a RequestOptions object.

**Signature:**

```typescript
abortSignal?: AbortSignal;
```
1 change: 1 addition & 0 deletions docs/reference/files/generative-ai.requestoptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface RequestOptions

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [abortSignal?](./generative-ai.requestoptions.abortsignal.md) | | AbortSignal | _(Optional)_ An object that may be used to abort aynchronous requests. This is only available on a per request basis, and is ignored by models constructed with a RequestOptions object. |
| [apiClient?](./generative-ai.requestoptions.apiclient.md) | | string | _(Optional)_ Additional attribution information to include in the x-goog-api-client header. Used by wrapper SDKs. |
| [apiVersion?](./generative-ai.requestoptions.apiversion.md) | | string | _(Optional)_ Version of API endpoint to call (e.g. "v1" or "v1beta"). If not specified, defaults to latest stable version. |
| [baseUrl?](./generative-ai.requestoptions.baseurl.md) | | string | _(Optional)_ Base endpoint url. Defaults to "https://generativelanguage.googleapis.com" |
Expand Down
13 changes: 13 additions & 0 deletions docs/reference/main/generative-ai.requestoptions.abortsignal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@google/generative-ai](./generative-ai.md) &gt; [RequestOptions](./generative-ai.requestoptions.md) &gt; [abortSignal](./generative-ai.requestoptions.abortsignal.md)

## RequestOptions.abortSignal property

An object that may be used to abort aynchronous requests. This is only available on a per request basis, and is ignored by models constructed with a RequestOptions object.

**Signature:**

```typescript
abortSignal?: AbortSignal;
```
1 change: 1 addition & 0 deletions docs/reference/main/generative-ai.requestoptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface RequestOptions

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [abortSignal?](./generative-ai.requestoptions.abortsignal.md) | | AbortSignal | _(Optional)_ An object that may be used to abort aynchronous requests. This is only available on a per request basis, and is ignored by models constructed with a RequestOptions object. |
| [apiClient?](./generative-ai.requestoptions.apiclient.md) | | string | _(Optional)_ Additional attribution information to include in the x-goog-api-client header. Used by wrapper SDKs. |
| [apiVersion?](./generative-ai.requestoptions.apiversion.md) | | string | _(Optional)_ Version of API endpoint to call (e.g. "v1" or "v1beta"). If not specified, defaults to latest stable version. |
| [baseUrl?](./generative-ai.requestoptions.baseurl.md) | | string | _(Optional)_ Base endpoint url. Defaults to "https://generativelanguage.googleapis.com" |
Expand Down
52 changes: 43 additions & 9 deletions packages/main/src/files/file-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,36 @@ export interface UploadMetadata {
* @public
*/
export class GoogleAIFileManager {
private _requestOptions: RequestOptions;
constructor(
public apiKey: string,
private _requestOptions?: RequestOptions,
) {}
requestOptions?: RequestOptions,
DellaBitta marked this conversation as resolved.
Show resolved Hide resolved
) {
this._requestOptions = {};
if (requestOptions) {
Object.assign(this._requestOptions, requestOptions);
delete this._requestOptions.abortSignal;
}
}

/**
* Upload a file
*/
async uploadFile(
filePath: string,
fileMetadata: FileMetadata,
requestOptions?: RequestOptions,
): Promise<UploadFileResponse> {
const file = readFileSync(filePath);
const filesRequestOptions = Object.create(this._requestOptions);
DellaBitta marked this conversation as resolved.
Show resolved Hide resolved
if (requestOptions) {
Object.assign(filesRequestOptions, requestOptions);
}

const url = new FilesRequestUrl(
FilesTask.UPLOAD,
this.apiKey,
this._requestOptions,
filesRequestOptions,
);

const uploadHeaders = getHeaders(url);
Expand Down Expand Up @@ -95,11 +108,18 @@ export class GoogleAIFileManager {
/**
* List all uploaded files
*/
async listFiles(listParams?: ListParams): Promise<ListFilesResponse> {
async listFiles(
listParams?: ListParams,
requestOptions?: RequestOptions,
): Promise<ListFilesResponse> {
const filesRequestOptions = Object.create(this._requestOptions);
if (requestOptions) {
Object.assign(filesRequestOptions, requestOptions);
}
const url = new FilesRequestUrl(
FilesTask.LIST,
this.apiKey,
this._requestOptions,
filesRequestOptions,
);
if (listParams?.pageSize) {
url.appendParam("pageSize", listParams.pageSize.toString());
Expand All @@ -115,11 +135,18 @@ export class GoogleAIFileManager {
/**
* Get metadata for file with given ID
*/
async getFile(fileId: string): Promise<FileMetadataResponse> {
async getFile(
fileId: string,
requestOptions?: RequestOptions,
): Promise<FileMetadataResponse> {
const filesRequestOptions = Object.create(this._requestOptions);
if (requestOptions) {
Object.assign(filesRequestOptions, requestOptions);
}
const url = new FilesRequestUrl(
FilesTask.GET,
this.apiKey,
this._requestOptions,
filesRequestOptions,
);
url.appendPath(parseFileId(fileId));
const uploadHeaders = getHeaders(url);
Expand All @@ -130,11 +157,18 @@ export class GoogleAIFileManager {
/**
* Delete file with given ID
*/
async deleteFile(fileId: string): Promise<void> {
async deleteFile(
fileId: string,
requestOptions?: RequestOptions,
): Promise<void> {
const filesRequestOptions = Object.create(this._requestOptions);
if (requestOptions) {
Object.assign(filesRequestOptions, requestOptions);
}
const url = new FilesRequestUrl(
FilesTask.DELETE,
this.apiKey,
this._requestOptions,
filesRequestOptions,
);
url.appendPath(parseFileId(fileId));
const uploadHeaders = getHeaders(url);
Expand Down
22 changes: 16 additions & 6 deletions packages/main/src/files/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,23 @@ export async function makeFilesRequest(
}

/**
* Get AbortSignal if timeout is specified
* Create an AbortSignal based on the timeout and abortSignal in the
* RequestOptions.
*/
function getSignal(requestOptions?: RequestOptions): AbortSignal | null {
if (requestOptions?.timeout >= 0) {
const abortController = new AbortController();
const signal = abortController.signal;
setTimeout(() => abortController.abort(), requestOptions.timeout);
return signal;
if (
requestOptions?.abortSignal !== undefined ||
requestOptions?.timeout >= 0
) {
const controller = new AbortController();
if (requestOptions?.timeout >= 0) {
setTimeout(() => controller.abort(), requestOptions.timeout);
}
if (requestOptions.abortSignal) {
DellaBitta marked this conversation as resolved.
Show resolved Hide resolved
requestOptions.abortSignal.addEventListener("abort", () => {
controller.abort();
});
}
return controller.signal;
}
}
75 changes: 75 additions & 0 deletions packages/main/test-integration/node/abort-signal.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* @license
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { expect, use } from "chai";
import * as chaiAsPromised from "chai-as-promised";
import { RequestOptions } from "../..";
import { GoogleAIFileManager } from "../../dist/files";

use(chaiAsPromised);

/**
* Integration tests against live backend.
*/
describe("abortSignal", function () {
this.timeout(60e3);
this.slow(10e3);
it("file manager uploadFile abort test", async () => {
const fileManager = new GoogleAIFileManager(process.env.GEMINI_API_KEY);
const filePathInService = "abortsignal.jpg";

// This delete step should cleanup the state of the service for this and
// future executions.
try {
await fileManager.deleteFile("files/abortsignal");
} catch (error) {}

const abortSignal = AbortSignal.timeout(1);
const promise = fileManager.uploadFile(
"test-integration/resources/cat.jpg",
{
mimeType: "image/jpeg",
name: filePathInService,
},
{
abortSignal,
},
);
await expect(promise).to.be.rejectedWith("This operation was aborted");
});
it("file manager listFiles abort test", async () => {
const fileManager = new GoogleAIFileManager(process.env.GEMINI_API_KEY);
const abortSignal = AbortSignal.timeout(1);
const requestOptions: RequestOptions = { abortSignal };
const promise = fileManager.listFiles(/* listParams= */ {}, requestOptions);
await expect(promise).to.be.rejectedWith("This operation was aborted");
});
it("file manager getFile abort test", async () => {
const fileManager = new GoogleAIFileManager(process.env.GEMINI_API_KEY);
const abortSignal = AbortSignal.timeout(1);
const requestOptions: RequestOptions = { abortSignal };
const promise = fileManager.getFile("abortSignal.jpg", requestOptions);
await expect(promise).to.be.rejectedWith("This operation was aborted");
});
it("file manager deleteFile abort test", async () => {
const fileManager = new GoogleAIFileManager(process.env.GEMINI_API_KEY);
const abortSignal = AbortSignal.timeout(1);
const requestOptions: RequestOptions = { abortSignal };
const promise = fileManager.deleteFile("abortSignal.jpg", requestOptions);
await expect(promise).to.be.rejectedWith("This operation was aborted");
});
});
Binary file added packages/main/test-integration/resources/cat.jpg
DellaBitta marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions packages/main/types/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ export interface RequestOptions {
* Custom HTTP request headers.
*/
customHeaders?: Headers | Record<string, string>;
/**
* An object that may be used to abort aynchronous requests. This is only available on
DellaBitta marked this conversation as resolved.
Show resolved Hide resolved
* a per request basis, and is ignored by models constructed with a RequestOptions object.
*/
abortSignal?: AbortSignal;
}

/**
Expand Down
Loading