@chainfuse/ai-tools 0.9.0 → 0.10.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 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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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.config.environment, response.headers.get('cf-aig-log-id'), {
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.config.environment, 'openai'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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.config.environment, 'azure-openai', server.id.toLowerCase()].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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.config.environment, 'anthropic'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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.config.environment, 'google-ai-studio', 'v1beta'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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.config.environment, 'workers-ai', 'v1'].join('/'), 'https://gateway.ai.cloudflare.com').toString(),
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 ?? !this.config.environment.startsWith('production'))
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 ?? !this.config.environment.startsWith('production'))
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.config.environment,
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
- environment: 'internal' | 'production-passive' | 'preview-passive' | 'production-active' | 'preview-active';
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.9.0",
3
+ "version": "0.10.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.0",
52
- "@ai-sdk/azure": "^1.3.0",
53
- "@ai-sdk/google": "^1.2.1",
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.0",
56
- "@chainfuse/helpers": "^2.1.1",
57
- "@chainfuse/types": "^2.0.0",
58
- "ai": "^4.2.0",
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.20250320.0",
64
+ "@cloudflare/workers-types": "^4.20250321.0",
65
65
  "openai": "^4.89.0"
66
66
  },
67
- "gitHead": "60babb051a4005d8495655784427e446fc7c7bcb"
67
+ "gitHead": "f0eaab21228260be471a6fac0874068139677035"
68
68
  }