@llmnative/react 1.15.5 → 1.17.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.
@@ -43,6 +43,14 @@ export type AIConfig = {
43
43
  anthropicApiKey?: string;
44
44
  mistralApiKey?: string;
45
45
  glmApiKey?: string;
46
+ /** Cloudflare Workers AI — both apiToken and accountId are required (the account id is part of every URL). */
47
+ cloudflare?: {
48
+ apiToken?: string;
49
+ accountId?: string;
50
+ defaultModel?: string;
51
+ /** Keep models that require the Workers Paid plan in model discovery. Default: false. */
52
+ includePaidModels?: boolean;
53
+ };
46
54
  openAICompatible?: {
47
55
  apiKey?: string;
48
56
  baseUrl?: string;
@@ -145,6 +145,8 @@ export interface I18nDict {
145
145
  editSettings: string;
146
146
  attachFiles: string;
147
147
  dropFilesHere: string;
148
+ modelPricing: string;
149
+ modelPriceNotFound: string;
148
150
  attachmentsNotSupported: string;
149
151
  run: string;
150
152
  runFailed: string;
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import type { AIModelPricing } from '../../providers/ai/AIProvider';
2
3
  import { type EditorCommand } from '../ui/fields/ContextMenu';
3
4
  /**
4
5
  * Chatbot — l'input/composer AI condiviso, estratto da `Prompt` (CR-071): textarea,
@@ -32,7 +33,12 @@ export interface ChatbotSubmitPayload {
32
33
  export interface ChatbotModelOption {
33
34
  label: string;
34
35
  value: string;
36
+ /** Input/output price per 1M tokens, shown next to the label; a free model (both 0) gets
37
+ * a highlighted row. `null` = price looked up but not found (flagged in the row);
38
+ * omitted = the consumer has no pricing at all, nothing is shown. */
39
+ pricing?: AIModelPricing | null;
35
40
  }
41
+ export declare const isFreeModelOption: (option: ChatbotModelOption) => boolean;
36
42
  export interface ChatbotProps {
37
43
  /** Attributo `name` nativo sulla textarea sottostante — puro attributo DOM, MAI un
38
44
  * binding a Form (Chatbot non lo legge/scrive): serve solo a chi ha bisogno di un
@@ -78,8 +78,8 @@ export { loadGoogleMaps } from './providers/googleMaps/loadGoogleMaps';
78
78
  export type { GoogleMapsConfig } from './providers/googleMaps/loadGoogleMaps';
79
79
  export { useEmailProvider, EmailProvider } from './providers/email/EmailProviderContext';
80
80
  export { GmailEmailProvider } from './providers/email/google/GmailEmailProvider';
81
- export type { AIRequestOptions, AIAttachment, AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIModelCatalog, AIProviderDefinition, AICompleteRequest, AICompleteResult, AIConversationTurn, AIToolDefinition, AIToolCall, AIToolResult, } from './providers/ai';
82
- export { createAIProviderRegistry, getAIModelCatalog, formatAIModelRef, parseAIModelRef, AI_PROVIDER_DEFINITIONS, AI_PROVIDER_DESCRIPTORS, OPENAI_COMPATIBLE_PROVIDER_DESCRIPTOR, toProviderDescriptor } from './providers/ai';
81
+ export type { AIRequestOptions, AIAttachment, AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIModelPricing, DiscoveredAIModel, AIProviderCapabilities, AIModelCatalog, AIProviderDefinition, AICompleteRequest, AICompleteResult, AIConversationTurn, AIToolDefinition, AIToolCall, AIToolResult, CloudflareProviderOptions, } from './providers/ai';
82
+ export { createAIProviderRegistry, getAIModelCatalog, formatAIModelRef, parseAIModelRef, isFreeAIModel, AI_PROVIDER_DEFINITIONS, AI_PROVIDER_DESCRIPTORS, OPENAI_COMPATIBLE_PROVIDER_DESCRIPTOR, CLOUDFLARE_PROVIDER_DESCRIPTOR, createCloudflareProviderDefinition, toProviderDescriptor } from './providers/ai';
83
83
  export type { ProviderDescriptor, ProviderCredentialField } from './providers/ProviderDescriptor';
84
84
  export { useAIProvider, useAIProviderRegistry, AIProvider } from './providers/ai/AIProviderContext';
85
85
  export { proxyFetch, useProxy, configureProxy, isProxyEnabled } from './providers/proxy';
@@ -1,12 +1,24 @@
1
1
  import type { PromptVariables } from '../../conf/Prompt';
2
2
  import type { ProviderConfigurable } from '../ProviderConfiguration';
3
+ /** Token prices of a model, in `currency` per 1M tokens. `input === 0 && output === 0` means
4
+ * the model is free. */
5
+ export interface AIModelPricing {
6
+ input: number;
7
+ output: number;
8
+ currency: 'USD';
9
+ /** Where the price comes from: the provider's own model listing, or the models.dev catalog. */
10
+ source: 'provider' | 'models.dev';
11
+ }
3
12
  export interface AIModelDescriptor {
4
13
  id: string;
5
14
  provider: string;
6
15
  model: string;
7
16
  label: string;
8
17
  deprecated?: boolean;
18
+ /** Absent = price not found (neither in the provider listing nor on models.dev). */
19
+ pricing?: AIModelPricing;
9
20
  }
21
+ export declare const isFreeAIModel: (model: Pick<AIModelDescriptor, "pricing">) => boolean;
10
22
  export interface AIProviderCapabilities {
11
23
  models: AIModelDescriptor[];
12
24
  supportsTemperature?: boolean;
@@ -0,0 +1,27 @@
1
+ import type { ProviderDescriptor } from '../ProviderDescriptor';
2
+ import type { AIModelPricing } from './AIProvider';
3
+ import { type AIProviderDefinition } from './shared';
4
+ type CloudflareModelProperty = {
5
+ property_id?: string;
6
+ value?: unknown;
7
+ };
8
+ type CloudflareModel = {
9
+ name?: string;
10
+ properties?: CloudflareModelProperty[];
11
+ };
12
+ export type CloudflareProviderOptions = {
13
+ accountId: string;
14
+ defaultModel?: string;
15
+ /** Keep models flagged `require_workers_paid` in discovery (they fail with 403 on the Free plan). */
16
+ includePaidModels?: boolean;
17
+ };
18
+ /** The catalog's `price` property: `[{ unit: 'per M input tokens', price, currency }, { unit:
19
+ * 'per M output tokens', … }]`. Anything else resolves to undefined and models.dev fills in. */
20
+ export declare const parseCloudflarePricing: (model: CloudflareModel) => AIModelPricing | undefined;
21
+ /** Built per account: the account id is part of every Workers AI URL, while
22
+ * AIProviderDefinition.complete()/discoverModels() only ever receive the API token. */
23
+ export declare const createCloudflareProviderDefinition: ({ accountId, defaultModel, includePaidModels, }: CloudflareProviderOptions) => AIProviderDefinition;
24
+ /** "Connect this provider" metadata — the working definition needs an account id, so (like
25
+ * openai-compatible) it is built only once one is configured; see createAIProviderRegistry. */
26
+ export declare const CLOUDFLARE_PROVIDER_DESCRIPTOR: ProviderDescriptor;
27
+ export {};
@@ -2,15 +2,21 @@ import type { AIConfig } from '../../Config';
2
2
  import type { ProviderDescriptor } from '../ProviderDescriptor';
3
3
  import type { AIProviderAdapter } from './AIProvider';
4
4
  import { type AIProviderDefinition } from './shared';
5
- export type { AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIRequestOptions, AIAttachment, AICompleteRequest, AICompleteResult, AIConversationTurn, AIToolDefinition, AIToolCall, AIToolResult, } from './AIProvider';
6
- export { formatAIModelRef, parseAIModelRef } from './AIProvider';
5
+ export type { AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIModelPricing, AIProviderCapabilities, AIRequestOptions, AIAttachment, AICompleteRequest, AICompleteResult, AIConversationTurn, AIToolDefinition, AIToolCall, AIToolResult, } from './AIProvider';
6
+ export { formatAIModelRef, parseAIModelRef, isFreeAIModel } from './AIProvider';
7
+ export type { DiscoveredAIModel } from './shared';
7
8
  export type { AIModelCatalog, AIProviderDefinition } from './shared';
8
9
  export { getAIModelCatalog } from './shared';
10
+ export { CLOUDFLARE_PROVIDER_DESCRIPTOR, createCloudflareProviderDefinition } from './cloudflare';
11
+ export type { CloudflareProviderOptions } from './cloudflare';
9
12
  export declare const AI_PROVIDER_DEFINITIONS: AIProviderDefinition[];
10
13
  /** Generic "connect this provider" view of an AIProviderDefinition — the shape a CMS/admin
11
14
  * UI needs (label, description, credential fields, where to find them), independent of the
12
15
  * runtime completion contract (discoverModels/complete) it also carries. */
13
16
  export declare const toProviderDescriptor: (definition: AIProviderDefinition) => ProviderDescriptor;
17
+ /** Includes Cloudflare: like openai-compatible its working definition needs a second credential
18
+ * (the account id) before it can be built, but unlike openai-compatible it is a fixed, named
19
+ * vendor — a "connect" UI should list it alongside the others. */
14
20
  export declare const AI_PROVIDER_DESCRIPTORS: ProviderDescriptor[];
15
21
  /** The user-configurable "bring your own endpoint" slot — metadata-only counterpart of the
16
22
  * dynamic definition getDynamicAIProviderDefinitions() builds once a baseUrl is actually
@@ -0,0 +1,23 @@
1
+ import type { AIModelDescriptor, AIModelPricing } from './AIProvider';
2
+ /** Public, CORS-open catalog (`access-control-allow-origin: *`) of models with their token
3
+ * prices, in USD per 1M tokens — the same unit AIModelPricing uses. */
4
+ export declare const MODELS_DEV_URL = "https://models.dev/api.json";
5
+ /** Compact cache shape: providerKey → modelId → [input, output]. The raw catalog is ~5 MB,
6
+ * this keeps only the providers above (~700 entries). */
7
+ type PricingIndex = Record<string, Record<string, [number, number]>>;
8
+ type ModelsDevCatalog = Record<string, {
9
+ models?: Record<string, {
10
+ cost?: {
11
+ input?: unknown;
12
+ output?: unknown;
13
+ };
14
+ }>;
15
+ }>;
16
+ export declare const buildPricingIndex: (catalog: ModelsDevCatalog) => PricingIndex;
17
+ export declare const lookupModelsDevPricing: (index: PricingIndex, providerId: string, model: string) => AIModelPricing | undefined;
18
+ /** Fills `pricing` from models.dev on the models the provider listing left without one.
19
+ * Models are never dropped: a model with no match simply keeps `pricing` undefined. */
20
+ export declare const withModelsDevPricing: (providerId: string, models: AIModelDescriptor[]) => Promise<AIModelDescriptor[]>;
21
+ /** Test-only: drops the in-flight promise between cases. */
22
+ export declare const resetModelsDevPricingForTests: () => void;
23
+ export {};
@@ -1,4 +1,4 @@
1
- import type { AIProviderDefinition, BuiltInAIProviderId } from './shared';
1
+ import type { AIProviderDefinition, BuiltInAIProviderId, DiscoveredAIModel } from './shared';
2
2
  import type { AIConversationTurn, AICompleteResult, AIToolDefinition } from './AIProvider';
3
3
  type OpenAICompatibleDefinitionOptions = {
4
4
  id: BuiltInAIProviderId;
@@ -15,6 +15,8 @@ type OpenAICompatibleDefinitionOptions = {
15
15
  credentialsHint?: string;
16
16
  /** Override the default validateApiKey when the models endpoint is public or uses a non-standard error format. */
17
17
  validateApiKey?: AIProviderDefinition['validateApiKey'];
18
+ /** Maps one `/models` entry — for providers whose listing also reports prices (OpenRouter). */
19
+ mapModelEntry?: (entry: Record<string, unknown>) => string | DiscoveredAIModel | undefined;
18
20
  };
19
21
  /** Esportate per riuso da provider "chat completions"-simili ma non costruiti tramite
20
22
  * createOpenAICompatibleProviderDefinition (vedi opencode.ts) — stesso wire format OpenAI,
@@ -37,5 +39,5 @@ export declare function parseOpenAIResponse(response: {
37
39
  message?: Record<string, unknown>;
38
40
  }>;
39
41
  } | null): AICompleteResult | null;
40
- export declare const createOpenAICompatibleProviderDefinition: ({ id, label, description, configKey, requiredConfigKeys, defaultModel, fallbackModels, baseUrl, modelsUrl, chatCompletionsUrl, dashboardUrl, credentialsHint, validateApiKey: validateApiKeyOverride, }: OpenAICompatibleDefinitionOptions) => AIProviderDefinition;
42
+ export declare const createOpenAICompatibleProviderDefinition: ({ id, label, description, configKey, requiredConfigKeys, defaultModel, fallbackModels, baseUrl, modelsUrl, chatCompletionsUrl, dashboardUrl, credentialsHint, validateApiKey: validateApiKeyOverride, mapModelEntry, }: OpenAICompatibleDefinitionOptions) => AIProviderDefinition;
41
43
  export {};
@@ -1 +1,5 @@
1
+ import type { AIModelPricing } from './AIProvider';
2
+ /** `/models` prices are USD per token as decimal strings; `-1` marks routers with a variable
3
+ * price (openrouter/auto…), which count as "price not found". */
4
+ export declare const parseOpenRouterPricing: (pricing: unknown) => AIModelPricing | undefined;
1
5
  export declare const OPENROUTER_PROVIDER_DEFINITION: import("./shared").AIProviderDefinition;
@@ -1,7 +1,13 @@
1
1
  import { type ProviderConfigurationState } from '../ProviderConfiguration';
2
2
  import type { ProviderCredentialField } from '../ProviderDescriptor';
3
- import type { AICompleteRequest, AICompleteResult, AIKeyValidationResult, AIModelDescriptor, AIProviderAdapter, AIProviderCapabilities, AIRequestOptions } from './AIProvider';
4
- export type BuiltInAIProviderId = 'openai' | 'openrouter' | 'opencode' | 'openai-compatible' | 'deepseek' | 'gemini' | 'anthropic' | 'mistral' | 'glm';
3
+ import type { AICompleteRequest, AICompleteResult, AIKeyValidationResult, AIModelDescriptor, AIModelPricing, AIProviderAdapter, AIProviderCapabilities, AIRequestOptions } from './AIProvider';
4
+ export type BuiltInAIProviderId = 'openai' | 'openrouter' | 'opencode' | 'openai-compatible' | 'deepseek' | 'gemini' | 'anthropic' | 'mistral' | 'glm' | 'cloudflare';
5
+ /** A discovered model carrying the price its provider listing already reports (OpenRouter,
6
+ * Cloudflare). Models discovered as a bare id get their price from models.dev instead. */
7
+ export type DiscoveredAIModel = {
8
+ model: string;
9
+ pricing?: AIModelPricing;
10
+ };
5
11
  export type AIProviderDefinition = {
6
12
  id: BuiltInAIProviderId;
7
13
  label: string;
@@ -20,7 +26,7 @@ export type AIProviderDefinition = {
20
26
  /** Short guidance on where in the dashboard to find the credential. */
21
27
  credentialsHint?: string;
22
28
  capabilities?: Omit<AIProviderCapabilities, 'models'>;
23
- discoverModels: (apiKey: string) => Promise<string[]>;
29
+ discoverModels: (apiKey: string) => Promise<Array<string | DiscoveredAIModel>>;
24
30
  complete: (apiKey: string, request: Required<Pick<AICompleteRequest, 'prompt' | 'model'>> & AIRequestOptions & Pick<AICompleteRequest, 'history' | 'tools' | 'signal' | 'logId'>) => Promise<AICompleteResult | null>;
25
31
  /**
26
32
  * Per-provider auth check. When omitted, the default implementation in
@@ -35,7 +35,7 @@ export type DataDriverName = 'dbRealtime' | 'firestoreDb' | 'supabaseDb' | 'mock
35
35
  export type StorageDriverName = 'firestorage' | 'supabaseStorage';
36
36
  export type AuthDriverName = 'googleAuth' | 'firebaseAuth' | 'dropboxAuth' | 'supabaseAuth';
37
37
  export type EmailDriverName = 'gmail';
38
- export type AIDriverName = 'openai' | 'openrouter' | 'opencode' | 'openai-compatible' | 'deepseek' | 'gemini' | 'anthropic' | 'mistral';
38
+ export type AIDriverName = 'openai' | 'openrouter' | 'opencode' | 'openai-compatible' | 'deepseek' | 'gemini' | 'anthropic' | 'mistral' | 'cloudflare';
39
39
  export type CredentialsDriverName = 'googleServiceAccount';
40
40
  export type ServicesConfig = {
41
41
  data?: DataDriverName | string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llmnative/react",
3
- "version": "1.15.5",
3
+ "version": "1.17.0",
4
4
  "description": "LLM-native React framework for deterministic UI generation. Data-driven by default, schema-driven optional. Ultra-low token consumption — built for AI agents, not just humans.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",