@chainfuse/ai-tools 0.1.2 → 0.2.1
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/base.mjs +1 -1
- package/dist/providers/customProviders.d.mts +6 -2
- package/dist/providers/customProviders.mjs +21 -11
- package/dist/providers/rawProviders.d.mts +8 -2
- package/dist/providers/rawProviders.mjs +210 -8
- package/dist/providers/types.d.mts +1 -12
- package/dist/registry.d.mts +3 -1
- package/dist/registry.mjs +2 -0
- package/dist/types.d.mts +22 -3
- package/package.json +11 -9
package/dist/base.mjs
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import type { GoogleGenerativeAIProvider } from '@ai-sdk/google';
|
|
2
|
+
import type { OpenAICompatibleProvider } from '@ai-sdk/openai-compatible';
|
|
1
3
|
import { AiBase } from '../base.mjs';
|
|
2
4
|
import type { AiRequestConfig } from '../types.mjs';
|
|
3
|
-
import type { AzureOpenAIProvider
|
|
5
|
+
import type { AzureOpenAIProvider } from './types.mjs';
|
|
4
6
|
export declare class AiCustomProviders extends AiBase {
|
|
5
7
|
oaiOpenai(args: AiRequestConfig): Promise<import("@ai-sdk/openai").OpenAIProvider>;
|
|
6
8
|
azOpenai(args: AiRequestConfig, [server, ...servers]?: import("../serverSelector/types.mjs").Server[]): Promise<AzureOpenAIProvider>;
|
|
7
9
|
anthropic(args: AiRequestConfig): Promise<import("@ai-sdk/anthropic").AnthropicProvider>;
|
|
8
10
|
private static workersAiIsRest;
|
|
9
|
-
cfWorkersAi(args: AiRequestConfig): Promise<
|
|
11
|
+
cfWorkersAi(args: AiRequestConfig): Promise<OpenAICompatibleProvider<"@cf/meta/llama-2-7b-chat-int8" | "@cf/mistral/mistral-7b-instruct-v0.1" | "@cf/meta/llama-2-7b-chat-fp16" | "@hf/thebloke/llama-2-13b-chat-awq" | "@hf/thebloke/mistral-7b-instruct-v0.1-awq" | "@hf/thebloke/zephyr-7b-beta-awq" | "@hf/thebloke/openhermes-2.5-mistral-7b-awq" | "@hf/thebloke/neural-chat-7b-v3-1-awq" | "@hf/thebloke/llamaguard-7b-awq" | "@hf/thebloke/deepseek-coder-6.7b-base-awq" | "@hf/thebloke/deepseek-coder-6.7b-instruct-awq" | "@cf/deepseek-ai/deepseek-math-7b-instruct" | "@cf/defog/sqlcoder-7b-2" | "@cf/openchat/openchat-3.5-0106" | "@cf/tiiuae/falcon-7b-instruct" | "@cf/thebloke/discolm-german-7b-v1-awq" | "@cf/qwen/qwen1.5-0.5b-chat" | "@cf/qwen/qwen1.5-7b-chat-awq" | "@cf/qwen/qwen1.5-14b-chat-awq" | "@cf/tinyllama/tinyllama-1.1b-chat-v1.0" | "@cf/microsoft/phi-2" | "@cf/qwen/qwen1.5-1.8b-chat" | "@cf/mistral/mistral-7b-instruct-v0.2-lora" | "@hf/nousresearch/hermes-2-pro-mistral-7b" | "@hf/nexusflow/starling-lm-7b-beta" | "@hf/google/gemma-7b-it" | "@cf/meta-llama/llama-2-7b-chat-hf-lora" | "@cf/google/gemma-2b-it-lora" | "@cf/google/gemma-7b-it-lora" | "@hf/mistral/mistral-7b-instruct-v0.2" | "@cf/meta/llama-3-8b-instruct" | "@cf/fblgit/una-cybertron-7b-v2-bf16" | "@cf/meta/llama-3-8b-instruct-awq" | "@hf/meta-llama/meta-llama-3-8b-instruct" | "@cf/meta/llama-3.1-8b-instruct" | "@cf/meta/llama-3.1-8b-instruct-fp8" | "@cf/meta/llama-3.1-8b-instruct-awq" | "@cf/meta/llama-3.2-3b-instruct" | "@cf/meta/llama-3.2-1b-instruct" | "@cf/meta/llama-3.3-70b-instruct-fp8-fast" | "@cf/meta/llama-3.2-11b-vision-instruct", "@cf/meta/llama-2-7b-chat-int8" | "@cf/mistral/mistral-7b-instruct-v0.1" | "@cf/meta/llama-2-7b-chat-fp16" | "@hf/thebloke/llama-2-13b-chat-awq" | "@hf/thebloke/mistral-7b-instruct-v0.1-awq" | "@hf/thebloke/zephyr-7b-beta-awq" | "@hf/thebloke/openhermes-2.5-mistral-7b-awq" | "@hf/thebloke/neural-chat-7b-v3-1-awq" | "@hf/thebloke/llamaguard-7b-awq" | "@hf/thebloke/deepseek-coder-6.7b-base-awq" | "@hf/thebloke/deepseek-coder-6.7b-instruct-awq" | "@cf/deepseek-ai/deepseek-math-7b-instruct" | "@cf/defog/sqlcoder-7b-2" | "@cf/openchat/openchat-3.5-0106" | "@cf/tiiuae/falcon-7b-instruct" | "@cf/thebloke/discolm-german-7b-v1-awq" | "@cf/qwen/qwen1.5-0.5b-chat" | "@cf/qwen/qwen1.5-7b-chat-awq" | "@cf/qwen/qwen1.5-14b-chat-awq" | "@cf/tinyllama/tinyllama-1.1b-chat-v1.0" | "@cf/microsoft/phi-2" | "@cf/qwen/qwen1.5-1.8b-chat" | "@cf/mistral/mistral-7b-instruct-v0.2-lora" | "@hf/nousresearch/hermes-2-pro-mistral-7b" | "@hf/nexusflow/starling-lm-7b-beta" | "@hf/google/gemma-7b-it" | "@cf/meta-llama/llama-2-7b-chat-hf-lora" | "@cf/google/gemma-2b-it-lora" | "@cf/google/gemma-7b-it-lora" | "@hf/mistral/mistral-7b-instruct-v0.2" | "@cf/meta/llama-3-8b-instruct" | "@cf/fblgit/una-cybertron-7b-v2-bf16" | "@cf/meta/llama-3-8b-instruct-awq" | "@hf/meta-llama/meta-llama-3-8b-instruct" | "@cf/meta/llama-3.1-8b-instruct" | "@cf/meta/llama-3.1-8b-instruct-fp8" | "@cf/meta/llama-3.1-8b-instruct-awq" | "@cf/meta/llama-3.2-3b-instruct" | "@cf/meta/llama-3.2-1b-instruct" | "@cf/meta/llama-3.3-70b-instruct-fp8-fast" | "@cf/meta/llama-3.2-11b-vision-instruct", "@cf/baai/bge-base-en-v1.5" | "@cf/baai/bge-small-en-v1.5" | "@cf/baai/bge-large-en-v1.5">>;
|
|
12
|
+
custom(args: AiRequestConfig): Promise<OpenAICompatibleProvider<string, string, string>>;
|
|
13
|
+
googleAi(args: AiRequestConfig): Promise<GoogleGenerativeAIProvider>;
|
|
10
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Helpers } from '@chainfuse/helpers';
|
|
2
|
-
import {
|
|
2
|
+
import { AiModels, enabledCloudflareLlmProviders } from '@chainfuse/types';
|
|
3
3
|
import { APICallError, experimental_customProvider as customProvider, TypeValidationError, experimental_wrapLanguageModel as wrapLanguageModel } from 'ai';
|
|
4
4
|
import { ZodError } from 'zod';
|
|
5
5
|
import { AiBase } from '../base.mjs';
|
|
@@ -17,7 +17,7 @@ export class AiCustomProviders extends AiBase {
|
|
|
17
17
|
const acc = await accPromise;
|
|
18
18
|
// @ts-expect-error override for types
|
|
19
19
|
acc[model] = wrapLanguageModel({
|
|
20
|
-
model: (await raw.azOpenai(args, server
|
|
20
|
+
model: (await raw.azOpenai(args, server))(model),
|
|
21
21
|
middleware: {
|
|
22
22
|
wrapGenerate: async ({ doGenerate, model, params }) => {
|
|
23
23
|
try {
|
|
@@ -40,7 +40,7 @@ export class AiCustomProviders extends AiBase {
|
|
|
40
40
|
if (args.logging ?? this.config.environment !== 'production')
|
|
41
41
|
console.error('ai', 'custom provider', this.chalk.rgb(...Helpers.uniqueIdColor(idempotencyId))(`[${idempotencyId}]`), this.chalk.blue('FALLBACK'), nextServer.id, 'REMAINING', JSON.stringify(leftOverServers.slice(leftOverServers.indexOf(nextServer) + 1).map((s) => s.id)));
|
|
42
42
|
// Must be double awaited to prevent a promise from being returned
|
|
43
|
-
return await (await raw.azOpenai({ ...args, idempotencyId }, nextServer
|
|
43
|
+
return await (await raw.azOpenai({ ...args, idempotencyId }, nextServer))(model.modelId).doGenerate(params);
|
|
44
44
|
}
|
|
45
45
|
catch (nextServerError) {
|
|
46
46
|
if (APICallError.isInstance(nextServerError)) {
|
|
@@ -70,7 +70,7 @@ export class AiCustomProviders extends AiBase {
|
|
|
70
70
|
textEmbeddingModels: await server.textEmbeddingModelAvailability.reduce(async (accPromise, model) => {
|
|
71
71
|
const acc = await accPromise;
|
|
72
72
|
// @ts-expect-error override for types
|
|
73
|
-
acc[model] = (await raw.azOpenai(args, server
|
|
73
|
+
acc[model] = (await raw.azOpenai(args, server)).textEmbeddingModel(model);
|
|
74
74
|
return acc;
|
|
75
75
|
}, Promise.resolve({})),
|
|
76
76
|
// An optional fallback provider to use when a requested model is not found in the custom provider.
|
|
@@ -139,13 +139,7 @@ export class AiCustomProviders extends AiBase {
|
|
|
139
139
|
});
|
|
140
140
|
return acc;
|
|
141
141
|
}, Promise.resolve({})),
|
|
142
|
-
|
|
143
|
-
textEmbeddingModels: await enabledCloudflareLlmEmbeddingProviders.reduce(async (accPromise, model) => {
|
|
144
|
-
const acc = await accPromise;
|
|
145
|
-
// @ts-expect-error override for types
|
|
146
|
-
acc[model] = (await raw.restWorkersAi(args)).textEmbeddingModel(model);
|
|
147
|
-
return acc;
|
|
148
|
-
}, Promise.resolve({})),
|
|
142
|
+
fallbackProvider: await raw.restWorkersAi(args),
|
|
149
143
|
});
|
|
150
144
|
}
|
|
151
145
|
else {
|
|
@@ -164,4 +158,20 @@ export class AiCustomProviders extends AiBase {
|
|
|
164
158
|
}) as CloudflareOpenAIProvider;*/
|
|
165
159
|
}
|
|
166
160
|
}
|
|
161
|
+
custom(args) {
|
|
162
|
+
return new AiRawProviders(this.config).custom(args);
|
|
163
|
+
}
|
|
164
|
+
async googleAi(args) {
|
|
165
|
+
const fallbackProvider = await new AiRawProviders(this.config).googleAi(args);
|
|
166
|
+
return customProvider({
|
|
167
|
+
languageModels: {
|
|
168
|
+
// provider:actual model name:extra
|
|
169
|
+
[AiModels.LanguageModels.GoogleGenerativeAi.gemini_flash_beta_search.split(':').slice(1).join(':')]: fallbackProvider(AiModels.LanguageModels.GoogleGenerativeAi.gemini_flash_beta_search.split(':')[1], { useSearchGrounding: true }),
|
|
170
|
+
[AiModels.LanguageModels.GoogleGenerativeAi.gemini_flash_search.split(':').slice(1).join(':')]: fallbackProvider(AiModels.LanguageModels.GoogleGenerativeAi.gemini_flash_search.split(':')[1], { useSearchGrounding: true }),
|
|
171
|
+
[AiModels.LanguageModels.GoogleGenerativeAi.gemini_pro_search.split(':').slice(1).join(':')]: fallbackProvider(AiModels.LanguageModels.GoogleGenerativeAi.gemini_pro_search.split(':')[1], { useSearchGrounding: true }),
|
|
172
|
+
},
|
|
173
|
+
fallbackProvider,
|
|
174
|
+
// GoogleGenerativeAi
|
|
175
|
+
});
|
|
176
|
+
}
|
|
167
177
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import type { OpenAICompatibleProvider } from '@ai-sdk/openai-compatible';
|
|
2
|
+
import type { cloudflareModelPossibilities } from '@chainfuse/types';
|
|
1
3
|
import { AiBase } from '../base.mjs';
|
|
4
|
+
import type { Server } from '../serverSelector/types.mjs';
|
|
2
5
|
import type { AiRequestConfig } from '../types.mjs';
|
|
3
6
|
export declare class AiRawProviders extends AiBase {
|
|
4
7
|
private readonly cacheTtl;
|
|
8
|
+
private updateGatewayLog;
|
|
5
9
|
oaiOpenai(args: AiRequestConfig): Promise<import("@ai-sdk/openai").OpenAIProvider>;
|
|
6
|
-
azOpenai(args: AiRequestConfig, server:
|
|
10
|
+
azOpenai(args: AiRequestConfig, server: Server): Promise<import("@ai-sdk/azure").AzureOpenAIProvider>;
|
|
7
11
|
anthropic(args: AiRequestConfig): Promise<import("@ai-sdk/anthropic").AnthropicProvider>;
|
|
8
|
-
|
|
12
|
+
custom(args: AiRequestConfig): Promise<OpenAICompatibleProvider<string, string, string>>;
|
|
13
|
+
googleAi(args: AiRequestConfig): Promise<import("@ai-sdk/google").GoogleGenerativeAIProvider>;
|
|
14
|
+
restWorkersAi(args: AiRequestConfig): Promise<OpenAICompatibleProvider<cloudflareModelPossibilities<'Text Generation'>, cloudflareModelPossibilities<'Text Generation'>, cloudflareModelPossibilities<'Text Embeddings'>>>;
|
|
9
15
|
}
|
|
@@ -1,8 +1,38 @@
|
|
|
1
|
-
import { BufferHelpers, CryptoHelpers, Helpers } from '@chainfuse/helpers';
|
|
1
|
+
import { BufferHelpers, CryptoHelpers, DnsHelpers, Helpers } from '@chainfuse/helpers';
|
|
2
|
+
import haversine from 'haversine-distance';
|
|
3
|
+
import { z } from 'zod';
|
|
2
4
|
import { AiBase } from '../base.mjs';
|
|
3
5
|
export class AiRawProviders extends AiBase {
|
|
4
6
|
// 2628288 seconds is what cf defines as 1 month in their cache rules
|
|
5
7
|
cacheTtl = 2628288;
|
|
8
|
+
async updateGatewayLog(response, metadataHeader, startRoundTrip, modelTime) {
|
|
9
|
+
/**
|
|
10
|
+
* @todo `cloudflare` rest package not updated to this endpoint yet
|
|
11
|
+
*/
|
|
12
|
+
const updateMetadata = fetch(new URL(['client', 'v4', 'accounts', this.config.gateway.accountId, 'ai-gateway', 'gateways', this.config.environment, 'logs', response.headers.get('cf-aig-log-id')].join('/'), 'https://api.cloudflare.com'), {
|
|
13
|
+
method: 'PATCH',
|
|
14
|
+
headers: {
|
|
15
|
+
Authorization: `Bearer ${this.config.gateway.apiToken}`,
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify({
|
|
19
|
+
metadata: {
|
|
20
|
+
...metadataHeader,
|
|
21
|
+
timing: JSON.stringify({
|
|
22
|
+
fromCache: response.headers.get('cf-aig-cache-status')?.toLowerCase() === 'hit',
|
|
23
|
+
totalRoundtripTime: performance.now() - startRoundTrip,
|
|
24
|
+
modelTime,
|
|
25
|
+
}),
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
if (this.config.backgroundContext) {
|
|
30
|
+
this.config.backgroundContext.waitUntil(updateMetadata);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
await updateMetadata;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
6
36
|
oaiOpenai(args) {
|
|
7
37
|
return import('@ai-sdk/openai').then(async ({ createOpenAI }) => createOpenAI({
|
|
8
38
|
baseURL: new URL(['v1', this.config.gateway.accountId, this.config.environment, 'openai'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
@@ -29,6 +59,7 @@ export class AiRawProviders extends AiBase {
|
|
|
29
59
|
},
|
|
30
60
|
compatibility: 'strict',
|
|
31
61
|
fetch: async (input, rawInit) => {
|
|
62
|
+
const startRoundTrip = performance.now();
|
|
32
63
|
const headers = new Headers(rawInit?.headers);
|
|
33
64
|
const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
|
|
34
65
|
if (metadataHeader.idempotencyId.split('-').length === 4) {
|
|
@@ -40,6 +71,7 @@ export class AiRawProviders extends AiBase {
|
|
|
40
71
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
41
72
|
if (args.logging ?? this.config.environment !== 'production')
|
|
42
73
|
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));
|
|
74
|
+
await this.updateGatewayLog(response, metadataHeader, startRoundTrip, response.headers.has('openai-processing-ms') ? parseInt(response.headers.get('openai-processing-ms')) : undefined);
|
|
43
75
|
// Inject it to have it available for retries
|
|
44
76
|
const mutableHeaders = new Headers(response.headers);
|
|
45
77
|
mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
|
|
@@ -57,13 +89,13 @@ export class AiRawProviders extends AiBase {
|
|
|
57
89
|
}
|
|
58
90
|
azOpenai(args, server) {
|
|
59
91
|
return import('@ai-sdk/azure').then(async ({ createAzure }) => createAzure({
|
|
60
|
-
apiKey: this.config.providers.azureOpenAi.apiTokens[`AZURE_API_KEY_${server.toUpperCase().replaceAll('-', '_')}`],
|
|
92
|
+
apiKey: this.config.providers.azureOpenAi.apiTokens[`AZURE_API_KEY_${server.id.toUpperCase().replaceAll('-', '_')}`],
|
|
61
93
|
/**
|
|
62
94
|
* @link https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#api-specs
|
|
63
95
|
* From the table, pick the `Latest GA release` for `Data plane - inference`
|
|
64
96
|
*/
|
|
65
97
|
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(),
|
|
98
|
+
baseURL: new URL(['v1', this.config.gateway.accountId, this.config.environment, 'azure-openai', server.id.toLowerCase()].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
67
99
|
headers: {
|
|
68
100
|
'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
|
|
69
101
|
'cf-aig-metadata': JSON.stringify({
|
|
@@ -72,7 +104,11 @@ export class AiRawProviders extends AiBase {
|
|
|
72
104
|
// Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
|
|
73
105
|
idempotencyId: args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
|
|
74
106
|
serverInfo: JSON.stringify({
|
|
75
|
-
name:
|
|
107
|
+
name: `azure-${server.id}`,
|
|
108
|
+
distance: haversine({
|
|
109
|
+
lat: Helpers.precisionFloat(this.config.geoRouting?.userCoordinate?.lat ?? '0'),
|
|
110
|
+
lon: Helpers.precisionFloat(this.config.geoRouting?.userCoordinate?.lon ?? '0'),
|
|
111
|
+
}, server.coordinate),
|
|
76
112
|
}),
|
|
77
113
|
/**
|
|
78
114
|
* Blank at first, add after request finishes
|
|
@@ -84,6 +120,7 @@ export class AiRawProviders extends AiBase {
|
|
|
84
120
|
...(args.skipCache && { 'cf-aig-skip-cache': 'true' }),
|
|
85
121
|
},
|
|
86
122
|
fetch: async (input, rawInit) => {
|
|
123
|
+
const startRoundTrip = performance.now();
|
|
87
124
|
const headers = new Headers(rawInit?.headers);
|
|
88
125
|
const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
|
|
89
126
|
if (metadataHeader.idempotencyId.split('-').length === 4) {
|
|
@@ -95,6 +132,7 @@ export class AiRawProviders extends AiBase {
|
|
|
95
132
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
96
133
|
if (args.logging ?? this.config.environment !== 'production')
|
|
97
134
|
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));
|
|
135
|
+
await this.updateGatewayLog(response, metadataHeader, startRoundTrip, response.headers.has('x-envoy-upstream-service-time') ? parseInt(response.headers.get('x-envoy-upstream-service-time')) : undefined);
|
|
98
136
|
// Inject it to have it available for retries
|
|
99
137
|
const mutableHeaders = new Headers(response.headers);
|
|
100
138
|
mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
|
|
@@ -122,7 +160,168 @@ export class AiRawProviders extends AiBase {
|
|
|
122
160
|
// Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
|
|
123
161
|
idempotencyId: args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
|
|
124
162
|
serverInfo: JSON.stringify({
|
|
125
|
-
name: '
|
|
163
|
+
name: 'anthropic',
|
|
164
|
+
}),
|
|
165
|
+
/**
|
|
166
|
+
* Blank at first, add after request finishes
|
|
167
|
+
* CF AI Gateway allows only editing existing metadata not creating new ones after the request is made
|
|
168
|
+
*/
|
|
169
|
+
timing: JSON.stringify({}),
|
|
170
|
+
}),
|
|
171
|
+
...(args.cache && { 'cf-aig-cache-ttl': (typeof args.cache === 'boolean' ? (args.cache ? this.cacheTtl : 0) : args.cache).toString() }),
|
|
172
|
+
...(args.skipCache && { 'cf-aig-skip-cache': 'true' }),
|
|
173
|
+
},
|
|
174
|
+
fetch: async (input, rawInit) => {
|
|
175
|
+
const startRoundTrip = performance.now();
|
|
176
|
+
const headers = new Headers(rawInit?.headers);
|
|
177
|
+
const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
|
|
178
|
+
if (metadataHeader.idempotencyId.split('-').length === 4) {
|
|
179
|
+
metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
|
|
180
|
+
headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
|
|
181
|
+
}
|
|
182
|
+
if (args.logging ?? this.config.environment !== 'production')
|
|
183
|
+
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));
|
|
184
|
+
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
185
|
+
if (args.logging ?? this.config.environment !== 'production')
|
|
186
|
+
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));
|
|
187
|
+
await this.updateGatewayLog(response, metadataHeader, startRoundTrip);
|
|
188
|
+
// Inject it to have it available for retries
|
|
189
|
+
const mutableHeaders = new Headers(response.headers);
|
|
190
|
+
mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
|
|
191
|
+
if (response.ok) {
|
|
192
|
+
return new Response(response.body, { ...response, headers: mutableHeaders });
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
const [body1, body2] = response.body.tee();
|
|
196
|
+
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())));
|
|
197
|
+
return new Response(body2, { ...response, headers: mutableHeaders });
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
custom(args) {
|
|
204
|
+
if (this.config.providers.custom?.url) {
|
|
205
|
+
// Verify that the custom provider url is a valid URL
|
|
206
|
+
return z
|
|
207
|
+
.string()
|
|
208
|
+
.trim()
|
|
209
|
+
.url()
|
|
210
|
+
.transform((url) => new URL(url))
|
|
211
|
+
.parseAsync(this.config.providers.custom.url)
|
|
212
|
+
.then((customProviderUrl) =>
|
|
213
|
+
// Verify that the custom provider url is not an IP address
|
|
214
|
+
z
|
|
215
|
+
.string()
|
|
216
|
+
.trim()
|
|
217
|
+
.ip()
|
|
218
|
+
.safeParseAsync(customProviderUrl.hostname)
|
|
219
|
+
.then(async ({ success }) => {
|
|
220
|
+
if (success) {
|
|
221
|
+
throw new Error('IP custom providers not allowed');
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
// Run domain through ZT policies
|
|
225
|
+
const doh = new DnsHelpers(new URL('dns-query', `https://${this.config.providers.custom?.dohId}.cloudflare-gateway.com`));
|
|
226
|
+
const aCheck = doh.query(customProviderUrl.hostname, 'A', undefined, undefined, 2 * 1000);
|
|
227
|
+
const aaaaCheck = doh.query(customProviderUrl.hostname, 'AAAA', undefined, undefined, 2 * 1000);
|
|
228
|
+
return Promise.allSettled([aCheck, aaaaCheck]).then((checks) => {
|
|
229
|
+
const fulfulledChecks = checks.filter((check) => check.status === 'fulfilled');
|
|
230
|
+
/**
|
|
231
|
+
* Blocked domains return 0.0.0.0 or :: as the answer
|
|
232
|
+
* @link https://developers.cloudflare.com/cloudflare-one/policies/gateway/block-page/
|
|
233
|
+
*/
|
|
234
|
+
if (fulfulledChecks.length > 0 && fulfulledChecks.some((obj) => 'Answer' in obj.value && Array.isArray(obj.value.Answer) && obj.value.Answer.some((answer) => answer.data !== '0.0.0.0' && answer.data !== '::'))) {
|
|
235
|
+
// ZT Pass, perform the calls
|
|
236
|
+
return import('@ai-sdk/openai-compatible').then(async ({ createOpenAICompatible }) => createOpenAICompatible({
|
|
237
|
+
baseURL: customProviderUrl.toString(),
|
|
238
|
+
...(this.config.providers.custom?.apiToken && { apiKey: this.config.providers.custom.apiToken }),
|
|
239
|
+
headers: {
|
|
240
|
+
// ZT Auth if present
|
|
241
|
+
...(this.config.providers.custom &&
|
|
242
|
+
'clientId' in this.config.providers.custom &&
|
|
243
|
+
this.config.providers.custom.clientId &&
|
|
244
|
+
'clientSecret' in this.config.providers.custom &&
|
|
245
|
+
this.config.providers.custom.clientSecret && {
|
|
246
|
+
'CF-Access-Client-Id': this.config.providers.custom.clientId,
|
|
247
|
+
'CF-Access-Client-Secret': this.config.providers.custom.clientSecret,
|
|
248
|
+
}),
|
|
249
|
+
'X-Dataspace-Id': (await BufferHelpers.uuidConvert(args.dataspaceId)).utf8,
|
|
250
|
+
'X-Executor': JSON.stringify(args.executor),
|
|
251
|
+
// Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
|
|
252
|
+
'X-Idempotency-Id': args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
|
|
253
|
+
// Request to skip or custom cache duration (no guarantee that upstream server will respect it)
|
|
254
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
255
|
+
...((args.skipCache || args.cache) && { 'Cache-Control': [args.skipCache && 'no-cache', args.cache && `max-age=${typeof args.cache === 'boolean' ? (args.cache ? this.cacheTtl : 0) : args.cache}`].join(', ') }),
|
|
256
|
+
},
|
|
257
|
+
name: 'custom',
|
|
258
|
+
fetch: async (input, rawInit) => {
|
|
259
|
+
const headers = new Headers(rawInit?.headers);
|
|
260
|
+
let idempotencyId = headers.get('X-Idempotency-Id');
|
|
261
|
+
if (idempotencyId.split('-').length === 4) {
|
|
262
|
+
idempotencyId = `${idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
|
|
263
|
+
headers.set('X-Idempotency-Id', idempotencyId);
|
|
264
|
+
}
|
|
265
|
+
if (args.logging ?? this.config.environment !== 'production')
|
|
266
|
+
console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(idempotencyId))(`[${idempotencyId}]`), this.chalk.magenta(rawInit?.method), this.chalk.magenta(new URL(new Request(input).url).pathname));
|
|
267
|
+
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
268
|
+
if (args.logging ?? this.config.environment !== 'production')
|
|
269
|
+
console.info('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(idempotencyId))(`[${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));
|
|
270
|
+
// Inject it to have it available for retries
|
|
271
|
+
const mutableHeaders = new Headers(response.headers);
|
|
272
|
+
mutableHeaders.set('X-Idempotency-Id', idempotencyId);
|
|
273
|
+
if (response.ok) {
|
|
274
|
+
return new Response(response.body, { ...response, headers: mutableHeaders });
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const [body1, body2] = response.body.tee();
|
|
278
|
+
console.error('ai', 'raw provider', this.chalk.rgb(...Helpers.uniqueIdColor(idempotencyId))(`[${idempotencyId}]`), this.chalk.red(JSON.stringify(await new Response(body1, response).json())));
|
|
279
|
+
return new Response(body2, { ...response, headers: mutableHeaders });
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
}));
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
throw new Error('Failed ZT check on custom provider url');
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}))
|
|
291
|
+
.catch(() => {
|
|
292
|
+
throw new Error('Invalid custom provider url');
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
// This always gets called, only throw error if actually being used
|
|
297
|
+
return import('@ai-sdk/openai-compatible').then(async ({ createOpenAICompatible }) => createOpenAICompatible({
|
|
298
|
+
// Dummy url that'll never be hit
|
|
299
|
+
baseURL: 'https://sushidata.com',
|
|
300
|
+
name: 'custom',
|
|
301
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
302
|
+
fetch: async () => {
|
|
303
|
+
throw new Error('Custom provider not configured');
|
|
304
|
+
},
|
|
305
|
+
}));
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
googleAi(args) {
|
|
309
|
+
return import('@ai-sdk/google').then(async ({ createGoogleGenerativeAI }) => createGoogleGenerativeAI({
|
|
310
|
+
/**
|
|
311
|
+
* `v1beta` is the only one that supports function calls as of now
|
|
312
|
+
* @link https://ai.google.dev/gemini-api/docs/api-versions
|
|
313
|
+
*/
|
|
314
|
+
baseURL: new URL(['v1', this.config.gateway.accountId, this.config.environment, 'google-ai-studio', 'v1beta'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
315
|
+
apiKey: this.config.providers.googleAi.apiToken,
|
|
316
|
+
headers: {
|
|
317
|
+
'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
|
|
318
|
+
'cf-aig-metadata': JSON.stringify({
|
|
319
|
+
dataspaceId: (await BufferHelpers.uuidConvert(args.dataspaceId)).utf8,
|
|
320
|
+
executor: JSON.stringify(args.executor),
|
|
321
|
+
// Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
|
|
322
|
+
idempotencyId: args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
|
|
323
|
+
serverInfo: JSON.stringify({
|
|
324
|
+
name: 'googleai',
|
|
126
325
|
}),
|
|
127
326
|
/**
|
|
128
327
|
* Blank at first, add after request finishes
|
|
@@ -134,6 +333,7 @@ export class AiRawProviders extends AiBase {
|
|
|
134
333
|
...(args.skipCache && { 'cf-aig-skip-cache': 'true' }),
|
|
135
334
|
},
|
|
136
335
|
fetch: async (input, rawInit) => {
|
|
336
|
+
const startRoundTrip = performance.now();
|
|
137
337
|
const headers = new Headers(rawInit?.headers);
|
|
138
338
|
const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
|
|
139
339
|
if (metadataHeader.idempotencyId.split('-').length === 4) {
|
|
@@ -145,6 +345,7 @@ export class AiRawProviders extends AiBase {
|
|
|
145
345
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
146
346
|
if (args.logging ?? this.config.environment !== 'production')
|
|
147
347
|
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));
|
|
348
|
+
await this.updateGatewayLog(response, metadataHeader, startRoundTrip);
|
|
148
349
|
// Inject it to have it available for retries
|
|
149
350
|
const mutableHeaders = new Headers(response.headers);
|
|
150
351
|
mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
|
|
@@ -161,7 +362,7 @@ export class AiRawProviders extends AiBase {
|
|
|
161
362
|
}));
|
|
162
363
|
}
|
|
163
364
|
restWorkersAi(args) {
|
|
164
|
-
return import('@ai-sdk/openai').then(async ({
|
|
365
|
+
return import('@ai-sdk/openai-compatible').then(async ({ createOpenAICompatible }) => createOpenAICompatible({
|
|
165
366
|
baseURL: new URL(['v1', this.config.gateway.accountId, this.config.environment, 'workers-ai', 'v1'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
166
367
|
apiKey: this.config.providers.workersAi.apiToken,
|
|
167
368
|
headers: {
|
|
@@ -172,7 +373,7 @@ export class AiRawProviders extends AiBase {
|
|
|
172
373
|
// Generate incomplete id because we don't have the body to hash yet. Fill it in in the `fetch()`
|
|
173
374
|
idempotencyId: args.idempotencyId ?? (await BufferHelpers.generateUuid).utf8.slice(0, 23),
|
|
174
375
|
serverInfo: JSON.stringify({
|
|
175
|
-
name: '
|
|
376
|
+
name: 'cloudflare',
|
|
176
377
|
}),
|
|
177
378
|
/**
|
|
178
379
|
* Blank at first, add after request finishes
|
|
@@ -183,9 +384,9 @@ export class AiRawProviders extends AiBase {
|
|
|
183
384
|
...(args.cache && { 'cf-aig-cache-ttl': (typeof args.cache === 'boolean' ? (args.cache ? this.cacheTtl : 0) : args.cache).toString() }),
|
|
184
385
|
...(args.skipCache && { 'cf-aig-skip-cache': 'true' }),
|
|
185
386
|
},
|
|
186
|
-
compatibility: 'compatible',
|
|
187
387
|
name: 'workersai',
|
|
188
388
|
fetch: async (input, rawInit) => {
|
|
389
|
+
const startRoundTrip = performance.now();
|
|
189
390
|
const headers = new Headers(rawInit?.headers);
|
|
190
391
|
const metadataHeader = JSON.parse(headers.get('cf-aig-metadata'));
|
|
191
392
|
if (metadataHeader.idempotencyId.split('-').length === 4) {
|
|
@@ -197,6 +398,7 @@ export class AiRawProviders extends AiBase {
|
|
|
197
398
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
198
399
|
if (args.logging ?? this.config.environment !== 'production')
|
|
199
400
|
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));
|
|
401
|
+
await this.updateGatewayLog(response, metadataHeader, startRoundTrip);
|
|
200
402
|
// Inject it to have it available for retries
|
|
201
403
|
const mutableHeaders = new Headers(response.headers);
|
|
202
404
|
mutableHeaders.set('X-Idempotency-Id', metadataHeader.idempotencyId);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OpenAIChatSettings, OpenAIEmbeddingSettings } from '@ai-sdk/openai/internal';
|
|
2
2
|
import type { EmbeddingModelV1, LanguageModelV1 } from '@ai-sdk/provider';
|
|
3
|
-
import type { AzureChatModels, AzureEmbeddingModels
|
|
3
|
+
import type { AzureChatModels, AzureEmbeddingModels } from '@chainfuse/types';
|
|
4
4
|
import type { Provider } from 'ai';
|
|
5
5
|
export interface AzureOpenAIProvider extends Provider {
|
|
6
6
|
(deploymentId: AzureChatModels, settings?: OpenAIChatSettings): LanguageModelV1;
|
|
@@ -13,14 +13,3 @@ export interface AzureOpenAIProvider extends Provider {
|
|
|
13
13
|
*/
|
|
14
14
|
textEmbeddingModel(deploymentId: AzureEmbeddingModels, settings?: OpenAIEmbeddingSettings): EmbeddingModelV1<string>;
|
|
15
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
|
-
}
|
package/dist/registry.d.mts
CHANGED
|
@@ -5,7 +5,9 @@ export declare class AiRegistry extends AiBase {
|
|
|
5
5
|
openai: import("@ai-sdk/openai").OpenAIProvider;
|
|
6
6
|
azure: import("./providers/types.mjs").AzureOpenAIProvider;
|
|
7
7
|
anthropic: import("@ai-sdk/anthropic").AnthropicProvider;
|
|
8
|
-
|
|
8
|
+
custom: import("@ai-sdk/openai-compatible").OpenAICompatibleProvider<string, string, string>;
|
|
9
|
+
'google.generative-ai': import("@ai-sdk/google").GoogleGenerativeAIProvider;
|
|
10
|
+
workersai: import("@ai-sdk/openai-compatible").OpenAICompatibleProvider<"@cf/meta/llama-2-7b-chat-int8" | "@cf/mistral/mistral-7b-instruct-v0.1" | "@cf/meta/llama-2-7b-chat-fp16" | "@hf/thebloke/llama-2-13b-chat-awq" | "@hf/thebloke/mistral-7b-instruct-v0.1-awq" | "@hf/thebloke/zephyr-7b-beta-awq" | "@hf/thebloke/openhermes-2.5-mistral-7b-awq" | "@hf/thebloke/neural-chat-7b-v3-1-awq" | "@hf/thebloke/llamaguard-7b-awq" | "@hf/thebloke/deepseek-coder-6.7b-base-awq" | "@hf/thebloke/deepseek-coder-6.7b-instruct-awq" | "@cf/deepseek-ai/deepseek-math-7b-instruct" | "@cf/defog/sqlcoder-7b-2" | "@cf/openchat/openchat-3.5-0106" | "@cf/tiiuae/falcon-7b-instruct" | "@cf/thebloke/discolm-german-7b-v1-awq" | "@cf/qwen/qwen1.5-0.5b-chat" | "@cf/qwen/qwen1.5-7b-chat-awq" | "@cf/qwen/qwen1.5-14b-chat-awq" | "@cf/tinyllama/tinyllama-1.1b-chat-v1.0" | "@cf/microsoft/phi-2" | "@cf/qwen/qwen1.5-1.8b-chat" | "@cf/mistral/mistral-7b-instruct-v0.2-lora" | "@hf/nousresearch/hermes-2-pro-mistral-7b" | "@hf/nexusflow/starling-lm-7b-beta" | "@hf/google/gemma-7b-it" | "@cf/meta-llama/llama-2-7b-chat-hf-lora" | "@cf/google/gemma-2b-it-lora" | "@cf/google/gemma-7b-it-lora" | "@hf/mistral/mistral-7b-instruct-v0.2" | "@cf/meta/llama-3-8b-instruct" | "@cf/fblgit/una-cybertron-7b-v2-bf16" | "@cf/meta/llama-3-8b-instruct-awq" | "@hf/meta-llama/meta-llama-3-8b-instruct" | "@cf/meta/llama-3.1-8b-instruct" | "@cf/meta/llama-3.1-8b-instruct-fp8" | "@cf/meta/llama-3.1-8b-instruct-awq" | "@cf/meta/llama-3.2-3b-instruct" | "@cf/meta/llama-3.2-1b-instruct" | "@cf/meta/llama-3.3-70b-instruct-fp8-fast" | "@cf/meta/llama-3.2-11b-vision-instruct", "@cf/meta/llama-2-7b-chat-int8" | "@cf/mistral/mistral-7b-instruct-v0.1" | "@cf/meta/llama-2-7b-chat-fp16" | "@hf/thebloke/llama-2-13b-chat-awq" | "@hf/thebloke/mistral-7b-instruct-v0.1-awq" | "@hf/thebloke/zephyr-7b-beta-awq" | "@hf/thebloke/openhermes-2.5-mistral-7b-awq" | "@hf/thebloke/neural-chat-7b-v3-1-awq" | "@hf/thebloke/llamaguard-7b-awq" | "@hf/thebloke/deepseek-coder-6.7b-base-awq" | "@hf/thebloke/deepseek-coder-6.7b-instruct-awq" | "@cf/deepseek-ai/deepseek-math-7b-instruct" | "@cf/defog/sqlcoder-7b-2" | "@cf/openchat/openchat-3.5-0106" | "@cf/tiiuae/falcon-7b-instruct" | "@cf/thebloke/discolm-german-7b-v1-awq" | "@cf/qwen/qwen1.5-0.5b-chat" | "@cf/qwen/qwen1.5-7b-chat-awq" | "@cf/qwen/qwen1.5-14b-chat-awq" | "@cf/tinyllama/tinyllama-1.1b-chat-v1.0" | "@cf/microsoft/phi-2" | "@cf/qwen/qwen1.5-1.8b-chat" | "@cf/mistral/mistral-7b-instruct-v0.2-lora" | "@hf/nousresearch/hermes-2-pro-mistral-7b" | "@hf/nexusflow/starling-lm-7b-beta" | "@hf/google/gemma-7b-it" | "@cf/meta-llama/llama-2-7b-chat-hf-lora" | "@cf/google/gemma-2b-it-lora" | "@cf/google/gemma-7b-it-lora" | "@hf/mistral/mistral-7b-instruct-v0.2" | "@cf/meta/llama-3-8b-instruct" | "@cf/fblgit/una-cybertron-7b-v2-bf16" | "@cf/meta/llama-3-8b-instruct-awq" | "@hf/meta-llama/meta-llama-3-8b-instruct" | "@cf/meta/llama-3.1-8b-instruct" | "@cf/meta/llama-3.1-8b-instruct-fp8" | "@cf/meta/llama-3.1-8b-instruct-awq" | "@cf/meta/llama-3.2-3b-instruct" | "@cf/meta/llama-3.2-1b-instruct" | "@cf/meta/llama-3.3-70b-instruct-fp8-fast" | "@cf/meta/llama-3.2-11b-vision-instruct", "@cf/baai/bge-base-en-v1.5" | "@cf/baai/bge-small-en-v1.5" | "@cf/baai/bge-large-en-v1.5">;
|
|
9
11
|
}>>;
|
|
10
12
|
registry(args: AiRequestConfig): Promise<import("ai").Provider>;
|
|
11
13
|
}
|
package/dist/registry.mjs
CHANGED
|
@@ -7,6 +7,8 @@ export class AiRegistry extends AiBase {
|
|
|
7
7
|
openai: await new AiCustomProviders(this.config).oaiOpenai(args),
|
|
8
8
|
azure: await new AiCustomProviders(this.config).azOpenai(args),
|
|
9
9
|
anthropic: await new AiCustomProviders(this.config).anthropic(args),
|
|
10
|
+
custom: await new AiCustomProviders(this.config).custom(args),
|
|
11
|
+
'google.generative-ai': await new AiCustomProviders(this.config).googleAi(args),
|
|
10
12
|
workersai: await new AiCustomProviders(this.config).cfWorkersAi(args),
|
|
11
13
|
});
|
|
12
14
|
}
|
package/dist/types.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PrefixedUuid, RawCoordinate, UuidExport } from '@chainfuse/types';
|
|
2
|
-
import type { Ai, IncomingRequestCfProperties } from '@cloudflare/workers-types/experimental';
|
|
2
|
+
import type { Ai, ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types/experimental';
|
|
3
3
|
import type haversine from 'haversine-distance';
|
|
4
4
|
export interface AiConfig {
|
|
5
5
|
gateway: {
|
|
@@ -13,10 +13,13 @@ export interface AiConfig {
|
|
|
13
13
|
};
|
|
14
14
|
environment: 'production' | 'preview';
|
|
15
15
|
providers: AiConfigProviders;
|
|
16
|
+
backgroundContext?: ExecutionContext;
|
|
16
17
|
}
|
|
17
18
|
export interface AiConfigProviders {
|
|
18
19
|
anthropic: AiConfigAnthropic;
|
|
19
20
|
azureOpenAi: AiConfigAzOpenai;
|
|
21
|
+
custom?: AiConfigCustom;
|
|
22
|
+
googleAi: AiConfigGoogleAi;
|
|
20
23
|
openAi: AiConfigOaiOpenai;
|
|
21
24
|
workersAi: AiConfigWorkersai;
|
|
22
25
|
}
|
|
@@ -26,10 +29,27 @@ export interface AiConfigAnthropic {
|
|
|
26
29
|
export interface AiConfigAzOpenai {
|
|
27
30
|
apiTokens: Record<`AZURE_API_KEY_${string}`, string>;
|
|
28
31
|
}
|
|
32
|
+
export interface AiConfigCustomBase {
|
|
33
|
+
/**
|
|
34
|
+
* For safety resons, no direct IPs allowed.
|
|
35
|
+
*/
|
|
36
|
+
url: string;
|
|
37
|
+
dohId: string;
|
|
38
|
+
apiToken?: string;
|
|
39
|
+
}
|
|
40
|
+
export type AiConfigCustom = AiConfigCustomBase | (AiConfigCustomBase & AiConfigCustomZT);
|
|
41
|
+
export interface AiConfigCustomZT {
|
|
42
|
+
clientId: string;
|
|
43
|
+
clientSecret: string;
|
|
44
|
+
}
|
|
45
|
+
export interface AiConfigGoogleAi {
|
|
46
|
+
apiToken: string;
|
|
47
|
+
}
|
|
29
48
|
export interface AiConfigOaiOpenai {
|
|
30
49
|
apiToken: `sk-${string}`;
|
|
31
50
|
organization: `org-${string}`;
|
|
32
51
|
}
|
|
52
|
+
export type AiConfigWorkersai = AiConfigWorkersaiRest | AiConfigWorkersaiBinding;
|
|
33
53
|
export interface AiConfigWorkersaiRest {
|
|
34
54
|
apiToken: string;
|
|
35
55
|
}
|
|
@@ -37,7 +57,6 @@ export interface AiConfigWorkersaiRest {
|
|
|
37
57
|
* @deprecated Not functional. Use REST instead
|
|
38
58
|
*/
|
|
39
59
|
export type AiConfigWorkersaiBinding = Ai;
|
|
40
|
-
export type AiConfigWorkersai = AiConfigWorkersaiRest | AiConfigWorkersaiBinding;
|
|
41
60
|
/**
|
|
42
61
|
* It's a UUID, but the last block is SHA256 of the request body
|
|
43
62
|
*/
|
|
@@ -74,7 +93,7 @@ export interface AiRequestConfig {
|
|
|
74
93
|
skipCache?: boolean;
|
|
75
94
|
}
|
|
76
95
|
export interface AiRequestMetadataServerInfo {
|
|
77
|
-
name: 'anthropic' | 'cloudflare' | 'openai';
|
|
96
|
+
name: 'anthropic' | 'cloudflare' | 'googleai' | 'openai';
|
|
78
97
|
}
|
|
79
98
|
export interface AiRequestMetadataServerInfoWithLocation {
|
|
80
99
|
name: `${'azure' | 'google'}-${string}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainfuse/ai-tools",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "ChainFuse",
|
|
6
6
|
"homepage": "https://github.com/ChainFuse/packages/tree/main/packages/ai-tools#readme",
|
|
@@ -48,19 +48,21 @@
|
|
|
48
48
|
},
|
|
49
49
|
"prettier": "@demosjarco/prettier-config",
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@ai-sdk/anthropic": "^1.0.
|
|
52
|
-
"@ai-sdk/azure": "^1.0.
|
|
51
|
+
"@ai-sdk/anthropic": "^1.0.8",
|
|
52
|
+
"@ai-sdk/azure": "^1.0.18",
|
|
53
|
+
"@ai-sdk/google": "^1.0.14",
|
|
53
54
|
"@ai-sdk/openai": "^1.0.5",
|
|
54
|
-
"@
|
|
55
|
-
"@chainfuse/
|
|
56
|
-
"
|
|
55
|
+
"@ai-sdk/openai-compatible": "^0.0.15",
|
|
56
|
+
"@chainfuse/helpers": "^0.6.0",
|
|
57
|
+
"@chainfuse/types": "^1.4.1",
|
|
58
|
+
"ai": "^4.0.31",
|
|
57
59
|
"chalk": "^5.4.1",
|
|
58
60
|
"haversine-distance": "^1.2.3",
|
|
59
61
|
"workers-ai-provider": "^0.0.10"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
|
-
"@cloudflare/workers-types": "^4.
|
|
63
|
-
"openai": "^4.77.
|
|
64
|
+
"@cloudflare/workers-types": "^4.20250109.0",
|
|
65
|
+
"openai": "^4.77.4"
|
|
64
66
|
},
|
|
65
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "875629e9d3ae2cb62f053f78551c3a5e4d4443f5"
|
|
66
68
|
}
|