@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.
Files changed (93) hide show
  1. package/dist/adapters/aliyun-oss-file-upload-adapter.d.ts +44 -0
  2. package/dist/adapters/aliyun-oss-file-upload-adapter.js +96 -0
  3. package/dist/adapters/gemini-file-upload-adapter.d.ts +26 -0
  4. package/dist/adapters/gemini-file-upload-adapter.js +92 -0
  5. package/dist/adapters/hub-oss-file-upload-adapter.d.ts +29 -0
  6. package/dist/adapters/hub-oss-file-upload-adapter.js +53 -0
  7. package/dist/adapters/index.d.ts +10 -0
  8. package/dist/adapters/index.js +10 -0
  9. package/dist/adapters/openai-file-upload-adapter.d.ts +38 -0
  10. package/dist/adapters/openai-file-upload-adapter.js +56 -0
  11. package/dist/adapters/volcengine-file-upload-adapter.d.ts +24 -0
  12. package/dist/adapters/volcengine-file-upload-adapter.js +45 -0
  13. package/dist/builtin-providers.d.ts +8 -0
  14. package/dist/builtin-providers.js +2237 -0
  15. package/dist/constants.d.ts +1 -0
  16. package/dist/constants.js +1 -0
  17. package/dist/credentials.d.ts +1 -0
  18. package/dist/credentials.js +8 -0
  19. package/dist/debug-transport.d.ts +12 -0
  20. package/dist/debug-transport.js +99 -0
  21. package/dist/errors.d.ts +11 -0
  22. package/dist/errors.js +12 -0
  23. package/dist/events.d.ts +48 -0
  24. package/dist/events.js +1 -0
  25. package/dist/file-upload-service.d.ts +68 -0
  26. package/dist/file-upload-service.js +110 -0
  27. package/dist/gemini-schema-utils.d.ts +17 -0
  28. package/dist/gemini-schema-utils.js +76 -0
  29. package/dist/index.d.ts +37 -0
  30. package/dist/index.js +33 -0
  31. package/dist/llm-client.d.ts +43 -0
  32. package/dist/llm-client.js +217 -0
  33. package/dist/media-client.d.ts +42 -0
  34. package/dist/media-client.js +174 -0
  35. package/dist/media-transport.d.ts +176 -0
  36. package/dist/media-transport.js +16 -0
  37. package/dist/media.d.ts +2 -0
  38. package/dist/media.js +1 -0
  39. package/dist/model-detection.d.ts +22 -0
  40. package/dist/model-detection.js +28 -0
  41. package/dist/paths.d.ts +2 -0
  42. package/dist/paths.js +11 -0
  43. package/dist/provider-def.d.ts +220 -0
  44. package/dist/provider-def.js +9 -0
  45. package/dist/provider-registry.d.ts +51 -0
  46. package/dist/provider-registry.js +130 -0
  47. package/dist/provider-tool-api.d.ts +44 -0
  48. package/dist/provider-tool-api.js +9 -0
  49. package/dist/provider-variant-resolver.d.ts +35 -0
  50. package/dist/provider-variant-resolver.js +174 -0
  51. package/dist/retry.d.ts +37 -0
  52. package/dist/retry.js +71 -0
  53. package/dist/transport.d.ts +281 -0
  54. package/dist/transport.js +27 -0
  55. package/dist/transports/anthropic-messages.d.ts +65 -0
  56. package/dist/transports/anthropic-messages.js +1004 -0
  57. package/dist/transports/gemini-cache-api.d.ts +86 -0
  58. package/dist/transports/gemini-cache-api.js +141 -0
  59. package/dist/transports/gemini-file-api.d.ts +90 -0
  60. package/dist/transports/gemini-file-api.js +164 -0
  61. package/dist/transports/gemini-generatecontent.d.ts +56 -0
  62. package/dist/transports/gemini-generatecontent.js +688 -0
  63. package/dist/transports/gemini-lyria-realtime.d.ts +117 -0
  64. package/dist/transports/gemini-lyria-realtime.js +295 -0
  65. package/dist/transports/gemini-media.d.ts +53 -0
  66. package/dist/transports/gemini-media.js +383 -0
  67. package/dist/transports/media-resolve.d.ts +50 -0
  68. package/dist/transports/media-resolve.js +91 -0
  69. package/dist/transports/minimax-media.d.ts +56 -0
  70. package/dist/transports/minimax-media.js +433 -0
  71. package/dist/transports/openai-chat.d.ts +81 -0
  72. package/dist/transports/openai-chat.js +782 -0
  73. package/dist/transports/openai-media.d.ts +24 -0
  74. package/dist/transports/openai-media.js +118 -0
  75. package/dist/transports/openai-responses.d.ts +63 -0
  76. package/dist/transports/openai-responses.js +778 -0
  77. package/dist/transports/qwen-media.d.ts +59 -0
  78. package/dist/transports/qwen-media.js +411 -0
  79. package/dist/transports/realtime-transport.d.ts +183 -0
  80. package/dist/transports/realtime-transport.js +332 -0
  81. package/dist/transports/volcengine-grounding.d.ts +58 -0
  82. package/dist/transports/volcengine-grounding.js +69 -0
  83. package/dist/transports/volcengine-media.d.ts +94 -0
  84. package/dist/transports/volcengine-media.js +801 -0
  85. package/dist/transports/volcengine-responses.d.ts +64 -0
  86. package/dist/transports/volcengine-responses.js +797 -0
  87. package/dist/transports/zhipu-media.d.ts +82 -0
  88. package/dist/transports/zhipu-media.js +522 -0
  89. package/dist/transports/zhipu-tool-api.d.ts +35 -0
  90. package/dist/transports/zhipu-tool-api.js +126 -0
  91. package/dist/wire-types.d.ts +51 -0
  92. package/dist/wire-types.js +1 -0
  93. 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
+ }