@chainfuse/ai-tools 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base.d.mts +2 -0
- package/dist/base.mjs +16 -0
- package/dist/providers/customProviders.mjs +3 -3
- package/dist/providers/rawProviders.mjs +19 -19
- package/dist/types.d.mts +12 -1
- package/package.json +10 -10
package/dist/base.d.mts
CHANGED
|
@@ -4,4 +4,6 @@ export declare class AiBase {
|
|
|
4
4
|
protected _config: AiConfig;
|
|
5
5
|
constructor(config: AiConfig);
|
|
6
6
|
get config(): Readonly<AiConfig>;
|
|
7
|
+
protected get gatewayName(): "nocost" | "production-passive-bot" | "production-passive-human" | "production-active-bot" | "production-active-human" | "preview-passive-bot" | "preview-passive-human" | "preview-active-bot" | "preview-active-human";
|
|
8
|
+
protected get gatewayLog(): boolean;
|
|
7
9
|
}
|
package/dist/base.mjs
CHANGED
|
@@ -8,4 +8,20 @@ export class AiBase {
|
|
|
8
8
|
get config() {
|
|
9
9
|
return Object.freeze(this._config);
|
|
10
10
|
}
|
|
11
|
+
get gatewayName() {
|
|
12
|
+
if (this.config.billing.noCost) {
|
|
13
|
+
return 'nocost';
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
return `${this.config.billing.environment}-${this.config.billing.action}-${this.config.billing.user}`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
get gatewayLog() {
|
|
20
|
+
if (this.config.billing.noCost) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return this.config.billing.environment !== 'production';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
11
27
|
}
|
|
@@ -33,14 +33,14 @@ export class AiCustomProviders extends AiBase {
|
|
|
33
33
|
const lastServer = new URL(error.url).pathname.split('/')[5];
|
|
34
34
|
const compatibleServers = await new ServerSelector(this.config).closestServers(await import('@chainfuse/types/ai-tools/catalog/azure').then(({ azureCatalog }) => azureCatalog), model.modelId);
|
|
35
35
|
const lastServerIndex = compatibleServers.findIndex((s) => s.id.toLowerCase() === lastServer.toLowerCase());
|
|
36
|
-
if (args.logging ??
|
|
36
|
+
if (args.logging ?? this.gatewayLog)
|
|
37
37
|
console.error('ai', 'custom provider', this.chalk.rgb(...Helpers.uniqueIdColor(idempotencyId))(`[${idempotencyId}]`), this.chalk.red('FAIL'), compatibleServers[lastServerIndex].id, 'REMAINING', JSON.stringify(compatibleServers.slice(lastServerIndex + 1).map((s) => s.id)));
|
|
38
38
|
// Should retry with the next server
|
|
39
39
|
const leftOverServers = compatibleServers.slice(lastServerIndex + 1);
|
|
40
40
|
const errors = [error];
|
|
41
41
|
for (const nextServer of leftOverServers) {
|
|
42
42
|
try {
|
|
43
|
-
if (args.logging ??
|
|
43
|
+
if (args.logging ?? this.gatewayLog)
|
|
44
44
|
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)));
|
|
45
45
|
// Must be double awaited to prevent a promise from being returned
|
|
46
46
|
return await (await raw.azOpenai({ ...args, idempotencyId }, nextServer, (() => {
|
|
@@ -58,7 +58,7 @@ export class AiCustomProviders extends AiBase {
|
|
|
58
58
|
}
|
|
59
59
|
catch (nextServerError) {
|
|
60
60
|
if (APICallError.isInstance(nextServerError)) {
|
|
61
|
-
if (args.logging ??
|
|
61
|
+
if (args.logging ?? this.gatewayLog)
|
|
62
62
|
console.error('ai', 'custom provider', this.chalk.rgb(...Helpers.uniqueIdColor(idempotencyId))(`[${idempotencyId}]`), this.chalk.red('FAIL'), nextServer.id, 'REMAINING', JSON.stringify(leftOverServers.slice(leftOverServers.indexOf(nextServer) + 1).map((s) => s.id)));
|
|
63
63
|
errors.push(nextServerError);
|
|
64
64
|
}
|
|
@@ -6,7 +6,7 @@ export class AiRawProviders extends AiBase {
|
|
|
6
6
|
async updateGatewayLog(response, metadataHeader, startRoundTrip, modelTime) {
|
|
7
7
|
const updateMetadata = import('@chainfuse/helpers')
|
|
8
8
|
.then(({ NetHelpers }) => NetHelpers.cfApi(this.config.gateway.apiToken))
|
|
9
|
-
.then((cf) => cf.aiGateway.logs.edit(this.
|
|
9
|
+
.then((cf) => cf.aiGateway.logs.edit(this.gatewayName, response.headers.get('cf-aig-log-id'), {
|
|
10
10
|
account_id: this.config.gateway.accountId,
|
|
11
11
|
metadata: {
|
|
12
12
|
...Object.entries({
|
|
@@ -34,7 +34,7 @@ export class AiRawProviders extends AiBase {
|
|
|
34
34
|
}
|
|
35
35
|
oaiOpenai(args) {
|
|
36
36
|
return import('@ai-sdk/openai').then(async ({ createOpenAI }) => createOpenAI({
|
|
37
|
-
baseURL: new URL(['v1', this.config.gateway.accountId, this.
|
|
37
|
+
baseURL: new URL(['v1', this.config.gateway.accountId, this.gatewayName, 'openai'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
38
38
|
apiKey: this.config.providers.openAi.apiToken,
|
|
39
39
|
organization: this.config.providers.openAi.organization,
|
|
40
40
|
headers: {
|
|
@@ -61,10 +61,10 @@ export class AiRawProviders extends AiBase {
|
|
|
61
61
|
metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
|
|
62
62
|
headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
|
|
63
63
|
}
|
|
64
|
-
if (args.logging ??
|
|
64
|
+
if (args.logging ?? this.gatewayLog)
|
|
65
65
|
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));
|
|
66
66
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
67
|
-
if (args.logging ??
|
|
67
|
+
if (args.logging ?? this.gatewayLog)
|
|
68
68
|
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));
|
|
69
69
|
await this.updateGatewayLog(response, metadataHeader, startRoundTrip, response.headers.has('openai-processing-ms') ? parseInt(response.headers.get('openai-processing-ms')) : undefined);
|
|
70
70
|
// Inject it to have it available for retries
|
|
@@ -90,7 +90,7 @@ export class AiRawProviders extends AiBase {
|
|
|
90
90
|
* From the table, pick the `Latest GA release` for `Data plane - inference`
|
|
91
91
|
*/
|
|
92
92
|
apiVersion: '2024-10-21',
|
|
93
|
-
baseURL: new URL(['v1', this.config.gateway.accountId, this.
|
|
93
|
+
baseURL: new URL(['v1', this.config.gateway.accountId, this.gatewayName, 'azure-openai', server.id.toLowerCase()].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
94
94
|
headers: {
|
|
95
95
|
'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
|
|
96
96
|
...(cost && { 'cf-aig-custom-cost': JSON.stringify({ per_token_in: cost.inputTokenCost ?? undefined, per_token_out: cost.outputTokenCost ?? undefined }) }),
|
|
@@ -122,10 +122,10 @@ export class AiRawProviders extends AiBase {
|
|
|
122
122
|
metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
|
|
123
123
|
headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
|
|
124
124
|
}
|
|
125
|
-
if (args.logging ??
|
|
125
|
+
if (args.logging ?? this.gatewayLog)
|
|
126
126
|
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));
|
|
127
127
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
128
|
-
if (args.logging ??
|
|
128
|
+
if (args.logging ?? this.gatewayLog)
|
|
129
129
|
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));
|
|
130
130
|
await this.updateGatewayLog(response, metadataHeader, startRoundTrip, response.headers.has('x-envoy-upstream-service-time') ? parseInt(response.headers.get('x-envoy-upstream-service-time')) : undefined);
|
|
131
131
|
// Inject it to have it available for retries
|
|
@@ -145,7 +145,7 @@ export class AiRawProviders extends AiBase {
|
|
|
145
145
|
}
|
|
146
146
|
anthropic(args) {
|
|
147
147
|
return import('@ai-sdk/anthropic').then(async ({ createAnthropic }) => createAnthropic({
|
|
148
|
-
baseURL: new URL(['v1', this.config.gateway.accountId, this.
|
|
148
|
+
baseURL: new URL(['v1', this.config.gateway.accountId, this.gatewayName, 'anthropic'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
149
149
|
apiKey: this.config.providers.anthropic.apiToken,
|
|
150
150
|
headers: {
|
|
151
151
|
'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
|
|
@@ -170,10 +170,10 @@ export class AiRawProviders extends AiBase {
|
|
|
170
170
|
metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
|
|
171
171
|
headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
|
|
172
172
|
}
|
|
173
|
-
if (args.logging ??
|
|
173
|
+
if (args.logging ?? this.gatewayLog)
|
|
174
174
|
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));
|
|
175
175
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
176
|
-
if (args.logging ??
|
|
176
|
+
if (args.logging ?? this.gatewayLog)
|
|
177
177
|
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));
|
|
178
178
|
await this.updateGatewayLog(response, metadataHeader, startRoundTrip);
|
|
179
179
|
// Inject it to have it available for retries
|
|
@@ -256,10 +256,10 @@ export class AiRawProviders extends AiBase {
|
|
|
256
256
|
idempotencyId = `${idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
|
|
257
257
|
headers.set('X-Idempotency-Id', idempotencyId);
|
|
258
258
|
}
|
|
259
|
-
if (args.logging ??
|
|
259
|
+
if (args.logging ?? this.gatewayLog)
|
|
260
260
|
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));
|
|
261
261
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
262
|
-
if (args.logging ??
|
|
262
|
+
if (args.logging ?? this.gatewayLog)
|
|
263
263
|
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));
|
|
264
264
|
// Inject it to have it available for retries
|
|
265
265
|
const mutableHeaders = new Headers(response.headers);
|
|
@@ -305,7 +305,7 @@ export class AiRawProviders extends AiBase {
|
|
|
305
305
|
* `v1beta` is the only one that supports function calls as of now
|
|
306
306
|
* @link https://ai.google.dev/gemini-api/docs/api-versions
|
|
307
307
|
*/
|
|
308
|
-
baseURL: new URL(['v1', this.config.gateway.accountId, this.
|
|
308
|
+
baseURL: new URL(['v1', this.config.gateway.accountId, this.gatewayName, 'google-ai-studio', 'v1beta'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
309
309
|
apiKey: this.config.providers.googleAi.apiToken,
|
|
310
310
|
headers: {
|
|
311
311
|
'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
|
|
@@ -330,10 +330,10 @@ export class AiRawProviders extends AiBase {
|
|
|
330
330
|
metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
|
|
331
331
|
headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
|
|
332
332
|
}
|
|
333
|
-
if (args.logging ??
|
|
333
|
+
if (args.logging ?? this.gatewayLog)
|
|
334
334
|
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));
|
|
335
335
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
336
|
-
if (args.logging ??
|
|
336
|
+
if (args.logging ?? this.gatewayLog)
|
|
337
337
|
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));
|
|
338
338
|
await this.updateGatewayLog(response, metadataHeader, startRoundTrip);
|
|
339
339
|
// Inject it to have it available for retries
|
|
@@ -353,7 +353,7 @@ export class AiRawProviders extends AiBase {
|
|
|
353
353
|
}
|
|
354
354
|
restWorkersAi(args) {
|
|
355
355
|
return import('@ai-sdk/openai-compatible').then(async ({ createOpenAICompatible }) => createOpenAICompatible({
|
|
356
|
-
baseURL: new URL(['v1', this.config.gateway.accountId, this.
|
|
356
|
+
baseURL: new URL(['v1', this.config.gateway.accountId, this.gatewayName, 'workers-ai', 'v1'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
|
|
357
357
|
apiKey: this.config.providers.workersAi.apiToken,
|
|
358
358
|
headers: {
|
|
359
359
|
'cf-aig-authorization': `Bearer ${this.config.gateway.apiToken}`,
|
|
@@ -379,10 +379,10 @@ export class AiRawProviders extends AiBase {
|
|
|
379
379
|
metadataHeader.idempotencyId = `${metadataHeader.idempotencyId}-${(await CryptoHelpers.getHash('SHA-256', await new Request(input, rawInit).arrayBuffer())).slice(0, 12)}`;
|
|
380
380
|
headers.set('cf-aig-metadata', JSON.stringify(metadataHeader));
|
|
381
381
|
}
|
|
382
|
-
if (args.logging ??
|
|
382
|
+
if (args.logging ?? this.gatewayLog)
|
|
383
383
|
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));
|
|
384
384
|
return fetch(input, { ...rawInit, headers }).then(async (response) => {
|
|
385
|
-
if (args.logging ??
|
|
385
|
+
if (args.logging ?? this.gatewayLog)
|
|
386
386
|
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));
|
|
387
387
|
await this.updateGatewayLog(response, metadataHeader, startRoundTrip);
|
|
388
388
|
// Inject it to have it available for retries
|
|
@@ -404,7 +404,7 @@ export class AiRawProviders extends AiBase {
|
|
|
404
404
|
return import('workers-ai-provider').then(async ({ createWorkersAI }) => createWorkersAI({
|
|
405
405
|
binding: this.config.providers.workersAi,
|
|
406
406
|
gateway: {
|
|
407
|
-
id: this.
|
|
407
|
+
id: this.gatewayName,
|
|
408
408
|
...(args.cache && { cacheTtl: typeof args.cache === 'boolean' ? (args.cache ? this.cacheTtl : 0) : args.cache }),
|
|
409
409
|
...(args.skipCache && { skipCache: true }),
|
|
410
410
|
metadata: {
|
package/dist/types.d.mts
CHANGED
|
@@ -12,7 +12,18 @@ export interface AiConfig {
|
|
|
12
12
|
country?: IncomingRequestCfProperties['country'];
|
|
13
13
|
continent?: IncomingRequestCfProperties['continent'];
|
|
14
14
|
};
|
|
15
|
-
|
|
15
|
+
billing: {
|
|
16
|
+
noCost: true;
|
|
17
|
+
} | ({
|
|
18
|
+
noCost: false;
|
|
19
|
+
environment: 'production' | 'preview';
|
|
20
|
+
} & ({
|
|
21
|
+
user: 'bot';
|
|
22
|
+
action: 'passive';
|
|
23
|
+
} | {
|
|
24
|
+
user: 'human' | 'bot';
|
|
25
|
+
action: 'active';
|
|
26
|
+
}));
|
|
16
27
|
providers: AiConfigProviders;
|
|
17
28
|
backgroundContext?: ExecutionContext;
|
|
18
29
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainfuse/ai-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "ChainFuse",
|
|
6
6
|
"homepage": "https://github.com/ChainFuse/packages/tree/main/packages/ai-tools#readme",
|
|
@@ -48,21 +48,21 @@
|
|
|
48
48
|
},
|
|
49
49
|
"prettier": "@demosjarco/prettier-config",
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@ai-sdk/anthropic": "^1.2.
|
|
52
|
-
"@ai-sdk/azure": "^1.3.
|
|
53
|
-
"@ai-sdk/google": "^1.2.
|
|
51
|
+
"@ai-sdk/anthropic": "^1.2.1",
|
|
52
|
+
"@ai-sdk/azure": "^1.3.2",
|
|
53
|
+
"@ai-sdk/google": "^1.2.3",
|
|
54
54
|
"@ai-sdk/openai": "^1.0.5",
|
|
55
|
-
"@ai-sdk/openai-compatible": "^0.2.
|
|
56
|
-
"@chainfuse/helpers": "^2.
|
|
57
|
-
"@chainfuse/types": "^2.
|
|
58
|
-
"ai": "^4.2.
|
|
55
|
+
"@ai-sdk/openai-compatible": "^0.2.1",
|
|
56
|
+
"@chainfuse/helpers": "^2.2.1",
|
|
57
|
+
"@chainfuse/types": "^2.1.1",
|
|
58
|
+
"ai": "^4.2.5",
|
|
59
59
|
"chalk": "^5.4.1",
|
|
60
60
|
"haversine-distance": "^1.2.3",
|
|
61
61
|
"workers-ai-provider": "^0.2.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@cloudflare/workers-types": "^4.
|
|
64
|
+
"@cloudflare/workers-types": "^4.20250321.0",
|
|
65
65
|
"openai": "^4.89.0"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "540b2b0358f6d2602370d23eccf64c856868d3d9"
|
|
68
68
|
}
|