@xiaozhiclaw/provider-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/aliyun-oss-file-upload-adapter.d.ts +44 -0
- package/dist/adapters/aliyun-oss-file-upload-adapter.js +96 -0
- package/dist/adapters/gemini-file-upload-adapter.d.ts +26 -0
- package/dist/adapters/gemini-file-upload-adapter.js +92 -0
- package/dist/adapters/hub-oss-file-upload-adapter.d.ts +29 -0
- package/dist/adapters/hub-oss-file-upload-adapter.js +53 -0
- package/dist/adapters/index.d.ts +10 -0
- package/dist/adapters/index.js +10 -0
- package/dist/adapters/openai-file-upload-adapter.d.ts +38 -0
- package/dist/adapters/openai-file-upload-adapter.js +56 -0
- package/dist/adapters/volcengine-file-upload-adapter.d.ts +24 -0
- package/dist/adapters/volcengine-file-upload-adapter.js +45 -0
- package/dist/builtin-providers.d.ts +8 -0
- package/dist/builtin-providers.js +2237 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/credentials.d.ts +1 -0
- package/dist/credentials.js +8 -0
- package/dist/debug-transport.d.ts +12 -0
- package/dist/debug-transport.js +99 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +12 -0
- package/dist/events.d.ts +48 -0
- package/dist/events.js +1 -0
- package/dist/file-upload-service.d.ts +68 -0
- package/dist/file-upload-service.js +110 -0
- package/dist/gemini-schema-utils.d.ts +17 -0
- package/dist/gemini-schema-utils.js +76 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +33 -0
- package/dist/llm-client.d.ts +43 -0
- package/dist/llm-client.js +217 -0
- package/dist/media-client.d.ts +42 -0
- package/dist/media-client.js +174 -0
- package/dist/media-transport.d.ts +176 -0
- package/dist/media-transport.js +16 -0
- package/dist/media.d.ts +2 -0
- package/dist/media.js +1 -0
- package/dist/model-detection.d.ts +22 -0
- package/dist/model-detection.js +28 -0
- package/dist/paths.d.ts +2 -0
- package/dist/paths.js +11 -0
- package/dist/provider-def.d.ts +220 -0
- package/dist/provider-def.js +9 -0
- package/dist/provider-registry.d.ts +51 -0
- package/dist/provider-registry.js +130 -0
- package/dist/provider-tool-api.d.ts +44 -0
- package/dist/provider-tool-api.js +9 -0
- package/dist/provider-variant-resolver.d.ts +35 -0
- package/dist/provider-variant-resolver.js +174 -0
- package/dist/retry.d.ts +37 -0
- package/dist/retry.js +71 -0
- package/dist/transport.d.ts +281 -0
- package/dist/transport.js +27 -0
- package/dist/transports/anthropic-messages.d.ts +65 -0
- package/dist/transports/anthropic-messages.js +1004 -0
- package/dist/transports/gemini-cache-api.d.ts +86 -0
- package/dist/transports/gemini-cache-api.js +141 -0
- package/dist/transports/gemini-file-api.d.ts +90 -0
- package/dist/transports/gemini-file-api.js +164 -0
- package/dist/transports/gemini-generatecontent.d.ts +56 -0
- package/dist/transports/gemini-generatecontent.js +688 -0
- package/dist/transports/gemini-lyria-realtime.d.ts +117 -0
- package/dist/transports/gemini-lyria-realtime.js +295 -0
- package/dist/transports/gemini-media.d.ts +53 -0
- package/dist/transports/gemini-media.js +383 -0
- package/dist/transports/media-resolve.d.ts +50 -0
- package/dist/transports/media-resolve.js +91 -0
- package/dist/transports/minimax-media.d.ts +56 -0
- package/dist/transports/minimax-media.js +433 -0
- package/dist/transports/openai-chat.d.ts +81 -0
- package/dist/transports/openai-chat.js +782 -0
- package/dist/transports/openai-media.d.ts +24 -0
- package/dist/transports/openai-media.js +118 -0
- package/dist/transports/openai-responses.d.ts +63 -0
- package/dist/transports/openai-responses.js +778 -0
- package/dist/transports/qwen-media.d.ts +59 -0
- package/dist/transports/qwen-media.js +411 -0
- package/dist/transports/realtime-transport.d.ts +183 -0
- package/dist/transports/realtime-transport.js +332 -0
- package/dist/transports/volcengine-grounding.d.ts +58 -0
- package/dist/transports/volcengine-grounding.js +69 -0
- package/dist/transports/volcengine-media.d.ts +94 -0
- package/dist/transports/volcengine-media.js +801 -0
- package/dist/transports/volcengine-responses.d.ts +64 -0
- package/dist/transports/volcengine-responses.js +797 -0
- package/dist/transports/zhipu-media.d.ts +82 -0
- package/dist/transports/zhipu-media.js +522 -0
- package/dist/transports/zhipu-tool-api.d.ts +35 -0
- package/dist/transports/zhipu-tool-api.js +126 -0
- package/dist/wire-types.d.ts +51 -0
- package/dist/wire-types.js +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GeminiCacheAPI 鈥?Explicit Context Caching for Gemini generateContent.
|
|
3
|
+
*
|
|
4
|
+
* Manages named cached content resources that can be referenced in
|
|
5
|
+
* generateContent requests via the `cachedContent` field.
|
|
6
|
+
*
|
|
7
|
+
* REST endpoints:
|
|
8
|
+
* POST /v1beta/cachedContents 鈥?create cache
|
|
9
|
+
* GET /v1beta/cachedContents 鈥?list caches
|
|
10
|
+
* GET /v1beta/cachedContents/{name} 鈥?get cache metadata
|
|
11
|
+
* PATCH /v1beta/cachedContents/{name} 鈥?update TTL
|
|
12
|
+
* DELETE /v1beta/cachedContents/{name} 鈥?delete cache
|
|
13
|
+
*
|
|
14
|
+
* Minimum cacheable content: 1024 tokens (Flash) / 4096 tokens (Pro).
|
|
15
|
+
* TTL default: 1 hour. Storage: ~$1.00/hour/MTok (Flash series).
|
|
16
|
+
*
|
|
17
|
+
* Docs: https://ai.google.dev/gemini-api/docs/caching
|
|
18
|
+
*/
|
|
19
|
+
export interface GeminiCacheCreateOptions {
|
|
20
|
+
/** Model to use, e.g. "models/gemini-3-flash-preview" */
|
|
21
|
+
model: string;
|
|
22
|
+
/** Contents to cache (same format as generateContent contents) */
|
|
23
|
+
contents: Array<Record<string, unknown>>;
|
|
24
|
+
/** Optional system instruction to include in cache */
|
|
25
|
+
systemInstruction?: Record<string, unknown>;
|
|
26
|
+
/** Time-to-live, e.g. "300s" for 5 minutes. Default: "3600s" (1 hour) */
|
|
27
|
+
ttl?: string;
|
|
28
|
+
/** Human-readable name for identifying the cache */
|
|
29
|
+
displayName?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface GeminiCachedContent {
|
|
32
|
+
/** Resource name, e.g. "cachedContents/abc123" */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Model this cache is bound to */
|
|
35
|
+
model: string;
|
|
36
|
+
/** Display name (if set) */
|
|
37
|
+
displayName?: string;
|
|
38
|
+
/** Token usage metadata */
|
|
39
|
+
usageMetadata?: {
|
|
40
|
+
totalTokenCount?: number;
|
|
41
|
+
};
|
|
42
|
+
/** Creation time (ISO 8601) */
|
|
43
|
+
createTime?: string;
|
|
44
|
+
/** Last update time (ISO 8601) */
|
|
45
|
+
updateTime?: string;
|
|
46
|
+
/** Expiration time (ISO 8601) */
|
|
47
|
+
expireTime?: string;
|
|
48
|
+
}
|
|
49
|
+
export declare class GeminiCacheAPI {
|
|
50
|
+
private baseUrl;
|
|
51
|
+
private timeoutMs;
|
|
52
|
+
constructor(config: {
|
|
53
|
+
baseUrl: string;
|
|
54
|
+
timeoutMs?: number;
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* Create a new cached content resource.
|
|
58
|
+
* The cache name returned can be passed as `cachedContent` in generateContent.
|
|
59
|
+
*/
|
|
60
|
+
createCache(options: GeminiCacheCreateOptions, apiKey: string, signal?: AbortSignal): Promise<GeminiCachedContent>;
|
|
61
|
+
/**
|
|
62
|
+
* Get metadata for a cached content resource.
|
|
63
|
+
*/
|
|
64
|
+
getCache(name: string, apiKey: string, signal?: AbortSignal): Promise<GeminiCachedContent>;
|
|
65
|
+
/**
|
|
66
|
+
* List all cached content resources.
|
|
67
|
+
*/
|
|
68
|
+
listCaches(apiKey: string, options?: {
|
|
69
|
+
pageSize?: number;
|
|
70
|
+
pageToken?: string;
|
|
71
|
+
}, signal?: AbortSignal): Promise<{
|
|
72
|
+
cachedContents: GeminiCachedContent[];
|
|
73
|
+
nextPageToken?: string;
|
|
74
|
+
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Update a cache's TTL or expiration time.
|
|
77
|
+
*/
|
|
78
|
+
updateCache(name: string, update: {
|
|
79
|
+
ttl?: string;
|
|
80
|
+
expireTime?: string;
|
|
81
|
+
}, apiKey: string, signal?: AbortSignal): Promise<GeminiCachedContent>;
|
|
82
|
+
/**
|
|
83
|
+
* Delete a cached content resource.
|
|
84
|
+
*/
|
|
85
|
+
deleteCache(name: string, apiKey: string, signal?: AbortSignal): Promise<void>;
|
|
86
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GeminiCacheAPI 鈥?Explicit Context Caching for Gemini generateContent.
|
|
3
|
+
*
|
|
4
|
+
* Manages named cached content resources that can be referenced in
|
|
5
|
+
* generateContent requests via the `cachedContent` field.
|
|
6
|
+
*
|
|
7
|
+
* REST endpoints:
|
|
8
|
+
* POST /v1beta/cachedContents 鈥?create cache
|
|
9
|
+
* GET /v1beta/cachedContents 鈥?list caches
|
|
10
|
+
* GET /v1beta/cachedContents/{name} 鈥?get cache metadata
|
|
11
|
+
* PATCH /v1beta/cachedContents/{name} 鈥?update TTL
|
|
12
|
+
* DELETE /v1beta/cachedContents/{name} 鈥?delete cache
|
|
13
|
+
*
|
|
14
|
+
* Minimum cacheable content: 1024 tokens (Flash) / 4096 tokens (Pro).
|
|
15
|
+
* TTL default: 1 hour. Storage: ~$1.00/hour/MTok (Flash series).
|
|
16
|
+
*
|
|
17
|
+
* Docs: https://ai.google.dev/gemini-api/docs/caching
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
20
|
+
// 鈹€鈹€ API Client 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
21
|
+
export class GeminiCacheAPI {
|
|
22
|
+
baseUrl;
|
|
23
|
+
timeoutMs;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
26
|
+
this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create a new cached content resource.
|
|
30
|
+
* The cache name returned can be passed as `cachedContent` in generateContent.
|
|
31
|
+
*/
|
|
32
|
+
async createCache(options, apiKey, signal) {
|
|
33
|
+
const url = `${this.baseUrl}/cachedContents`;
|
|
34
|
+
const body = {
|
|
35
|
+
model: options.model.startsWith("models/") ? options.model : `models/${options.model}`,
|
|
36
|
+
contents: options.contents,
|
|
37
|
+
};
|
|
38
|
+
if (options.systemInstruction) {
|
|
39
|
+
body.systemInstruction = options.systemInstruction;
|
|
40
|
+
}
|
|
41
|
+
if (options.ttl)
|
|
42
|
+
body.ttl = options.ttl;
|
|
43
|
+
if (options.displayName)
|
|
44
|
+
body.displayName = options.displayName;
|
|
45
|
+
const res = await fetch(url, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
"x-goog-api-key": apiKey,
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify(body),
|
|
52
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
53
|
+
});
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
const text = await res.text().catch(() => "");
|
|
56
|
+
throw new Error(`Gemini cache create error ${res.status}: ${text.slice(0, 500)}`);
|
|
57
|
+
}
|
|
58
|
+
return (await res.json());
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get metadata for a cached content resource.
|
|
62
|
+
*/
|
|
63
|
+
async getCache(name, apiKey, signal) {
|
|
64
|
+
const url = `${this.baseUrl}/${name}`;
|
|
65
|
+
const res = await fetch(url, {
|
|
66
|
+
method: "GET",
|
|
67
|
+
headers: { "x-goog-api-key": apiKey },
|
|
68
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
69
|
+
});
|
|
70
|
+
if (!res.ok) {
|
|
71
|
+
const text = await res.text().catch(() => "");
|
|
72
|
+
throw new Error(`Gemini cache get error ${res.status}: ${text.slice(0, 500)}`);
|
|
73
|
+
}
|
|
74
|
+
return (await res.json());
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* List all cached content resources.
|
|
78
|
+
*/
|
|
79
|
+
async listCaches(apiKey, options, signal) {
|
|
80
|
+
const params = new URLSearchParams();
|
|
81
|
+
if (options?.pageSize)
|
|
82
|
+
params.set("pageSize", String(options.pageSize));
|
|
83
|
+
if (options?.pageToken)
|
|
84
|
+
params.set("pageToken", options.pageToken);
|
|
85
|
+
const url = `${this.baseUrl}/cachedContents?${params.toString()}`;
|
|
86
|
+
const res = await fetch(url, {
|
|
87
|
+
method: "GET",
|
|
88
|
+
headers: { "x-goog-api-key": apiKey },
|
|
89
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
90
|
+
});
|
|
91
|
+
if (!res.ok) {
|
|
92
|
+
const text = await res.text().catch(() => "");
|
|
93
|
+
throw new Error(`Gemini cache list error ${res.status}: ${text.slice(0, 500)}`);
|
|
94
|
+
}
|
|
95
|
+
const data = (await res.json());
|
|
96
|
+
return {
|
|
97
|
+
cachedContents: data.cachedContents ?? [],
|
|
98
|
+
nextPageToken: data.nextPageToken,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Update a cache's TTL or expiration time.
|
|
103
|
+
*/
|
|
104
|
+
async updateCache(name, update, apiKey, signal) {
|
|
105
|
+
const url = `${this.baseUrl}/${name}`;
|
|
106
|
+
const body = {};
|
|
107
|
+
if (update.ttl)
|
|
108
|
+
body.ttl = update.ttl;
|
|
109
|
+
if (update.expireTime)
|
|
110
|
+
body.expireTime = update.expireTime;
|
|
111
|
+
const res = await fetch(url, {
|
|
112
|
+
method: "PATCH",
|
|
113
|
+
headers: {
|
|
114
|
+
"Content-Type": "application/json",
|
|
115
|
+
"x-goog-api-key": apiKey,
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify(body),
|
|
118
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
119
|
+
});
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
const text = await res.text().catch(() => "");
|
|
122
|
+
throw new Error(`Gemini cache update error ${res.status}: ${text.slice(0, 500)}`);
|
|
123
|
+
}
|
|
124
|
+
return (await res.json());
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Delete a cached content resource.
|
|
128
|
+
*/
|
|
129
|
+
async deleteCache(name, apiKey, signal) {
|
|
130
|
+
const url = `${this.baseUrl}/${name}`;
|
|
131
|
+
const res = await fetch(url, {
|
|
132
|
+
method: "DELETE",
|
|
133
|
+
headers: { "x-goog-api-key": apiKey },
|
|
134
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
135
|
+
});
|
|
136
|
+
if (!res.ok) {
|
|
137
|
+
const text = await res.text().catch(() => "");
|
|
138
|
+
throw new Error(`Gemini cache delete error ${res.status}: ${text.slice(0, 500)}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GeminiFileAPI 鈥?Gemini File API for uploading and managing files.
|
|
3
|
+
*
|
|
4
|
+
* Files uploaded via this API can be referenced in generateContent requests
|
|
5
|
+
* using `file_data: { file_uri, mime_type }` parts.
|
|
6
|
+
*
|
|
7
|
+
* Upload uses the resumable upload protocol (2-step):
|
|
8
|
+
* 1. POST /upload/v1beta/files 鈫?get upload URL (response header)
|
|
9
|
+
* 2. PUT {upload_url} with file bytes 鈫?get file info
|
|
10
|
+
*
|
|
11
|
+
* Other operations:
|
|
12
|
+
* GET /v1beta/files 鈥?list files
|
|
13
|
+
* GET /v1beta/files/{name} 鈥?get file metadata
|
|
14
|
+
* DELETE /v1beta/files/{name} 鈥?delete file
|
|
15
|
+
*
|
|
16
|
+
* Files expire after 48 hours. Max 2GB per file, 20GB per project.
|
|
17
|
+
*
|
|
18
|
+
* Docs: https://ai.google.dev/gemini-api/docs/files
|
|
19
|
+
*/
|
|
20
|
+
export interface GeminiFileInfo {
|
|
21
|
+
/** Resource name, e.g. "files/abc123" */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Display name (set during upload) */
|
|
24
|
+
displayName?: string;
|
|
25
|
+
/** MIME type */
|
|
26
|
+
mimeType: string;
|
|
27
|
+
/** File size in bytes */
|
|
28
|
+
sizeBytes?: string;
|
|
29
|
+
/** File URI for use in generateContent, e.g. "https://generativelanguage.googleapis.com/v1beta/files/abc123" */
|
|
30
|
+
uri: string;
|
|
31
|
+
/** Processing state: PROCESSING | ACTIVE | FAILED */
|
|
32
|
+
state: string;
|
|
33
|
+
/** Creation time (ISO 8601) */
|
|
34
|
+
createTime?: string;
|
|
35
|
+
/** Last update time (ISO 8601) */
|
|
36
|
+
updateTime?: string;
|
|
37
|
+
/** Expiration time (ISO 8601) */
|
|
38
|
+
expirationTime?: string;
|
|
39
|
+
/** Error info if state is FAILED */
|
|
40
|
+
error?: {
|
|
41
|
+
code: number;
|
|
42
|
+
message: string;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export declare class GeminiFileAPI {
|
|
46
|
+
private baseUrl;
|
|
47
|
+
private timeoutMs;
|
|
48
|
+
constructor(config: {
|
|
49
|
+
baseUrl: string;
|
|
50
|
+
timeoutMs?: number;
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Upload a file using the resumable upload protocol.
|
|
54
|
+
*
|
|
55
|
+
* Step 1: Initiate upload 鈫?get upload URL from response header
|
|
56
|
+
* Step 2: Upload bytes to that URL 鈫?get file metadata
|
|
57
|
+
*
|
|
58
|
+
* @returns GeminiFileInfo with .uri for use in generateContent
|
|
59
|
+
*/
|
|
60
|
+
uploadFile(file: Blob | Buffer, apiKey: string, options?: {
|
|
61
|
+
mimeType?: string;
|
|
62
|
+
displayName?: string;
|
|
63
|
+
}, signal?: AbortSignal): Promise<GeminiFileInfo>;
|
|
64
|
+
/**
|
|
65
|
+
* Wait for a file to finish processing (state 鈫?ACTIVE).
|
|
66
|
+
* Some file types (video, audio) require server-side processing.
|
|
67
|
+
*/
|
|
68
|
+
waitForProcessing(name: string, apiKey: string, options?: {
|
|
69
|
+
pollIntervalMs?: number;
|
|
70
|
+
maxWaitMs?: number;
|
|
71
|
+
}): Promise<GeminiFileInfo>;
|
|
72
|
+
/**
|
|
73
|
+
* Get metadata for an uploaded file.
|
|
74
|
+
*/
|
|
75
|
+
getFile(name: string, apiKey: string, signal?: AbortSignal): Promise<GeminiFileInfo>;
|
|
76
|
+
/**
|
|
77
|
+
* List uploaded files.
|
|
78
|
+
*/
|
|
79
|
+
listFiles(apiKey: string, options?: {
|
|
80
|
+
pageSize?: number;
|
|
81
|
+
pageToken?: string;
|
|
82
|
+
}, signal?: AbortSignal): Promise<{
|
|
83
|
+
files: GeminiFileInfo[];
|
|
84
|
+
nextPageToken?: string;
|
|
85
|
+
}>;
|
|
86
|
+
/**
|
|
87
|
+
* Delete an uploaded file.
|
|
88
|
+
*/
|
|
89
|
+
deleteFile(name: string, apiKey: string, signal?: AbortSignal): Promise<void>;
|
|
90
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GeminiFileAPI 鈥?Gemini File API for uploading and managing files.
|
|
3
|
+
*
|
|
4
|
+
* Files uploaded via this API can be referenced in generateContent requests
|
|
5
|
+
* using `file_data: { file_uri, mime_type }` parts.
|
|
6
|
+
*
|
|
7
|
+
* Upload uses the resumable upload protocol (2-step):
|
|
8
|
+
* 1. POST /upload/v1beta/files 鈫?get upload URL (response header)
|
|
9
|
+
* 2. PUT {upload_url} with file bytes 鈫?get file info
|
|
10
|
+
*
|
|
11
|
+
* Other operations:
|
|
12
|
+
* GET /v1beta/files 鈥?list files
|
|
13
|
+
* GET /v1beta/files/{name} 鈥?get file metadata
|
|
14
|
+
* DELETE /v1beta/files/{name} 鈥?delete file
|
|
15
|
+
*
|
|
16
|
+
* Files expire after 48 hours. Max 2GB per file, 20GB per project.
|
|
17
|
+
*
|
|
18
|
+
* Docs: https://ai.google.dev/gemini-api/docs/files
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_TIMEOUT_MS = 300_000; // 5 min for uploads
|
|
21
|
+
// 鈹€鈹€ API Client 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
22
|
+
export class GeminiFileAPI {
|
|
23
|
+
baseUrl;
|
|
24
|
+
timeoutMs;
|
|
25
|
+
constructor(config) {
|
|
26
|
+
// baseUrl should be e.g. "https://generativelanguage.googleapis.com/v1beta"
|
|
27
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
28
|
+
this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Upload a file using the resumable upload protocol.
|
|
32
|
+
*
|
|
33
|
+
* Step 1: Initiate upload 鈫?get upload URL from response header
|
|
34
|
+
* Step 2: Upload bytes to that URL 鈫?get file metadata
|
|
35
|
+
*
|
|
36
|
+
* @returns GeminiFileInfo with .uri for use in generateContent
|
|
37
|
+
*/
|
|
38
|
+
async uploadFile(file, apiKey, options, signal) {
|
|
39
|
+
const bytes = file instanceof Blob ? Buffer.from(await file.arrayBuffer()) : file;
|
|
40
|
+
const mimeType = options?.mimeType ?? "application/octet-stream";
|
|
41
|
+
const displayName = options?.displayName ?? "upload";
|
|
42
|
+
// Derive the upload base from our API base
|
|
43
|
+
// e.g. "https://generativelanguage.googleapis.com/v1beta"
|
|
44
|
+
// 鈫?"https://generativelanguage.googleapis.com/upload/v1beta/files"
|
|
45
|
+
const uploadInitUrl = this.baseUrl.replace(/(\/v1beta)$/, "/upload$1/files");
|
|
46
|
+
// Step 1: Initiate resumable upload
|
|
47
|
+
const initRes = await fetch(uploadInitUrl, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
headers: {
|
|
50
|
+
"x-goog-api-key": apiKey,
|
|
51
|
+
"X-Goog-Upload-Protocol": "resumable",
|
|
52
|
+
"X-Goog-Upload-Command": "start",
|
|
53
|
+
"X-Goog-Upload-Header-Content-Length": String(bytes.length),
|
|
54
|
+
"X-Goog-Upload-Header-Content-Type": mimeType,
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
file: { display_name: displayName },
|
|
59
|
+
}),
|
|
60
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
61
|
+
});
|
|
62
|
+
if (!initRes.ok) {
|
|
63
|
+
const text = await initRes.text().catch(() => "");
|
|
64
|
+
throw new Error(`Gemini file upload init error ${initRes.status}: ${text.slice(0, 500)}`);
|
|
65
|
+
}
|
|
66
|
+
// Extract upload URL from response header
|
|
67
|
+
const uploadUrl = initRes.headers.get("x-goog-upload-url");
|
|
68
|
+
if (!uploadUrl) {
|
|
69
|
+
throw new Error("Gemini file upload: missing x-goog-upload-url in response headers");
|
|
70
|
+
}
|
|
71
|
+
// Step 2: Upload the actual bytes
|
|
72
|
+
const uploadRes = await fetch(uploadUrl, {
|
|
73
|
+
method: "PUT",
|
|
74
|
+
headers: {
|
|
75
|
+
"Content-Length": String(bytes.length),
|
|
76
|
+
"X-Goog-Upload-Offset": "0",
|
|
77
|
+
"X-Goog-Upload-Command": "upload, finalize",
|
|
78
|
+
},
|
|
79
|
+
body: bytes,
|
|
80
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
81
|
+
});
|
|
82
|
+
if (!uploadRes.ok) {
|
|
83
|
+
const text = await uploadRes.text().catch(() => "");
|
|
84
|
+
throw new Error(`Gemini file upload error ${uploadRes.status}: ${text.slice(0, 500)}`);
|
|
85
|
+
}
|
|
86
|
+
const data = (await uploadRes.json());
|
|
87
|
+
return data.file;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Wait for a file to finish processing (state 鈫?ACTIVE).
|
|
91
|
+
* Some file types (video, audio) require server-side processing.
|
|
92
|
+
*/
|
|
93
|
+
async waitForProcessing(name, apiKey, options) {
|
|
94
|
+
const pollInterval = options?.pollIntervalMs ?? 2500;
|
|
95
|
+
const maxWait = options?.maxWaitMs ?? 120_000;
|
|
96
|
+
const start = Date.now();
|
|
97
|
+
while (Date.now() - start < maxWait) {
|
|
98
|
+
const file = await this.getFile(name, apiKey);
|
|
99
|
+
if (file.state === "ACTIVE")
|
|
100
|
+
return file;
|
|
101
|
+
if (file.state === "FAILED") {
|
|
102
|
+
throw new Error(`Gemini file processing failed: ${file.error?.message ?? "unknown error"}`);
|
|
103
|
+
}
|
|
104
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
105
|
+
}
|
|
106
|
+
throw new Error(`Gemini file processing timed out after ${maxWait}ms`);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get metadata for an uploaded file.
|
|
110
|
+
*/
|
|
111
|
+
async getFile(name, apiKey, signal) {
|
|
112
|
+
const url = `${this.baseUrl}/${name}`;
|
|
113
|
+
const res = await fetch(url, {
|
|
114
|
+
method: "GET",
|
|
115
|
+
headers: { "x-goog-api-key": apiKey },
|
|
116
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
117
|
+
});
|
|
118
|
+
if (!res.ok) {
|
|
119
|
+
const text = await res.text().catch(() => "");
|
|
120
|
+
throw new Error(`Gemini file get error ${res.status}: ${text.slice(0, 500)}`);
|
|
121
|
+
}
|
|
122
|
+
return (await res.json());
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* List uploaded files.
|
|
126
|
+
*/
|
|
127
|
+
async listFiles(apiKey, options, signal) {
|
|
128
|
+
const params = new URLSearchParams();
|
|
129
|
+
if (options?.pageSize)
|
|
130
|
+
params.set("pageSize", String(options.pageSize));
|
|
131
|
+
if (options?.pageToken)
|
|
132
|
+
params.set("pageToken", options.pageToken);
|
|
133
|
+
const url = `${this.baseUrl}/files?${params.toString()}`;
|
|
134
|
+
const res = await fetch(url, {
|
|
135
|
+
method: "GET",
|
|
136
|
+
headers: { "x-goog-api-key": apiKey },
|
|
137
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
138
|
+
});
|
|
139
|
+
if (!res.ok) {
|
|
140
|
+
const text = await res.text().catch(() => "");
|
|
141
|
+
throw new Error(`Gemini file list error ${res.status}: ${text.slice(0, 500)}`);
|
|
142
|
+
}
|
|
143
|
+
const data = (await res.json());
|
|
144
|
+
return {
|
|
145
|
+
files: data.files ?? [],
|
|
146
|
+
nextPageToken: data.nextPageToken,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Delete an uploaded file.
|
|
151
|
+
*/
|
|
152
|
+
async deleteFile(name, apiKey, signal) {
|
|
153
|
+
const url = `${this.baseUrl}/${name}`;
|
|
154
|
+
const res = await fetch(url, {
|
|
155
|
+
method: "DELETE",
|
|
156
|
+
headers: { "x-goog-api-key": apiKey },
|
|
157
|
+
signal: signal ?? AbortSignal.timeout(this.timeoutMs),
|
|
158
|
+
});
|
|
159
|
+
if (!res.ok) {
|
|
160
|
+
const text = await res.text().catch(() => "");
|
|
161
|
+
throw new Error(`Gemini file delete error ${res.status}: ${text.slice(0, 500)}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini generateContent TransportNative Gemini API streaming implementation.
|
|
3
|
+
*
|
|
4
|
+
* Targets Gemini 3 series exclusively (3.1 Pro, 3 Flash, 3.1 Flash-Lite).
|
|
5
|
+
* Uses the native Gemini REST API instead of the OpenAI compatibility layer,
|
|
6
|
+
* unlocking Gemini-exclusive features unavailable via the compat endpoint:
|
|
7
|
+
* - thinkingConfig (thinkingLevelG3 native control)
|
|
8
|
+
* - Google Search / Maps Grounding
|
|
9
|
+
* - Code Execution
|
|
10
|
+
* - Safety Settings fine-grained control
|
|
11
|
+
* - Thought Signatures for multi-turn reasoning continuity
|
|
12
|
+
* - URL Context / File Search
|
|
13
|
+
* - systemInstruction top-level field
|
|
14
|
+
*
|
|
15
|
+
* Streaming endpoint: POST .../models/{model}:streamGenerateContent?alt=sse
|
|
16
|
+
* Non-streaming: POST .../models/{model}:generateContent
|
|
17
|
+
* Auth: x-goog-api-key header
|
|
18
|
+
*
|
|
19
|
+
* Protocol reference: https://ai.google.dev/gemini-api/docs
|
|
20
|
+
* Aligned with gemini-ProviderMax.md native protocol strategy.
|
|
21
|
+
*/
|
|
22
|
+
import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
|
|
23
|
+
import type { ProviderQuirks } from "../provider-def.js";
|
|
24
|
+
import type { FileUploadAdapter } from "../file-upload-service.js";
|
|
25
|
+
export interface GeminiGenerateContentTransportConfig {
|
|
26
|
+
/** Base URL, e.g. "https://generativelanguage.googleapis.com/v1beta" */
|
|
27
|
+
baseUrl: string;
|
|
28
|
+
/** Per-request timeout in ms (default 180_000) */
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
/** Provider-specific quirks */
|
|
31
|
+
quirks?: ProviderQuirks;
|
|
32
|
+
/** File upload adapter for resolving local media URLs via upload instead of base64. */
|
|
33
|
+
fileUploadAdapter?: FileUploadAdapter;
|
|
34
|
+
}
|
|
35
|
+
export declare class GeminiGenerateContentTransport implements LLMTransport {
|
|
36
|
+
private baseUrl;
|
|
37
|
+
private timeoutMs;
|
|
38
|
+
private quirks;
|
|
39
|
+
private fileUploadAdapter?;
|
|
40
|
+
constructor(config: GeminiGenerateContentTransportConfig);
|
|
41
|
+
stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
|
|
42
|
+
private buildRequestBody;
|
|
43
|
+
private buildTools;
|
|
44
|
+
private buildToolConfig;
|
|
45
|
+
private buildGenerationConfig;
|
|
46
|
+
private fetchAndStream;
|
|
47
|
+
/**
|
|
48
|
+
* Parse SSE stream with 90s idle watchdog (CC parity).
|
|
49
|
+
*/
|
|
50
|
+
private parseSSEStreamWithWatchdog;
|
|
51
|
+
/**
|
|
52
|
+
* Process a single Gemini response chunk, yielding LLMChunk events.
|
|
53
|
+
*/
|
|
54
|
+
private processResponse;
|
|
55
|
+
private nonStreamingFallback;
|
|
56
|
+
}
|