@iblai/iblai-js 2.11.0 → 2.11.2
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.
|
@@ -2132,7 +2132,7 @@ var analyticsAnalyticsOverview$3 = {
|
|
|
2132
2132
|
topicsChartDescription: "The most discussed topics, ranked by how many messages each one generated.",
|
|
2133
2133
|
activeUsersChartDescription: "Unique active users per day, showing how engagement changes over time.",
|
|
2134
2134
|
llmSpend: "LLM spend",
|
|
2135
|
-
llmSpendDescription: "Raw cost of every traced LLM call in the selected period, from the trace store. Billing totals live on the Cost
|
|
2135
|
+
llmSpendDescription: "Raw cost of every traced LLM call in the selected period, from the trace store. Billing totals live on the Cost tab.",
|
|
2136
2136
|
allTopics: "All topics",
|
|
2137
2137
|
topicsRankedFooter: "{shown} of {total} topics · ranked by message volume"
|
|
2138
2138
|
};
|
|
@@ -8089,7 +8089,7 @@ var analyticsChartCard$3 = {
|
|
|
8089
8089
|
adjustRangeHint: "This card only — the page range stays where it is."
|
|
8090
8090
|
};
|
|
8091
8091
|
var analyticsCostTabs$3 = {
|
|
8092
|
-
ariaLabel: "Cost
|
|
8092
|
+
ariaLabel: "Cost sections",
|
|
8093
8093
|
spend: "Spend",
|
|
8094
8094
|
usage: "Usage & latency",
|
|
8095
8095
|
traces: "Traces"
|
|
@@ -9280,7 +9280,7 @@ var analyticsAnalyticsOverview$2 = {
|
|
|
9280
9280
|
topicsChartDescription: "Les sujets les plus abordés, classés selon le nombre de messages générés.",
|
|
9281
9281
|
activeUsersChartDescription: "Utilisateurs actifs uniques par jour, pour suivre l’évolution de l’engagement.",
|
|
9282
9282
|
llmSpend: "Dépenses LLM",
|
|
9283
|
-
llmSpendDescription: "Coût brut de chaque appel LLM tracé sur la période sélectionnée, issu du magasin de traces. Les totaux de facturation sont dans l'onglet Coûts
|
|
9283
|
+
llmSpendDescription: "Coût brut de chaque appel LLM tracé sur la période sélectionnée, issu du magasin de traces. Les totaux de facturation sont dans l'onglet Coûts.",
|
|
9284
9284
|
allTopics: "Tous les sujets",
|
|
9285
9285
|
topicsRankedFooter: "{shown} sur {total} sujets · classés par volume de messages"
|
|
9286
9286
|
};
|
|
@@ -15237,7 +15237,7 @@ var analyticsChartCard$2 = {
|
|
|
15237
15237
|
adjustRangeHint: "Cette carte uniquement — la plage de la page reste inchangée."
|
|
15238
15238
|
};
|
|
15239
15239
|
var analyticsCostTabs$2 = {
|
|
15240
|
-
ariaLabel: "Sections Coûts
|
|
15240
|
+
ariaLabel: "Sections Coûts",
|
|
15241
15241
|
spend: "Dépenses",
|
|
15242
15242
|
usage: "Utilisation et latence",
|
|
15243
15243
|
traces: "Traces"
|
|
@@ -16428,7 +16428,7 @@ var analyticsAnalyticsOverview$1 = {
|
|
|
16428
16428
|
topicsChartDescription: "Los temas más tratados, ordenados por la cantidad de mensajes que generó cada uno.",
|
|
16429
16429
|
activeUsersChartDescription: "Usuarios activos únicos por día, para ver cómo cambia la participación con el tiempo.",
|
|
16430
16430
|
llmSpend: "Gasto LLM",
|
|
16431
|
-
llmSpendDescription: "Costo bruto de cada llamada LLM trazada en el período seleccionado, del almacén de trazas. Los totales de facturación están en la pestaña Costos
|
|
16431
|
+
llmSpendDescription: "Costo bruto de cada llamada LLM trazada en el período seleccionado, del almacén de trazas. Los totales de facturación están en la pestaña Costos.",
|
|
16432
16432
|
allTopics: "Todos los temas",
|
|
16433
16433
|
topicsRankedFooter: "{shown} de {total} temas · ordenados por volumen de mensajes"
|
|
16434
16434
|
};
|
|
@@ -22385,7 +22385,7 @@ var analyticsChartCard$1 = {
|
|
|
22385
22385
|
adjustRangeHint: "Solo esta tarjeta — el rango de la página no cambia."
|
|
22386
22386
|
};
|
|
22387
22387
|
var analyticsCostTabs$1 = {
|
|
22388
|
-
ariaLabel: "Secciones de Costos
|
|
22388
|
+
ariaLabel: "Secciones de Costos",
|
|
22389
22389
|
spend: "Gasto",
|
|
22390
22390
|
usage: "Uso y latencia",
|
|
22391
22391
|
traces: "Trazas"
|
|
@@ -23576,7 +23576,7 @@ var analyticsAnalyticsOverview = {
|
|
|
23576
23576
|
topicsChartDescription: "讨论最多的主题,按各自产生的消息数排序。",
|
|
23577
23577
|
activeUsersChartDescription: "每日独立活跃用户数,展示参与度随时间的变化。",
|
|
23578
23578
|
llmSpend: "LLM 支出",
|
|
23579
|
-
llmSpendDescription: "所选时段内每次被追踪的 LLM
|
|
23579
|
+
llmSpendDescription: "所选时段内每次被追踪的 LLM 调用的原始成本,来自追踪存储。计费总额在成本页。",
|
|
23580
23580
|
allTopics: "所有主题",
|
|
23581
23581
|
topicsRankedFooter: "共 {total} 个主题,显示 {shown} 个 · 按消息量排序"
|
|
23582
23582
|
};
|
|
@@ -29533,7 +29533,7 @@ var analyticsChartCard = {
|
|
|
29533
29533
|
adjustRangeHint: "仅此卡片 — 页面范围保持不变。"
|
|
29534
29534
|
};
|
|
29535
29535
|
var analyticsCostTabs = {
|
|
29536
|
-
ariaLabel: "
|
|
29536
|
+
ariaLabel: "成本分区",
|
|
29537
29537
|
spend: "支出",
|
|
29538
29538
|
usage: "用量与延迟",
|
|
29539
29539
|
traces: "追踪"
|
|
@@ -192840,111 +192840,6 @@ function CreateApiModal({ isOpen, onClose, tenantKey, username }) {
|
|
|
192840
192840
|
: t('apiTabLabels.createModal.submit') })) }) })] })] }) }), apiKey && jsx(ApiKeyModal, { isOpen: true, onClose: () => setApiKey(null), apiKey: apiKey })] }));
|
|
192841
192841
|
}
|
|
192842
192842
|
|
|
192843
|
-
/**
|
|
192844
|
-
* Small pure utilities colocated with the LLM tab.
|
|
192845
|
-
* Ported from standalone's `@/lib/utils` and `@/lib/error`.
|
|
192846
|
-
*/
|
|
192847
|
-
// Canonical provider name for any label — a backend key ("azure_openai"), a
|
|
192848
|
-
// human label ("Microsoft"), or a local model's provider ("Meta"). Folds every
|
|
192849
|
-
// alias onto one identity so the same provider from different sources compares
|
|
192850
|
-
// equal. See getProviderName.
|
|
192851
|
-
const PROVIDER_NAME_BY_ALIAS = {
|
|
192852
|
-
microsoft: 'azure_openai',
|
|
192853
|
-
azureopenai: 'azure_openai',
|
|
192854
|
-
openai: 'openai',
|
|
192855
|
-
google: 'google',
|
|
192856
|
-
gemini: 'google',
|
|
192857
|
-
meta: 'llama',
|
|
192858
|
-
metallama: 'llama',
|
|
192859
|
-
llama: 'llama',
|
|
192860
|
-
mistral: 'mistral',
|
|
192861
|
-
mistralai: 'mistral',
|
|
192862
|
-
nvidia: 'nvidia',
|
|
192863
|
-
iblchatnvidia: 'nvidia',
|
|
192864
|
-
deepseek: 'deepseek',
|
|
192865
|
-
anthropic: 'anthropic',
|
|
192866
|
-
iblchatanthropic: 'anthropic',
|
|
192867
|
-
claude: 'anthropic',
|
|
192868
|
-
groq: 'groq',
|
|
192869
|
-
perplexity: 'perplexity',
|
|
192870
|
-
xai: 'xai',
|
|
192871
|
-
bedrock: 'bedrock',
|
|
192872
|
-
amazonbedrock: 'bedrock',
|
|
192873
|
-
amazon: 'bedrock',
|
|
192874
|
-
iblchatbedrock: 'bedrock',
|
|
192875
|
-
alibaba: 'alibaba',
|
|
192876
|
-
qwen: 'alibaba',
|
|
192877
|
-
ibm: 'ibm',
|
|
192878
|
-
granite: 'ibm',
|
|
192879
|
-
// ibl.ai's own hosted provider. The backend key is `iblai` (NameEnum.IBLAI);
|
|
192880
|
-
// the extra aliases cover the `IBLChat<Vendor>` house spelling and the
|
|
192881
|
-
// dotted/spaced brand forms, which all normalize to one of these.
|
|
192882
|
-
iblai: 'iblai',
|
|
192883
|
-
ibl: 'iblai',
|
|
192884
|
-
iblchatibl: 'iblai',
|
|
192885
|
-
iblchatiblai: 'iblai',
|
|
192886
|
-
};
|
|
192887
|
-
/**
|
|
192888
|
-
* Canonical provider name for any label, case- and punctuation-insensitive.
|
|
192889
|
-
* Folds backend keys and human/display labels onto one identity — e.g.
|
|
192890
|
-
* `getProviderName('Microsoft') === 'azure_openai'`,
|
|
192891
|
-
* `getProviderName('Meta') === 'llama'`, `getProviderName('Google') === 'google'`.
|
|
192892
|
-
* Unknown providers return their normalized (lowercased, alphanumeric-only) form.
|
|
192893
|
-
*
|
|
192894
|
-
* This is the single source of truth for provider identity, which matters as
|
|
192895
|
-
* soon as on-device models enter the picture: the local catalog labels its
|
|
192896
|
-
* providers the human way ("Meta", "Microsoft", "Alibaba") while the backend LLM
|
|
192897
|
-
* list uses wire keys ("llama", "azure_openai"). Comparing the two raw would
|
|
192898
|
-
* render a duplicate card for the same vendor.
|
|
192899
|
-
*/
|
|
192900
|
-
function getProviderName(llmProvider) {
|
|
192901
|
-
var _a;
|
|
192902
|
-
const normalized = (llmProvider !== null && llmProvider !== void 0 ? llmProvider : '').toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
192903
|
-
return (_a = PROVIDER_NAME_BY_ALIAS[normalized]) !== null && _a !== void 0 ? _a : normalized;
|
|
192904
|
-
}
|
|
192905
|
-
|
|
192906
|
-
// Logo + display name keyed by canonical provider name (see getProviderName).
|
|
192907
|
-
const PROVIDER_DETAILS_BY_NAME = {
|
|
192908
|
-
groq: { logo: '/llm-groq-provider.png', name: 'Groq' },
|
|
192909
|
-
nvidia: { logo: '/llm-nvidia-provider.webp', name: 'NVIDIA' },
|
|
192910
|
-
azure_openai: { logo: '/llm-microsoft-provider.png', name: 'Microsoft' },
|
|
192911
|
-
openai: { logo: '/llm-openai-provider-2.svg', name: 'OpenAI' },
|
|
192912
|
-
mistral: { logo: '/llm-mistral-provider.jpeg', name: 'Mistral' },
|
|
192913
|
-
google: { logo: '/llm-google-provider.svg', name: 'Google' },
|
|
192914
|
-
llama: { logo: '/llm-llama-provider.jpeg', name: 'Meta' },
|
|
192915
|
-
anthropic: { logo: '/llm-claude-provider.png', name: 'Anthropic' },
|
|
192916
|
-
perplexity: { logo: '/llm-perplexity-provider.webp', name: 'Perplexity' },
|
|
192917
|
-
deepseek: { logo: '/llm-deepseek-provider.png', name: 'DeepSeek' },
|
|
192918
|
-
xai: { logo: '/llm-xai-provider.jpg', name: 'xAI' },
|
|
192919
|
-
bedrock: { logo: '/llm-amazon-provider.png', name: 'Amazon' },
|
|
192920
|
-
alibaba: { logo: '/llm-alibaba-provider.png', name: 'Alibaba' },
|
|
192921
|
-
ibm: { logo: '/llm-ibm-provider.png', name: 'IBM' },
|
|
192922
|
-
iblai: { logo: '/llm-iblai-provider.png', name: 'ibl.ai' },
|
|
192923
|
-
};
|
|
192924
|
-
/**
|
|
192925
|
-
* Returns the canonical logo path and display name for an LLM provider.
|
|
192926
|
-
*
|
|
192927
|
-
* Resolution goes through {@link getProviderName}, so a backend wire key
|
|
192928
|
-
* (`azure_openai`), a human label (`Microsoft`) and an on-device catalog's
|
|
192929
|
-
* provider string (`Meta`, `Alibaba`) all land on the same entry — the provider
|
|
192930
|
-
* grid merges cloud and on-device providers into one list, so the two spellings
|
|
192931
|
-
* have to agree.
|
|
192932
|
-
*
|
|
192933
|
-
* `logo` is a static-root path (e.g. `/llm-amazon-provider.png`); the package
|
|
192934
|
-
* ships the canonical assets under `@iblai/web-containers/public/` — copy them
|
|
192935
|
-
* into your app's static-root (`public/` for Next.js) so the paths resolve.
|
|
192936
|
-
*/
|
|
192937
|
-
function getLLMProviderDetails(llmProvider, llmName) {
|
|
192938
|
-
var _a;
|
|
192939
|
-
const name = getProviderName(llmProvider);
|
|
192940
|
-
// OpenAI and Google use a model-specific logo when a concrete model is named.
|
|
192941
|
-
if (name === 'openai' && llmName)
|
|
192942
|
-
return { logo: '/llm-openai-provider.jpg', name: 'OpenAI' };
|
|
192943
|
-
if (name === 'google' && llmName)
|
|
192944
|
-
return { logo: '/llm-gemini-provider.png', name: 'Google' };
|
|
192945
|
-
return (_a = PROVIDER_DETAILS_BY_NAME[name]) !== null && _a !== void 0 ? _a : { logo: '/llm-generic-provider.png', name: llmProvider };
|
|
192946
|
-
}
|
|
192947
|
-
|
|
192948
192843
|
// Dynamic schema based on selected provider
|
|
192949
192844
|
const createDynamicSchema$1 = (schemaFields) => {
|
|
192950
192845
|
const schemaObj = {
|
|
@@ -193173,14 +193068,9 @@ function CreateLLMModal({ isOpen, onClose, tenantKey, onSuccess }) {
|
|
|
193173
193068
|
}
|
|
193174
193069
|
}, children: [jsx(SelectTrigger, { children: jsx(SelectValue, { placeholder: t('llmsTabCreateLlmModal.selectProviderPlaceholder') }) }), jsx(SelectContent, { children: availableProviders.map((provider) => {
|
|
193175
193070
|
var _a, _b;
|
|
193176
|
-
|
|
193177
|
-
|
|
193178
|
-
|
|
193179
|
-
const providerLogo = ((_a = provider === null || provider === void 0 ? void 0 : provider.service_info) === null || _a === void 0 ? void 0 : _a.logo) ||
|
|
193180
|
-
getLLMProviderDetails(provider.name).logo;
|
|
193181
|
-
const providerName = ((_b = provider === null || provider === void 0 ? void 0 : provider.service_info) === null || _b === void 0 ? void 0 : _b.display_name) ||
|
|
193182
|
-
provider.name;
|
|
193183
|
-
return (jsx(SelectItem, { value: provider.name, children: jsxs("div", { className: "flex items-center gap-2", children: [jsx("img", { src: providerLogo, alt: provider.name, className: "w-4 h-4 rounded-sm object-contain" }), providerName || provider.name] }) }, provider.name));
|
|
193071
|
+
const providerLogo = (_a = provider.service_info) === null || _a === void 0 ? void 0 : _a.logo;
|
|
193072
|
+
const providerName = ((_b = provider.service_info) === null || _b === void 0 ? void 0 : _b.display_name) || provider.name;
|
|
193073
|
+
return (jsx(SelectItem, { value: provider.name, children: jsxs("div", { className: "flex items-center gap-2", children: [providerLogo ? (jsx("img", { src: providerLogo, alt: providerName, className: "w-4 h-4 rounded-sm object-contain" })) : (jsx("span", { children: "\uD83D\uDD11" })), providerName] }) }, provider.name));
|
|
193184
193074
|
}) })] }), shouldShowError && (jsx("p", { className: "text-red-500 text-xs", children: (_b = field.state.meta.errors[0]) === null || _b === void 0 ? void 0 : _b.message }))] }));
|
|
193185
193075
|
} })), isCredentialsSchemaLoading && (jsxs("div", { className: "flex items-center justify-center py-4", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin mr-2" }), jsx("span", { className: "text-sm text-gray-600", children: t('llmsTabCreateLlmModal.loadingProviderConfigurations') })] })), showProviderForm && !isCredentialsSchemaLoading && !isAzureOpenAI && (jsx(Fragment$1, { children: schemaFields.map((fieldName) => (jsx(form.Field, { name: fieldName, children: (field) => {
|
|
193186
193076
|
var _a, _b;
|
|
@@ -193267,26 +193157,18 @@ function IntegrationLLMsTab({ tenantKey }) {
|
|
|
193267
193157
|
}
|
|
193268
193158
|
};
|
|
193269
193159
|
return (jsxs("div", { className: "space-y-4", children: [jsx(InfoBanner, { icon: jsx(Bot, { className: "w-5 h-5" }), children: t('llmsTabIntegrationLlmsTab.infoBannerText') }), jsx("div", { className: "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-x-auto", children: jsxs("table", { className: "w-full text-sm min-w-[600px]", children: [jsx("thead", { className: "bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600", children: jsxs("tr", { children: [jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: t('llmsTabIntegrationLlmsTab.colName') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: t('llmsTabIntegrationLlmsTab.colKey') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[50px]" })] }) }), jsx("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: isMaskedCredentialsLoading ? (jsx("tr", { children: jsx("td", { colSpan: 3, className: "px-6 py-8 text-center text-sm text-gray-500", children: t('llmsTabIntegrationLlmsTab.loading') }) })) : maskedCredentials.length === 0 ? (jsx("tr", { children: jsx("td", { colSpan: 3, className: "px-6 py-8 text-center text-sm text-gray-500", children: t('llmsTabIntegrationLlmsTab.noLlmKeysFound') }) })) : (maskedCredentials.map((cred, idx) => {
|
|
193270
|
-
var _a, _b, _c;
|
|
193160
|
+
var _a, _b, _c, _d, _e;
|
|
193271
193161
|
const provider = ((_a = cred.service_info) === null || _a === void 0 ? void 0 : _a.display_name) || cred.name;
|
|
193272
|
-
//
|
|
193273
|
-
|
|
193274
|
-
// degrade to a generic key emoji.
|
|
193275
|
-
let logoUrl;
|
|
193276
|
-
let logoAlt;
|
|
193277
|
-
if ((_b = cred.service_info) === null || _b === void 0 ? void 0 : _b.logo) {
|
|
193278
|
-
logoUrl = cred.service_info.logo;
|
|
193279
|
-
logoAlt = cred.service_info.display_name || cred.service_info.name;
|
|
193280
|
-
}
|
|
193281
|
-
else {
|
|
193282
|
-
logoUrl = getLLMProviderDetails(cred.name).logo;
|
|
193283
|
-
}
|
|
193162
|
+
// Logos are backend-owned (`service_info.logo`); no bundled fallback.
|
|
193163
|
+
const logoUrl = (_b = cred.service_info) === null || _b === void 0 ? void 0 : _b.logo;
|
|
193284
193164
|
const isAzure = isAzureOpenAI(cred);
|
|
193285
193165
|
const azureModels = isAzure ? getAzureModels(cred) : [];
|
|
193286
193166
|
const isExpanded = expandedRows.has(cred.name);
|
|
193287
|
-
return (jsxs(React__default.Fragment, { children: [jsxs("tr", { children: [jsx("td", { className: "px-6 py-4", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx("img", { src: logoUrl, alt:
|
|
193167
|
+
return (jsxs(React__default.Fragment, { children: [jsxs("tr", { children: [jsx("td", { className: "px-6 py-4", children: jsxs("div", { className: "flex items-center gap-2", children: [logoUrl ? (jsx("img", { src: logoUrl, alt: ((_c = cred.service_info) === null || _c === void 0 ? void 0 : _c.display_name) ||
|
|
193168
|
+
((_d = cred.service_info) === null || _d === void 0 ? void 0 : _d.name) ||
|
|
193169
|
+
cred.name, className: "w-6 h-6 rounded-sm object-contain" })) : (jsx("span", { className: "text-lg", children: '🔑' })), jsx("span", { className: "font-normal text-gray-900 dark:text-gray-100", children: provider || cred.name }), isAzure && azureModels.length > 0 && (jsx("button", { type: "button", onClick: () => toggleRowExpansion(cred.name), className: "p-0.5 hover:bg-gray-100 rounded", children: isExpanded ? (jsx(ChevronUp, { className: "h-4 w-4 text-gray-500" })) : (jsx(ChevronDown, { className: "h-4 w-4 text-gray-500" })) }))] }) }), jsx("td", { className: "px-6 py-4 font-mono text-sm text-gray-900 dark:text-gray-100", children: isAzure ? (jsx("span", { className: "text-xs text-gray-500", children: t('llmsTabIntegrationLlmsTab.azureModelCount', {
|
|
193288
193170
|
count: azureModels.length,
|
|
193289
|
-
}) })) : (String((
|
|
193171
|
+
}) })) : (String((_e = cred === null || cred === void 0 ? void 0 : cred.value) === null || _e === void 0 ? void 0 : _e.key).slice(0, 15) || '') }), jsx("td", { className: "px-6 py-4", children: jsx(Button$1, { variant: "ghost", size: "sm", className: "cursor-pointer mr-2", disabled: isDeletingIntegration || isDeletingCredential, onClick: () => handleDeleteCredential(cred.name, cred.platform, false), children: jsx(Trash, { className: "h-4 w-4" }) }) })] }), isAzure &&
|
|
193290
193172
|
isExpanded &&
|
|
193291
193173
|
azureModels.map((model, modelIdx) => (jsxs("tr", { children: [jsx("td", { className: "px-6 py-4 pl-12", children: jsx("span", { className: "text-sm text-gray-700", children: model.modelName.toLowerCase() }) }), jsx("td", { className: "px-6 py-4 font-mono text-sm text-gray-600", children: model.maskedKey.slice(0, 15) || '' }), jsx("td", { className: "px-6 py-4", children: jsx(Button$1, { variant: "ghost", size: "sm", className: "cursor-pointer", disabled: isDeletingIntegration || isDeletingCredential, onClick: () => handleDeleteCredential(cred.name, cred.platform, false, model.modelName), children: jsx(Trash, { className: "h-4 w-4" }) }) })] }, `${cred.name}-${model.modelName}-${modelIdx}`)))] }, cred.name + idx));
|
|
193292
193174
|
})) })] }) })] }));
|
|
@@ -229549,7 +229431,7 @@ const useOverview = ({ tenantKey, mentorId, usergroupIds, }) => {
|
|
|
229549
229431
|
...((usergroupIds === null || usergroupIds === void 0 ? void 0 : usergroupIds.length) ? { usergroup_ids: usergroupIds } : {}),
|
|
229550
229432
|
});
|
|
229551
229433
|
// LLM spend joins the KPI row so cost is visible before anyone opens the
|
|
229552
|
-
// Cost
|
|
229434
|
+
// Cost tab. It follows the page range; unavailable renders as an
|
|
229553
229435
|
// em-dash, never $0.00.
|
|
229554
229436
|
const globalFilters = (_o = useAnalyticsGlobalFilters()) === null || _o === void 0 ? void 0 : _o.filters;
|
|
229555
229437
|
const { data: llmSpendData, isLoading: isLoadingLlmSpend, error: llmSpendError, } = useGetLlmUsageMetricsQuery({
|
|
@@ -229959,7 +229841,7 @@ const defaultTabs = [
|
|
|
229959
229841
|
},
|
|
229960
229842
|
{
|
|
229961
229843
|
// The unified cost surface: ClickHouse billing + Langfuse LLM usage.
|
|
229962
|
-
label: 'Cost
|
|
229844
|
+
label: 'Cost',
|
|
229963
229845
|
value: 'financial',
|
|
229964
229846
|
},
|
|
229965
229847
|
{
|
|
@@ -230507,7 +230389,7 @@ const byProvider = (models) => {
|
|
|
230507
230389
|
.sort((a, b) => b.total_cost - a.total_cost);
|
|
230508
230390
|
};
|
|
230509
230391
|
/**
|
|
230510
|
-
* Spend view-model for the Cost
|
|
230392
|
+
* Spend view-model for the Cost tab, backed by the ClickHouse
|
|
230511
230393
|
* `/api/ai-analytics/` cost endpoints (KPIs, per-model, per-user) and the
|
|
230512
230394
|
* Langfuse `llm-usage` metrics resource (the daily spend series). The
|
|
230513
230395
|
* deprecated `/api/analytics/financial/` family is gone; the return shape is
|
|
@@ -230716,7 +230598,7 @@ const formatCompactNumber = (value) => {
|
|
|
230716
230598
|
const formatLatencySeconds = (value) => `${value.toFixed(2)}s`;
|
|
230717
230599
|
const UNAVAILABLE = '—';
|
|
230718
230600
|
/**
|
|
230719
|
-
* The Langfuse side of the Cost
|
|
230601
|
+
* The Langfuse side of the Cost tab: tokens, calls, latency percentiles
|
|
230720
230602
|
* and spend breakdowns per service and model. Ranked per-user/per-session
|
|
230721
230603
|
* totals live on the Spend sub-tab (ClickHouse) — Langfuse cannot group by
|
|
230722
230604
|
* those dimensions.
|
|
@@ -230788,7 +230670,7 @@ function useDebouncedValue(value, delay) {
|
|
|
230788
230670
|
}
|
|
230789
230671
|
/**
|
|
230790
230672
|
* Tenant user picker for the analytics filter rows — memory, transcripts and
|
|
230791
|
-
* the Cost
|
|
230673
|
+
* the Cost traces list.
|
|
230792
230674
|
* Both endpoints behind it do the searching, so the dropdown only pages in the
|
|
230793
230675
|
* first {@link USERS_PAGE_SIZE} matches for whatever is typed rather than
|
|
230794
230676
|
* filtering client-side.
|
|
@@ -231105,7 +230987,7 @@ function SpendTab({ tenantKey, mentorId: currentMentorId, userId, onOpenUserTrac
|
|
|
231105
230987
|
}) }), jsxs("div", { className: "flex items-center space-x-2", children: [jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 p-2 !w-auto !inline-flex bg-transparent", onClick: handleFirstPage, disabled: costPerUserPage === 1, children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsFinancialStats.goToFirstPage') }), jsx(ChevronsLeft, { className: "h-4 w-4" })] }), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 p-2 !w-auto !inline-flex bg-transparent", onClick: handlePreviousPage, disabled: costPerUserPage === 1, children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsFinancialStats.goToPreviousPage') }), jsx(ChevronLeft, { className: "h-4 w-4" })] }), generatePageNumbers().map((page, index) => (jsx(React__default.Fragment, { children: page === '...' ? (jsx("span", { className: "px-2 text-gray-500", children: "..." })) : (jsx(Button$1, { variant: costPerUserPage === page ? 'default' : 'outline', size: "sm", className: `h-8 p-3 !w-auto !inline-flex ${costPerUserPage === page ? 'bg-blue-50 text-blue-600' : 'bg-transparent'}`, onClick: () => setCostPerUserPage(page), children: page })) }, index))), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 p-2 !w-auto !inline-flex bg-transparent", onClick: handleNextPage, disabled: costPerUserPage === detailedCostPerUserData.total_pages, children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsFinancialStats.goToNextPage') }), jsx(ChevronRight, { className: "h-4 w-4" })] }), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 p-2 !w-auto !inline-flex bg-transparent", onClick: handleLastPage, disabled: costPerUserPage === detailedCostPerUserData.total_pages, children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsFinancialStats.goToLastPage') }), jsx(ChevronsRight, { className: "h-4 w-4" })] })] })] }))] }) }) })] }));
|
|
231106
230988
|
}
|
|
231107
230989
|
/**
|
|
231108
|
-
* The Cost
|
|
230990
|
+
* The Cost tab: one surface over two backends, split where the backends
|
|
231109
230991
|
* actually split. Spend is ClickHouse (billing truth: marked-up USD, ranked
|
|
231110
230992
|
* per-user history); Usage & latency and Traces are the Langfuse proxy
|
|
231111
230993
|
* (tokens, latency percentiles, per-call drill-down). Every card names its
|
|
@@ -237407,6 +237289,41 @@ function SignupButton({ authUrl, tenantKey, redirectTo, label = 'Sign Up', onCli
|
|
|
237407
237289
|
}
|
|
237408
237290
|
SignupButton.displayName = 'SignupButton';
|
|
237409
237291
|
|
|
237292
|
+
/**
|
|
237293
|
+
* A provider's logo as the backend serves it. Provider naming and artwork are
|
|
237294
|
+
* owned by the API (`LLMResponse.logo`, `ExternalServiceInfo.logo`), so there
|
|
237295
|
+
* is no bundled fallback image: a provider without a logo renders a neutral
|
|
237296
|
+
* initial instead, keeping the card layout intact.
|
|
237297
|
+
*/
|
|
237298
|
+
function LLMProviderLogo({ logo, label, alt = label, size = 32, className, }) {
|
|
237299
|
+
if (logo) {
|
|
237300
|
+
return (jsx(Image$4, { src: logo, alt: alt, className: cn('h-full w-full object-contain', className), width: size, height: size, loading: "lazy" }));
|
|
237301
|
+
}
|
|
237302
|
+
return (jsx("span", { role: "img", "aria-label": alt, "data-testid": "llm-provider-logo-placeholder", className: cn('flex h-full w-full items-center justify-center rounded bg-gray-100 text-xs font-semibold text-gray-500 uppercase', className), children: label.charAt(0) }));
|
|
237303
|
+
}
|
|
237304
|
+
|
|
237305
|
+
/**
|
|
237306
|
+
* Small pure utilities colocated with the LLM tab.
|
|
237307
|
+
* Ported from standalone's `@/lib/utils` and `@/lib/error`.
|
|
237308
|
+
*/
|
|
237309
|
+
/**
|
|
237310
|
+
* The label a provider renders with: the backend's `display_name` when it
|
|
237311
|
+
* ships one, else its raw `name`. There is deliberately no frontend map behind
|
|
237312
|
+
* this — naming (and the logo next to it) is owned by the backend.
|
|
237313
|
+
*/
|
|
237314
|
+
function llmProviderLabel(provider) {
|
|
237315
|
+
return provider.display_name || provider.name;
|
|
237316
|
+
}
|
|
237317
|
+
/**
|
|
237318
|
+
* The label a chat model renders with: the backend's `display_name` (`GPT-4.1
|
|
237319
|
+
* Mini`) when it ships one, else the raw wire key (`gpt-4.1-mini`). Same rule
|
|
237320
|
+
* as {@link llmProviderLabel}; every model list (LLM tab, sandbox) goes through
|
|
237321
|
+
* here so they never drift apart.
|
|
237322
|
+
*/
|
|
237323
|
+
function llmModelLabel(model) {
|
|
237324
|
+
return model.display_name || model.llm_name;
|
|
237325
|
+
}
|
|
237326
|
+
|
|
237410
237327
|
function OverlayModal({ open, onClose, title, description, className, children, }) {
|
|
237411
237328
|
const t = useT();
|
|
237412
237329
|
const [mounted, setMounted] = useState(false);
|
|
@@ -237442,15 +237359,22 @@ function canSwitchProvider(providers, name) {
|
|
|
237442
237359
|
function LLMProviderModal({ isOpen, onClose, onSelect, llmProvider, isSelecting, mentorSettings, llms, }) {
|
|
237443
237360
|
const t = useT();
|
|
237444
237361
|
const [searchQuery, setSearchQuery] = useState('');
|
|
237362
|
+
const providerLabel = llmProviderLabel(llmProvider);
|
|
237445
237363
|
const filteredLLMs = useMemo(() => {
|
|
237446
|
-
|
|
237364
|
+
const query = searchQuery.toLowerCase();
|
|
237365
|
+
// Match either label, same as the LLM tab's picker: rows show
|
|
237366
|
+
// `display_name`, but the raw key stays searchable.
|
|
237367
|
+
return llmProvider === null || llmProvider === void 0 ? void 0 : llmProvider.chat_models.filter((llm) => {
|
|
237368
|
+
var _a;
|
|
237369
|
+
return llm.llm_name.toLowerCase().includes(query) ||
|
|
237370
|
+
((_a = llm.display_name) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(query);
|
|
237371
|
+
});
|
|
237447
237372
|
}, [searchQuery, llmProvider]);
|
|
237448
237373
|
const switchLLMAllowed = canSwitchLLm(llmProvider);
|
|
237449
237374
|
const switchProviderAllowed = canSwitchProvider(llms, llmProvider.name);
|
|
237450
237375
|
return (jsxs(OverlayModal, { open: isOpen, onClose: onClose, title: t('clawSandboxLlmProviderModal.title'), description: t('clawSandboxLlmProviderModal.description', { providerName: llmProvider.name }), className: "max-w-4xl", children: [jsx("p", { className: "text-sm text-gray-600", children: t('clawSandboxLlmProviderModal.chooseLlmHint') }), jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" }), jsx(Input, { placeholder: t('clawSandboxLlmProviderModal.searchPlaceholder'), className: "py-6 pl-9", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), autoComplete: "off", disabled: isSelecting })] }), jsx("div", { className: "grid max-h-[60vh] grid-cols-1 gap-4 overflow-y-auto pr-2 sm:grid-cols-2 lg:grid-cols-3", children: filteredLLMs.map((llm) => {
|
|
237451
237376
|
const isActive = (mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.llm_name) === llm.llm_name &&
|
|
237452
237377
|
(mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.llm_provider) === llmProvider.name;
|
|
237453
|
-
const providerDetails = getLLMProviderDetails(llmProvider.name, llm.llm_name);
|
|
237454
237378
|
const isDisabled = !switchLLMAllowed || isSelecting || isActive || !switchProviderAllowed;
|
|
237455
237379
|
return (jsxs("button", { disabled: isDisabled, onClick: () => {
|
|
237456
237380
|
onSelect(llmProvider.name, llm.llm_name);
|
|
@@ -237458,11 +237382,9 @@ function LLMProviderModal({ isOpen, onClose, onSelect, llmProvider, isSelecting,
|
|
|
237458
237382
|
'cursor-not-allowed border-gray-200 bg-white': isDisabled,
|
|
237459
237383
|
'hover:border-blue-500 hover:bg-blue-50': !isDisabled,
|
|
237460
237384
|
'cursor-not-allowed border-blue-500 bg-blue-50': isActive,
|
|
237461
|
-
}), children: [jsx("span", { className: "flex h-8 w-8 items-center justify-center overflow-hidden rounded-lg", children: jsx(
|
|
237462
|
-
providerName:
|
|
237463
|
-
}), className: cn(
|
|
237464
|
-
grayscale: isDisabled && !isActive,
|
|
237465
|
-
}), width: 32, height: 32, loading: "lazy" }) }), jsx("span", { className: "text-left text-sm font-medium text-[#646464]", children: llm.llm_name })] }, llm.llm_name));
|
|
237385
|
+
}), children: [jsx("span", { className: "flex h-8 w-8 items-center justify-center overflow-hidden rounded-lg", children: jsx(LLMProviderLogo, { logo: llmProvider.logo, label: providerLabel, alt: t('clawSandboxLlmProviderModal.providerIconAlt', {
|
|
237386
|
+
providerName: providerLabel,
|
|
237387
|
+
}), className: cn({ grayscale: isDisabled && !isActive }) }) }), jsx("span", { className: "text-left text-sm font-medium text-[#646464]", children: llmModelLabel(llm) })] }, llm.llm_name));
|
|
237466
237388
|
}) })] }));
|
|
237467
237389
|
}
|
|
237468
237390
|
|
|
@@ -237633,6 +237555,13 @@ function SandboxConfig({ platformKey, mentorUniqueId, username }) {
|
|
|
237633
237555
|
const availableLLMProviders = useMemo(() => (llmProviders !== null && llmProviders !== void 0 ? llmProviders : []), [llmProviders]);
|
|
237634
237556
|
const filteredLLMProviders = useMemo(() => availableLLMProviders.filter((provider) => provider.name.toLowerCase().includes(llmSearchQuery.toLowerCase())), [availableLLMProviders, llmSearchQuery]);
|
|
237635
237557
|
const currentModel = parseModelIdentifier(agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.model);
|
|
237558
|
+
const currentModelProvider = availableLLMProviders.find((provider) => provider.name === currentModel.provider);
|
|
237559
|
+
// Same backend `display_name` the pickers render, so the trigger reads
|
|
237560
|
+
// `GPT-4.1 Mini` rather than the `gpt-4.1-mini` wire key stored in `model`.
|
|
237561
|
+
const currentChatModel = currentModelProvider === null || currentModelProvider === void 0 ? void 0 : currentModelProvider.chat_models.find((llm) => llm.llm_name === currentModel.llmName);
|
|
237562
|
+
const currentModelLabel = currentChatModel
|
|
237563
|
+
? llmModelLabel(currentChatModel)
|
|
237564
|
+
: currentModel.llmName || (agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.model);
|
|
237636
237565
|
const isUpdatingLLM = isUpdatingAgent;
|
|
237637
237566
|
// Push fails server-side with "No configuration to push" when every AgentConfig
|
|
237638
237567
|
// field is empty. Detect that locally so we can deny the click and tell the user
|
|
@@ -237920,17 +237849,17 @@ function SandboxConfig({ platformKey, mentorUniqueId, username }) {
|
|
|
237920
237849
|
}), children: ((_f = mentorConfig === null || mentorConfig === void 0 ? void 0 : mentorConfig.last_config_push_status) === null || _f === void 0 ? void 0 : _f.toLocaleLowerCase()) === 'success' ? (jsx(CircleCheck, { className: "h-4 w-4 text-green-600" })) : (jsx(CircleX, { className: "h-4 w-4 text-red-600" })) }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { className: "capitalize", children: mentorConfig.last_config_push_status }) })] }) }))] }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { className: "inline-flex", children: jsxs(Button$1, { variant: "outline", size: "sm", onClick: handlePush, disabled: isPushing || !hasAgentConfiguration, "aria-disabled": isPushing || !hasAgentConfiguration, children: [isPushing ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin mr-2" })) : (jsx(RefreshCw, { className: "h-4 w-4 mr-2" })), t('clawSandboxSandboxConfig.push')] }) }) }), !hasAgentConfiguration && (jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { children: t('clawSandboxSandboxConfig.setAgentConfigBeforePushing') }) }))] }) })] }), jsxs("div", { className: "flex items-center justify-between rounded-lg border p-6", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: t('clawSandboxSandboxConfig.model') }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('clawSandboxSandboxConfig.modelInfoAriaLabel'), children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { children: t('clawSandboxSandboxConfig.modelTooltip') }) })] }) })] }), jsx("div", { className: "flex items-center gap-3", children: (agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.model) ? (jsxs("button", { type: "button", className: "flex items-center gap-2 text-sm font-medium text-[#646464] transition-colors hover:text-[#484848] disabled:opacity-50", onClick: () => {
|
|
237921
237850
|
setLlmSearchQuery('');
|
|
237922
237851
|
setShowLLMPicker(true);
|
|
237923
|
-
}, disabled: isUpdatingLLM, "aria-label": t('clawSandboxSandboxConfig.changeModel'), children: [jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-white border", children: jsx(
|
|
237852
|
+
}, disabled: isUpdatingLLM, "aria-label": t('clawSandboxSandboxConfig.changeModel'), children: [jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-white border", children: jsx(LLMProviderLogo, { logo: currentModelProvider === null || currentModelProvider === void 0 ? void 0 : currentModelProvider.logo, label: currentModel.llmName || currentModel.provider, alt: t('clawSandboxSandboxConfig.providerLogoAlt', {
|
|
237924
237853
|
name: currentModel.llmName || currentModel.provider,
|
|
237925
|
-
}), className: "h-5 w-5
|
|
237854
|
+
}), size: 20, className: "h-5 w-5" }) }), jsx("span", { className: "max-w-[200px] truncate", children: currentModelLabel }), jsx(ChevronDown, { className: "h-4 w-4 text-gray-500" })] })) : (jsx(Button$1, { variant: "outline", size: "sm", onClick: () => {
|
|
237926
237855
|
setLlmSearchQuery('');
|
|
237927
237856
|
setShowLLMPicker(true);
|
|
237928
237857
|
}, disabled: isUpdatingLLM, children: t('clawSandboxSandboxConfig.selectModel') })) })] }), jsxs(OverlayModal, { open: showDisconnectConfirm, onClose: () => setShowDisconnectConfirm(false), title: t('clawSandboxSandboxConfig.disconnectInstanceTitle'), className: "max-w-md", children: [jsx("p", { className: "text-sm text-gray-600", children: t('clawSandboxSandboxConfig.disconnectInstanceConfirm', {
|
|
237929
237858
|
name: (_g = connectedInstance === null || connectedInstance === void 0 ? void 0 : connectedInstance.name) !== null && _g !== void 0 ? _g : mentorConfig.server_name,
|
|
237930
237859
|
}) }), jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [jsx(Button$1, { variant: "outline", onClick: () => setShowDisconnectConfirm(false), children: t('clawSandboxSandboxConfig.cancel') }), jsx(Button$1, { onClick: handleDisconnect, disabled: isDeleting, className: "bg-red-600 text-white hover:bg-red-700", children: isDeleting
|
|
237931
237860
|
? t('clawSandboxSandboxConfig.disconnecting')
|
|
237932
|
-
: t('clawSandboxSandboxConfig.disconnect') })] })] }), showLLMPicker &&
|
|
237933
|
-
const
|
|
237861
|
+
: t('clawSandboxSandboxConfig.disconnect') })] })] }), showLLMPicker && (jsx(OverlayModal, { open: true, onClose: closeLLMPicker, title: t('clawSandboxSandboxConfig.selectProviderTitle'), description: t('clawSandboxSandboxConfig.selectProviderDescription'), className: "max-w-3xl", children: !resolvedUsername ? (jsx("p", { className: "py-6 text-center text-sm text-gray-500", children: t('clawSandboxSandboxConfig.noUsernameForProviders') })) : (jsxs(Fragment$1, { children: [jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-500" }), jsx(Input, { id: "llm-search", name: "llm-search", type: "search", placeholder: t('clawSandboxSandboxConfig.searchProvidersPlaceholder'), className: "w-full py-6 pl-9", value: llmSearchQuery, onChange: (e) => setLlmSearchQuery(e.target.value) })] }), isLoadingLLMProviders ? (jsx("div", { className: "flex items-center justify-center py-10", children: jsx(LoaderCircle, { className: "h-5 w-5 animate-spin text-blue-500" }) })) : isLLMProvidersError ? (jsx("p", { className: "py-6 text-center text-sm text-red-500", children: t('clawSandboxSandboxConfig.failedToLoadProviders') })) : filteredLLMProviders.length === 0 ? (jsx("p", { className: "py-6 text-center text-sm text-gray-500", children: t('clawSandboxSandboxConfig.noProvidersAvailable') })) : (jsx("div", { className: "mt-2 grid max-h-[50vh] grid-cols-1 gap-4 overflow-y-auto pr-2 sm:grid-cols-2 lg:grid-cols-3", children: filteredLLMProviders.map((provider) => {
|
|
237862
|
+
const providerLabel = llmProviderLabel(provider);
|
|
237934
237863
|
const isSelected = currentModel.provider === provider.name;
|
|
237935
237864
|
return (jsxs("button", { type: "button", className: cn('flex cursor-pointer items-center gap-3 rounded-lg border border-gray-200 bg-white p-4 text-left shadow-sm transition-shadow hover:shadow-md', { 'border-blue-500': isSelected }), onClick: () => {
|
|
237936
237865
|
setSelectedLLMProvider({
|
|
@@ -237943,10 +237872,10 @@ function SandboxConfig({ platformKey, mentorUniqueId, username }) {
|
|
|
237943
237872
|
main_has_credentials: provider.main_has_credentials,
|
|
237944
237873
|
can_use_main_keys: provider.can_use_main_keys,
|
|
237945
237874
|
});
|
|
237946
|
-
}, children: [jsx("div", { className: "h-8 w-8 flex-shrink-0", children: jsx(
|
|
237947
|
-
name:
|
|
237948
|
-
})
|
|
237949
|
-
}) }))] })) })), selectedLLMProvider && (jsx(LLMProviderModal, { isOpen: true, onClose:
|
|
237875
|
+
}, children: [jsx("div", { className: "h-8 w-8 flex-shrink-0", children: jsx(LLMProviderLogo, { logo: provider.logo, label: providerLabel, alt: t('clawSandboxSandboxConfig.providerLogoAlt', {
|
|
237876
|
+
name: providerLabel,
|
|
237877
|
+
}) }) }), jsx("span", { className: "text-sm font-medium text-gray-900", children: providerLabel })] }, provider.id));
|
|
237878
|
+
}) }))] })) })), selectedLLMProvider && (jsx(LLMProviderModal, { isOpen: true, onClose: () => setSelectedLLMProvider(null), onSelect: handleSelectLLM, llmProvider: selectedLLMProvider, isSelecting: isUpdatingLLM, mentorSettings: {
|
|
237950
237879
|
llm_name: currentModel.llmName,
|
|
237951
237880
|
llm_provider: currentModel.provider,
|
|
237952
237881
|
}, llms: availableLLMProviders }))] })) : null;
|