@chainfuse/ai-tools 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.
@@ -0,0 +1,215 @@
1
+ import { BufferHelpers, CryptoHelpers, Helpers } from '@chainfuse/helpers';
2
+ import { AiBase } from '../base.mjs';
3
+ export class AiRawProviders extends AiBase {
4
+ // 2628288 seconds is what cf defines as 1 month in their cache rules
5
+ cacheTtl = 2628288;
6
+ oaiOpenai(args) {
7
+ return import('@ai-sdk/openai').then(async ({ createOpenAI }) => createOpenAI({
8
+ baseURL: new URL(['v1', this.config.gateway.accountId, this.config.environment, 'openai'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
9
+ apiKey: this.config.providers.openAi.apiToken,
10
+ organization: this.config.providers.openAi.organization,
11
+ headers: {
12
+ 'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
13
+ 'cf-aig-metadata': JSON.stringify({
14
+ dataspaceId: (await BufferHelpers.uuidConvert(args.dataspaceId)).utf8,
15
+ executor: JSON.stringify(args.executor),
16
+ // Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
17
+ idempotencyId: args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
18
+ serverInfo: JSON.stringify({
19
+ name: 'openai',
20
+ }),
21
+ /**
22
+ * Blank at first, add after request finishes
23
+ * CF AI Gateway allows only editing existing metadata not creating new ones after the request is made
24
+ */
25
+ timing: JSON.stringify({}),
26
+ }),
27
+ ...(args.cache && { 'cf-aig-cache-ttl': (typeof args.cache === 'boolean' ? (args.cache ? this.cacheTtl : 0) : args.cache).toString() }),
28
+ ...(args.skipCache && { 'cf-aig-skip-cache': 'true' }),
29
+ },
30
+ compatibility: 'strict',
31
+ fetch: async (input, rawInit) => {
32
+ const headers = new Headers(rawInit?.headers);
33
+ const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
34
+ if (metadataHeader.idempotencyId.split('-').length === 4) {
35
+ metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
36
+ headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
37
+ }
38
+ if (args.logging ?? this.config.environment !== 'production')
39
+ console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), this.chalk.magenta(rawInit?.method), this.chalk.magenta(new URL(new Request(input).url).pathname));
40
+ return fetch(input, { ...rawInit, headers }).then(async (response) => {
41
+ if (args.logging ?? this.config.environment !== 'production')
42
+ console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), response.ok ? this.chalk.green(response.status) : this.chalk.red(response.status), response.ok ? this.chalk.green(new URL(response.url).pathname) : this.chalk.red(new URL(response.url).pathname));
43
+ // Inject it to have it available for retries
44
+ const mutableHeaders = new Headers(response.headers);
45
+ mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
46
+ if (response.ok) {
47
+ return new Response(response.body, { ...response, headers: mutableHeaders });
48
+ }
49
+ else {
50
+ const [body1, body2] = response.body.tee();
51
+ console.error('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), this.chalk.red(JSON.stringify(await new Response(body1, response).json())));
52
+ return new Response(body2, { ...response, headers: mutableHeaders });
53
+ }
54
+ });
55
+ },
56
+ }));
57
+ }
58
+ azOpenai(args, server) {
59
+ return import('@ai-sdk/azure').then(async ({ createAzure }) => createAzure({
60
+ apiKey: this.config.providers.azureOpenAi.apiTokens[`AZURE_API_KEY_${server.toUpperCase().replaceAll('-', '_')}`],
61
+ /**
62
+ * @link https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#api-specs
63
+ * From the table, pick the `Latest GA release` for `Data plane - inference`
64
+ */
65
+ apiVersion: '2024-10-21',
66
+ baseURL: new URL(['v1', this.config.gateway.accountId, this.config.environment, 'azure-openai', server.toLowerCase()].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
67
+ headers: {
68
+ 'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
69
+ 'cf-aig-metadata': JSON.stringify({
70
+ dataspaceId: (await BufferHelpers.uuidConvert(args.dataspaceId)).utf8,
71
+ executor: JSON.stringify(args.executor),
72
+ // Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
73
+ idempotencyId: args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
74
+ serverInfo: JSON.stringify({
75
+ name: 'openai',
76
+ }),
77
+ /**
78
+ * Blank at first, add after request finishes
79
+ * CF AI Gateway allows only editing existing metadata not creating new ones after the request is made
80
+ */
81
+ timing: JSON.stringify({}),
82
+ }),
83
+ ...(args.cache && { 'cf-aig-cache-ttl': (typeof args.cache === 'boolean' ? (args.cache ? this.cacheTtl : 0) : args.cache).toString() }),
84
+ ...(args.skipCache && { 'cf-aig-skip-cache': 'true' }),
85
+ },
86
+ fetch: async (input, rawInit) => {
87
+ const headers = new Headers(rawInit?.headers);
88
+ const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
89
+ if (metadataHeader.idempotencyId.split('-').length === 4) {
90
+ metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
91
+ headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
92
+ }
93
+ if (args.logging ?? this.config.environment !== 'production')
94
+ console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), this.chalk.magenta(rawInit?.method), this.chalk.magenta(new URL(new Request(input).url).pathname));
95
+ return fetch(input, { ...rawInit, headers }).then(async (response) => {
96
+ if (args.logging ?? this.config.environment !== 'production')
97
+ console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), response.ok ? this.chalk.green(response.status) : this.chalk.red(response.status), response.ok ? this.chalk.green(new URL(response.url).pathname) : this.chalk.red(new URL(response.url).pathname));
98
+ // Inject it to have it available for retries
99
+ const mutableHeaders = new Headers(response.headers);
100
+ mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
101
+ if (response.ok) {
102
+ return new Response(response.body, { ...response, headers: mutableHeaders });
103
+ }
104
+ else {
105
+ const [body1, body2] = response.body.tee();
106
+ console.error('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), this.chalk.red(JSON.stringify(await new Response(body1, response).json())));
107
+ return new Response(body2, { ...response, headers: mutableHeaders });
108
+ }
109
+ });
110
+ },
111
+ }));
112
+ }
113
+ anthropic(args) {
114
+ return import('@ai-sdk/anthropic').then(async ({ createAnthropic }) => createAnthropic({
115
+ baseURL: new URL(['v1', this.config.gateway.accountId, this.config.environment, 'anthropic'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
116
+ apiKey: this.config.providers.anthropic.apiToken,
117
+ headers: {
118
+ 'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
119
+ 'cf-aig-metadata': JSON.stringify({
120
+ dataspaceId: (await BufferHelpers.uuidConvert(args.dataspaceId)).utf8,
121
+ executor: JSON.stringify(args.executor),
122
+ // Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
123
+ idempotencyId: args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
124
+ serverInfo: JSON.stringify({
125
+ name: 'openai',
126
+ }),
127
+ /**
128
+ * Blank at first, add after request finishes
129
+ * CF AI Gateway allows only editing existing metadata not creating new ones after the request is made
130
+ */
131
+ timing: JSON.stringify({}),
132
+ }),
133
+ ...(args.cache && { 'cf-aig-cache-ttl': (typeof args.cache === 'boolean' ? (args.cache ? this.cacheTtl : 0) : args.cache).toString() }),
134
+ ...(args.skipCache && { 'cf-aig-skip-cache': 'true' }),
135
+ },
136
+ fetch: async (input, rawInit) => {
137
+ const headers = new Headers(rawInit?.headers);
138
+ const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
139
+ if (metadataHeader.idempotencyId.split('-').length === 4) {
140
+ metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
141
+ headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
142
+ }
143
+ if (args.logging ?? this.config.environment !== 'production')
144
+ console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), this.chalk.magenta(rawInit?.method), this.chalk.magenta(new URL(new Request(input).url).pathname));
145
+ return fetch(input, { ...rawInit, headers }).then(async (response) => {
146
+ if (args.logging ?? this.config.environment !== 'production')
147
+ console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), response.ok ? this.chalk.green(response.status) : this.chalk.red(response.status), response.ok ? this.chalk.green(new URL(response.url).pathname) : this.chalk.red(new URL(response.url).pathname));
148
+ // Inject it to have it available for retries
149
+ const mutableHeaders = new Headers(response.headers);
150
+ mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
151
+ if (response.ok) {
152
+ return new Response(response.body, { ...response, headers: mutableHeaders });
153
+ }
154
+ else {
155
+ const [body1, body2] = response.body.tee();
156
+ console.error('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), this.chalk.red(JSON.stringify(await new Response(body1, response).json())));
157
+ return new Response(body2, { ...response, headers: mutableHeaders });
158
+ }
159
+ });
160
+ },
161
+ }));
162
+ }
163
+ restWorkersAi(args) {
164
+ return import('@ai-sdk/openai').then(async ({ createOpenAI }) => createOpenAI({
165
+ baseURL: new URL(['v1', this.config.gateway.accountId, this.config.environment, 'workers-ai', 'v1'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
166
+ apiKey: this.config.providers.workersAi.apiToken,
167
+ headers: {
168
+ 'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
169
+ 'cf-aig-metadata': JSON.stringify({
170
+ dataspaceId: (await BufferHelpers.uuidConvert(args.dataspaceId)).utf8,
171
+ executor: JSON.stringify(args.executor),
172
+ // Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
173
+ idempotencyId: args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
174
+ serverInfo: JSON.stringify({
175
+ name: 'openai',
176
+ }),
177
+ /**
178
+ * Blank at first, add after request finishes
179
+ * CF AI Gateway allows only editing existing metadata not creating new ones after the request is made
180
+ */
181
+ timing: JSON.stringify({}),
182
+ }),
183
+ ...(args.cache && { 'cf-aig-cache-ttl': (typeof args.cache === 'boolean' ? (args.cache ? this.cacheTtl : 0) : args.cache).toString() }),
184
+ ...(args.skipCache && { 'cf-aig-skip-cache': 'true' }),
185
+ },
186
+ compatibility: 'compatible',
187
+ name: 'workersai',
188
+ fetch: async (input, rawInit) => {
189
+ const headers = new Headers(rawInit?.headers);
190
+ const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
191
+ if (metadataHeader.idempotencyId.split('-').length === 4) {
192
+ metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
193
+ headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
194
+ }
195
+ if (args.logging ?? this.config.environment !== 'production')
196
+ console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), this.chalk.magenta(rawInit?.method), this.chalk.magenta(new URL(new Request(input).url).pathname));
197
+ return fetch(input, { ...rawInit, headers }).then(async (response) => {
198
+ if (args.logging ?? this.config.environment !== 'production')
199
+ console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), response.ok ? this.chalk.green(response.status) : this.chalk.red(response.status), response.ok ? this.chalk.green(new URL(response.url).pathname) : this.chalk.red(new URL(response.url).pathname));
200
+ // Inject it to have it available for retries
201
+ const mutableHeaders = new Headers(response.headers);
202
+ mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
203
+ if (response.ok) {
204
+ return new Response(response.body, { ...response, headers: mutableHeaders });
205
+ }
206
+ else {
207
+ const [body1, body2] = response.body.tee();
208
+ console.error('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(metadataHeader.idempotencyId))(`[${metadataHeader.idempotencyId}]`), this.chalk.red(JSON.stringify(await new Response(body1, response).json())));
209
+ return new Response(body2, { ...response, headers: mutableHeaders });
210
+ }
211
+ });
212
+ },
213
+ }));
214
+ }
215
+ }
@@ -0,0 +1,26 @@
1
+ import type { OpenAIChatSettings, OpenAIEmbeddingSettings } from '@ai-sdk/openai/internal';
2
+ import type { EmbeddingModelV1, LanguageModelV1 } from '@ai-sdk/provider';
3
+ import type { AzureChatModels, AzureEmbeddingModels, cloudflareModelPossibilities } from '@chainfuse/types';
4
+ import type { Provider } from 'ai';
5
+ export interface AzureOpenAIProvider extends Provider {
6
+ (deploymentId: AzureChatModels, settings?: OpenAIChatSettings): LanguageModelV1;
7
+ /**
8
+ Creates an Azure OpenAI chat model for text generation.
9
+ */
10
+ languageModel(deploymentId: AzureChatModels, settings?: OpenAIChatSettings): LanguageModelV1;
11
+ /**
12
+ Creates an Azure OpenAI model for text embeddings.
13
+ */
14
+ textEmbeddingModel(deploymentId: AzureEmbeddingModels, settings?: OpenAIEmbeddingSettings): EmbeddingModelV1<string>;
15
+ }
16
+ export interface CloudflareOpenAIProvider extends Provider {
17
+ (deploymentId: cloudflareModelPossibilities<'Text Generation'>, settings?: OpenAIChatSettings): LanguageModelV1;
18
+ /**
19
+ Creates an Azure OpenAI chat model for text generation.
20
+ */
21
+ languageModel(deploymentId: cloudflareModelPossibilities<'Text Generation'>, settings?: OpenAIChatSettings): LanguageModelV1;
22
+ /**
23
+ Creates an Azure OpenAI model for text embeddings.
24
+ */
25
+ textEmbeddingModel(deploymentId: cloudflareModelPossibilities<'Text Embeddings'>, settings?: OpenAIEmbeddingSettings): EmbeddingModelV1<string>;
26
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import { AiBase } from './base.mjs';
2
+ import type { AiRequestConfig } from './types.mjs';
3
+ export declare class AiRegistry extends AiBase {
4
+ providers(args: AiRequestConfig): Promise<Readonly<{
5
+ openai: import("@ai-sdk/openai").OpenAIProvider;
6
+ azure: import("./providers/types.mjs").AzureOpenAIProvider;
7
+ anthropic: import("@ai-sdk/anthropic").AnthropicProvider;
8
+ workersai: import("./providers/types.mjs").CloudflareOpenAIProvider;
9
+ }>>;
10
+ registry(args: AiRequestConfig): Promise<import("ai").Provider>;
11
+ }
@@ -0,0 +1,16 @@
1
+ import { experimental_createProviderRegistry as createProviderRegistry } from 'ai';
2
+ import { AiBase } from './base.mjs';
3
+ import { AiCustomProviders } from './providers/customProviders.mjs';
4
+ export class AiRegistry extends AiBase {
5
+ async providers(args) {
6
+ return Object.freeze({
7
+ openai: await new AiCustomProviders(this.config).oaiOpenai(args),
8
+ azure: await new AiCustomProviders(this.config).azOpenai(args),
9
+ anthropic: await new AiCustomProviders(this.config).anthropic(args),
10
+ workersai: await new AiCustomProviders(this.config).cfWorkersAi(args),
11
+ });
12
+ }
13
+ async registry(args) {
14
+ return createProviderRegistry(await this.providers(args));
15
+ }
16
+ }
@@ -0,0 +1,5 @@
1
+ import { ServerSelector } from './base.mjs';
2
+ import type { Server } from './types.mjs';
3
+ export declare class AzureServerSelector extends ServerSelector {
4
+ readonly servers: Set<Server>;
5
+ }
@@ -0,0 +1,240 @@
1
+ import { PrivacyRegion, ServerSelector } from './base.mjs';
2
+ export class AzureServerSelector extends ServerSelector {
3
+ // From: https://gist.github.com/demosjarco/2091b3a197e530f1402e9dfec6666cd8
4
+ servers = new Set([
5
+ {
6
+ id: 'OpenAi-AU-NewSouthWales',
7
+ coordinate: {
8
+ lat: -33.86,
9
+ lon: 151.2094,
10
+ },
11
+ region: PrivacyRegion.Australian_Privacy_Principles,
12
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
13
+ textEmbeddingModelAvailability: [],
14
+ },
15
+ {
16
+ id: 'OpenAi-BR-SaoPauloState',
17
+ coordinate: {
18
+ lat: -23.55,
19
+ lon: -46.633,
20
+ },
21
+ region: PrivacyRegion.Brazil_General_Data_protection_Law,
22
+ languageModelAvailability: ['gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
23
+ textEmbeddingModelAvailability: [],
24
+ },
25
+ {
26
+ id: 'OpenAI-CA-Toronto',
27
+ coordinate: {
28
+ lat: 43.653,
29
+ lon: -79.383,
30
+ },
31
+ region: PrivacyRegion.Canada_Personal_Information_Protection_and_Electronic_Documents_Act,
32
+ languageModelAvailability: [],
33
+ textEmbeddingModelAvailability: [],
34
+ },
35
+ {
36
+ id: 'OpenAI-CA-Quebec',
37
+ coordinate: {
38
+ lat: 46.817,
39
+ lon: -71.217,
40
+ },
41
+ region: PrivacyRegion.Canada_Personal_Information_Protection_and_Electronic_Documents_Act,
42
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
43
+ textEmbeddingModelAvailability: ['text-embedding-3-small', 'text-embedding-3-large'],
44
+ },
45
+ {
46
+ id: 'OpenAi-US-Virginia',
47
+ coordinate: {
48
+ lat: 37.3719,
49
+ lon: -79.8164,
50
+ },
51
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
52
+ textEmbeddingModelAvailability: ['text-embedding-3-small', 'text-embedding-3-large'],
53
+ },
54
+ {
55
+ id: 'OpenAi-US-Virginia2',
56
+ coordinate: {
57
+ lat: 36.6681,
58
+ lon: -78.3889,
59
+ },
60
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
61
+ textEmbeddingModelAvailability: ['text-embedding-3-small', 'text-embedding-3-large'],
62
+ },
63
+ {
64
+ id: 'OpenAi-EU-Paris',
65
+ coordinate: {
66
+ lat: 46.3772,
67
+ lon: 2.373,
68
+ },
69
+ region: PrivacyRegion.General_Data_Protection_Regulation,
70
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
71
+ textEmbeddingModelAvailability: ['text-embedding-3-large'],
72
+ },
73
+ {
74
+ id: 'OpenAi-EU-Frankfurt',
75
+ coordinate: {
76
+ lat: 50.110924,
77
+ lon: 8.682127,
78
+ },
79
+ region: PrivacyRegion.General_Data_Protection_Regulation,
80
+ languageModelAvailability: ['gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
81
+ textEmbeddingModelAvailability: [],
82
+ },
83
+ {
84
+ id: 'OpenAi-JP-Tokyo',
85
+ coordinate: {
86
+ lat: 35.68,
87
+ lon: 139.77,
88
+ },
89
+ region: PrivacyRegion.Japan_Act_on_the_Protection_of_Personal_Information,
90
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
91
+ textEmbeddingModelAvailability: ['text-embedding-3-large'],
92
+ },
93
+ {
94
+ id: 'OpenAi-KR-Seoul',
95
+ coordinate: {
96
+ lat: 37.5665,
97
+ lon: 126.978,
98
+ },
99
+ region: PrivacyRegion.Korean_Personal_Information_Protection_Act,
100
+ languageModelAvailability: ['gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
101
+ textEmbeddingModelAvailability: [],
102
+ },
103
+ {
104
+ id: 'OpenAi-US-Illinois',
105
+ coordinate: {
106
+ lat: 41.8819,
107
+ lon: -87.6278,
108
+ },
109
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
110
+ textEmbeddingModelAvailability: [],
111
+ },
112
+ {
113
+ id: 'OpenAi-NO-Oslo',
114
+ coordinate: {
115
+ lat: 59.913868,
116
+ lon: 10.752245,
117
+ },
118
+ region: PrivacyRegion.Norwegian_Personal_Data_Act,
119
+ languageModelAvailability: ['gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
120
+ textEmbeddingModelAvailability: ['text-embedding-3-large'],
121
+ },
122
+ {
123
+ id: 'OpenAi-EU-Warsaw',
124
+ coordinate: {
125
+ lat: 52.23334,
126
+ lon: 21.01666,
127
+ },
128
+ region: PrivacyRegion.General_Data_Protection_Regulation,
129
+ languageModelAvailability: ['gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
130
+ textEmbeddingModelAvailability: [],
131
+ },
132
+ {
133
+ id: 'OpenAi-ZA-Johannesburg',
134
+ coordinate: {
135
+ lat: 28.21837,
136
+ lon: -25.73134,
137
+ },
138
+ region: PrivacyRegion.SouthAfrica_Protection_Personal_Information_Act,
139
+ languageModelAvailability: ['gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
140
+ textEmbeddingModelAvailability: [],
141
+ },
142
+ {
143
+ id: 'OpenAi-US-Texas',
144
+ coordinate: {
145
+ lat: 29.4167,
146
+ lon: -98.5,
147
+ },
148
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
149
+ textEmbeddingModelAvailability: [],
150
+ },
151
+ {
152
+ id: 'OpenAi-IN-Chennai',
153
+ coordinate: {
154
+ lat: 12.9822,
155
+ lon: 80.1636,
156
+ },
157
+ region: PrivacyRegion.Indian_Personal_Protection,
158
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
159
+ textEmbeddingModelAvailability: ['text-embedding-3-large'],
160
+ },
161
+ {
162
+ id: 'OpenAi-EU-Gavle',
163
+ coordinate: {
164
+ lat: 60.67488,
165
+ lon: 17.14127,
166
+ },
167
+ region: PrivacyRegion.General_Data_Protection_Regulation,
168
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o-mini', 'gpt-4o'],
169
+ textEmbeddingModelAvailability: ['text-embedding-3-large'],
170
+ },
171
+ {
172
+ id: 'OpenAi-EU-Madrid',
173
+ coordinate: {
174
+ lat: 3.4209,
175
+ lon: 40.4259,
176
+ },
177
+ region: PrivacyRegion.General_Data_Protection_Regulation,
178
+ languageModelAvailability: ['gpt-4-turbo', 'gpt-4o'],
179
+ textEmbeddingModelAvailability: [],
180
+ },
181
+ {
182
+ id: 'OpenAi-CH-Geneva',
183
+ coordinate: {
184
+ lat: 46.204391,
185
+ lon: 6.143158,
186
+ },
187
+ region: PrivacyRegion.Swiss_Federal_Act_on_Data_Protection,
188
+ languageModelAvailability: [],
189
+ textEmbeddingModelAvailability: [],
190
+ },
191
+ {
192
+ id: 'OpenAi-CH-Zurich',
193
+ coordinate: {
194
+ lat: 47.451542,
195
+ lon: 8.564572,
196
+ },
197
+ region: PrivacyRegion.Swiss_Federal_Act_on_Data_Protection,
198
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
199
+ textEmbeddingModelAvailability: [],
200
+ },
201
+ {
202
+ id: 'OpenAi-UK-London',
203
+ coordinate: {
204
+ lat: 50.941,
205
+ lon: -0.799,
206
+ },
207
+ region: PrivacyRegion.UK_General_Data_Protection_Regulation,
208
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
209
+ textEmbeddingModelAvailability: ['text-embedding-3-large'],
210
+ },
211
+ {
212
+ id: 'OpenAi-EU-Netherlands',
213
+ coordinate: {
214
+ lat: 52.3667,
215
+ lon: 4.9,
216
+ },
217
+ region: PrivacyRegion.General_Data_Protection_Regulation,
218
+ languageModelAvailability: ['gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
219
+ textEmbeddingModelAvailability: [],
220
+ },
221
+ {
222
+ id: 'OpenAi-US-California',
223
+ coordinate: {
224
+ lat: 37.783,
225
+ lon: -122.417,
226
+ },
227
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
228
+ textEmbeddingModelAvailability: [],
229
+ },
230
+ {
231
+ id: 'OpenAi-US-Phoenix',
232
+ coordinate: {
233
+ lat: 33.448376,
234
+ lon: -112.074036,
235
+ },
236
+ languageModelAvailability: ['gpt-35-turbo', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini'],
237
+ textEmbeddingModelAvailability: ['text-embedding-3-large'],
238
+ },
239
+ ]);
240
+ }
@@ -0,0 +1,22 @@
1
+ import type { RawCoordinate } from '@chainfuse/types';
2
+ import type { IncomingRequestCfProperties } from '@cloudflare/workers-types/experimental';
3
+ import { AiBase } from '../base.mjs';
4
+ import type { Server } from './types.mjs';
5
+ export declare enum PrivacyRegion {
6
+ Australian_Privacy_Principles = "APPs",
7
+ Brazil_General_Data_protection_Law = "LGPD",
8
+ Canada_Personal_Information_Protection_and_Electronic_Documents_Act = "PIPEDA",
9
+ General_Data_Protection_Regulation = "GDPR",
10
+ Indian_Personal_Protection = "PDP",
11
+ Japan_Act_on_the_Protection_of_Personal_Information = "APPI",
12
+ Korean_Personal_Information_Protection_Act = "PIPA",
13
+ Norwegian_Personal_Data_Act = "NPDA",
14
+ SouthAfrica_Protection_Personal_Information_Act = "PoPIA",
15
+ Swiss_Federal_Act_on_Data_Protection = "revFADP",
16
+ UK_General_Data_Protection_Regulation = "UK-GDPR"
17
+ }
18
+ export declare abstract class ServerSelector extends AiBase {
19
+ readonly servers: Set<Server>;
20
+ static determinePrivacyRegion(country?: IncomingRequestCfProperties['country'], continent?: IncomingRequestCfProperties['continent']): PrivacyRegion[];
21
+ closestServers(requiredCapability?: (Server['languageModelAvailability'] | Server['textEmbeddingModelAvailability'])[number], userCoordinate?: RawCoordinate, privacyRegion?: PrivacyRegion[]): Server[];
22
+ }