@lastbrain/ai-ui-react 1.0.62 → 1.0.64

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.
@@ -4,7 +4,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
4
4
  * Provider d'authentification LastBrain
5
5
  * Gère l'état de connexion, la session et les appels IA
6
6
  */
7
- import { createContext, useContext, useEffect, useCallback, useState, } from "react";
7
+ import { createContext, useContext, useEffect, useCallback, useMemo, useState, } from "react";
8
+ import { createLBClient } from "@lastbrain/ai-ui-core";
8
9
  const LBContext = createContext(undefined);
9
10
  export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", proxyUrl = "/api/lastbrain", onStatusChange, onAuthChange, }) {
10
11
  const [state, setState] = useState({
@@ -18,61 +19,70 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
18
19
  const [isLoadingStatus, setIsLoadingStatus] = useState(false);
19
20
  const [isLoadingStorage, setIsLoadingStorage] = useState(false);
20
21
  const [storageLastFetch, setStorageLastFetch] = useState(0);
22
+ const lbClient = useMemo(() => createLBClient({
23
+ baseUrl: proxyUrl,
24
+ mode: process.env.LB_API_KEY ? "env-key" : "auto",
25
+ selectedApiKeyId: state.selectedKey?.id,
26
+ }), [proxyUrl, state.selectedKey?.id]);
21
27
  /**
22
28
  * Vérifie si une session existe au chargement
23
29
  */
24
30
  const checkSession = useCallback(async () => {
25
31
  try {
26
- const response = await fetch(`${proxyUrl}/auth/session/verify`, {
27
- credentials: "include",
28
- });
29
- if (response.ok) {
30
- const session = await response.json();
31
- // Récupérer les infos utilisateur depuis /auth/status
32
- try {
33
- const statusResponse = await fetch(`${proxyUrl}/auth/status`, {
34
- credentials: "include",
35
- });
36
- if (statusResponse.ok) {
37
- const statusData = await statusResponse.json();
38
- setState({
39
- status: "ready",
40
- session,
41
- user: {
42
- id: session.userId,
43
- email: statusData.user?.email || "",
44
- },
45
- });
32
+ const session = await lbClient.verifySession();
33
+ if (session) {
34
+ const userData = await lbClient.getUser().catch(() => null);
35
+ const activeKey = userData?.apiKeyActive
36
+ ? {
37
+ id: userData.apiKeyActive.id,
38
+ name: userData.apiKeyActive.name,
39
+ keyPrefix: userData.apiKeyActive.prefix,
40
+ scopes: userData.apiKeyActive.scopes || [],
41
+ isActive: true,
42
+ createdAt: "",
46
43
  }
47
- else {
48
- // Fallback sans email
49
- setState({
50
- status: "ready",
51
- session,
52
- user: {
53
- id: session.userId,
54
- email: "",
55
- },
56
- });
57
- }
58
- }
59
- catch (statusError) {
60
- console.error("[LBProvider] Failed to fetch status:", statusError);
61
- // Fallback sans email
44
+ : undefined;
45
+ setApiKeys(userData?.apiKeys || []);
46
+ setState({
47
+ status: "ready",
48
+ session,
49
+ user: {
50
+ id: session.userId,
51
+ email: userData?.user?.email || "",
52
+ },
53
+ selectedKey: activeKey,
54
+ });
55
+ onStatusChange?.("ready");
56
+ }
57
+ else {
58
+ // Supabase session mode (no lb_session cookie): try user endpoint directly
59
+ const userData = await lbClient.getUser().catch(() => null);
60
+ if (userData?.user?.id) {
61
+ const activeKey = userData?.apiKeyActive
62
+ ? {
63
+ id: userData.apiKeyActive.id,
64
+ name: userData.apiKeyActive.name,
65
+ keyPrefix: userData.apiKeyActive.prefix,
66
+ scopes: userData.apiKeyActive.scopes || [],
67
+ isActive: true,
68
+ createdAt: "",
69
+ }
70
+ : undefined;
71
+ setApiKeys(userData.apiKeys || []);
62
72
  setState({
63
73
  status: "ready",
64
- session,
65
74
  user: {
66
- id: session.userId,
67
- email: "",
75
+ id: userData.user.id,
76
+ email: userData.user.email || "",
68
77
  },
78
+ selectedKey: activeKey,
69
79
  });
80
+ onStatusChange?.("ready");
81
+ }
82
+ else {
83
+ setState({ status: "needs_auth" });
84
+ onStatusChange?.("needs_auth");
70
85
  }
71
- onStatusChange?.("ready");
72
- }
73
- else {
74
- setState({ status: "needs_auth" });
75
- onStatusChange?.("needs_auth");
76
86
  }
77
87
  }
78
88
  catch (error) {
@@ -80,7 +90,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
80
90
  setState({ status: "needs_auth" });
81
91
  onStatusChange?.("needs_auth");
82
92
  }
83
- }, [proxyUrl, onStatusChange]);
93
+ }, [lbClient, onStatusChange]);
84
94
  useEffect(() => {
85
95
  checkSession();
86
96
  }, [checkSession]);
@@ -89,23 +99,8 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
89
99
  */
90
100
  const fetchApiKeys = useCallback(async (token) => {
91
101
  try {
92
- console.log("[LBProvider] Fetching API keys with token:", token.substring(0, 20) + "...");
93
- const response = await fetch(`${proxyUrl}/public/user/api-keys`, {
94
- headers: {
95
- Authorization: `Bearer ${token}`,
96
- "Content-Type": "application/json",
97
- },
98
- credentials: "include",
99
- });
100
- console.log("[LBProvider] API keys response status:", response.status);
101
- if (!response.ok) {
102
- const errorData = await response.json().catch(() => ({}));
103
- console.error("[LBProvider] Failed to fetch API keys:", errorData);
104
- throw new Error(errorData.message || "Failed to fetch API keys");
105
- }
106
- const data = await response.json();
107
- console.log("[LBProvider] API keys received:", data);
108
- const keys = data.apiKeys || data;
102
+ const data = await lbClient.getUser(token);
103
+ const keys = data.apiKeys || [];
109
104
  setApiKeys(keys);
110
105
  return keys;
111
106
  }
@@ -113,7 +108,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
113
108
  console.error("[LBProvider] Failed to fetch API keys:", error);
114
109
  throw error;
115
110
  }
116
- }, [proxyUrl]);
111
+ }, [lbClient]);
117
112
  /**
118
113
  * Sélectionne une clé API et crée une session
119
114
  */
@@ -121,22 +116,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
121
116
  try {
122
117
  console.log("[LBProvider] Selecting API key:", apiKeyId);
123
118
  setState((prev) => ({ ...prev, status: "loading" }));
124
- const response = await fetch(`${proxyUrl}/auth/session`, {
125
- method: "POST",
126
- headers: {
127
- "Content-Type": "application/json",
128
- Authorization: `Bearer ${token}`,
129
- },
130
- body: JSON.stringify({ api_key_id: apiKeyId }),
131
- credentials: "include",
132
- });
133
- console.log("[LBProvider] Session response status:", response.status);
134
- if (!response.ok) {
135
- const errorData = await response.json().catch(() => ({}));
136
- console.error("[LBProvider] Failed to create session:", errorData);
137
- throw new Error(errorData.message || "Failed to create session");
138
- }
139
- const sessionResult = await response.json();
119
+ const sessionResult = await lbClient.selectApiKey(apiKeyId, token);
140
120
  console.log("[LBProvider] Session created successfully:", sessionResult);
141
121
  setState({
142
122
  status: "ready",
@@ -162,7 +142,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
162
142
  });
163
143
  throw error;
164
144
  }
165
- }, [proxyUrl, state.user, onStatusChange, onAuthChange]);
145
+ }, [lbClient, state.user, onStatusChange, onAuthChange]);
166
146
  /**
167
147
  * Connexion utilisateur (étape 1 : login)
168
148
  * Retourne le token et les clés API sans créer de session
@@ -171,24 +151,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
171
151
  try {
172
152
  console.log("[LBProvider] Login attempt:", email);
173
153
  setState((prev) => ({ ...prev, status: "loading" }));
174
- const response = await fetch(`${proxyUrl}/auth/login`, {
175
- method: "POST",
176
- headers: { "Content-Type": "application/json" },
177
- body: JSON.stringify({ email, password }),
178
- credentials: "include",
179
- });
180
- console.log("[LBProvider] Login response status:", response.status);
181
- if (!response.ok) {
182
- const error = await response.json();
183
- const errorMessage = error.message || "Login failed";
184
- console.error("[LBProvider] Login failed:", errorMessage);
185
- setState({
186
- status: "needs_auth",
187
- error: errorMessage,
188
- });
189
- return { success: false, error: errorMessage };
190
- }
191
- const result = await response.json();
154
+ const result = await lbClient.login(email, password);
192
155
  console.log("[LBProvider] Login successful:", result.user?.email);
193
156
  console.log("[LBProvider] Access token received:", result.accessToken ? "YES" : "NO");
194
157
  console.log("[LBProvider] Token length:", result.accessToken?.length || 0);
@@ -259,7 +222,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
259
222
  });
260
223
  return { success: false, error: message };
261
224
  }
262
- }, [proxyUrl, fetchApiKeys, selectApiKey]);
225
+ }, [lbClient, fetchApiKeys, selectApiKey]);
263
226
  /**
264
227
  * Récupère le status API basique (balance, API key info) - RAPIDE
265
228
  */
@@ -271,22 +234,43 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
271
234
  }
272
235
  setIsLoadingStatus(true);
273
236
  try {
274
- const response = await fetch(`${proxyUrl}/auth/status?fast=true`, {
275
- credentials: "include",
276
- });
277
- if (response.ok) {
278
- const data = await response.json();
279
- setBasicStatus(data);
280
- // Combiner avec le storage existant si disponible
281
- const combinedStatus = {
282
- ...data,
283
- storage: storageStatus?.storage || data.storage,
284
- };
285
- setApiStatus(combinedStatus);
237
+ let data;
238
+ try {
239
+ data = await lbClient.getStatus();
286
240
  }
287
- else {
288
- setBasicStatus(null);
241
+ catch {
242
+ // Backward compatibility: older backends may not expose /auth/status
243
+ const userData = await lbClient.getUser();
244
+ data = {
245
+ authType: userData.authType,
246
+ user: userData.user,
247
+ apiKey: userData.apiKeyActive,
248
+ api_key: userData.apiKeyActive,
249
+ balance: {
250
+ used: 0,
251
+ total: userData.balance?.sellValueUsd || 0,
252
+ percentage: 0,
253
+ },
254
+ };
289
255
  }
256
+ const normalizedStatus = {
257
+ ...data,
258
+ authType: data?.authType,
259
+ user: data?.user,
260
+ apiKey: data?.apiKey || data?.api_key,
261
+ api_key: data?.api_key || data?.apiKey,
262
+ balance: data?.balance || {
263
+ used: 0,
264
+ total: 0,
265
+ percentage: 0,
266
+ },
267
+ };
268
+ setBasicStatus(normalizedStatus);
269
+ const combinedStatus = {
270
+ ...normalizedStatus,
271
+ storage: storageStatus?.storage,
272
+ };
273
+ setApiStatus(combinedStatus);
290
274
  }
291
275
  catch (error) {
292
276
  console.error("[LBProvider] Failed to fetch basic status:", error);
@@ -295,7 +279,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
295
279
  finally {
296
280
  setIsLoadingStatus(false);
297
281
  }
298
- }, [proxyUrl, state.status, storageStatus]);
282
+ }, [lbClient, state.status, storageStatus]);
299
283
  /**
300
284
  * Récupère le storage - LENT avec cache (5 minutes)
301
285
  */
@@ -315,35 +299,16 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
315
299
  }
316
300
  setIsLoadingStorage(true);
317
301
  try {
318
- // Essayer l'endpoint spécialisé storage d'abord
319
- let response = await fetch(`${proxyUrl}/auth/status/storage`, {
320
- credentials: "include",
321
- });
322
- // Si 404, faire un fallback vers l'endpoint normal (backward compatibility)
323
- if (!response.ok && response.status === 404) {
324
- console.log("[LBProvider] Storage endpoint not available, using fallback");
325
- response = await fetch(`${proxyUrl}/auth/status`, {
326
- credentials: "include",
327
- });
328
- }
329
- if (response.ok) {
330
- const data = await response.json();
331
- // Si c'est la réponse complète (fallback), extraire juste le storage
332
- const storageData = data.storage ? { storage: data.storage } : data;
333
- setStorageStatus(storageData);
334
- setStorageLastFetch(now);
335
- // Combiner avec le basic status
336
- const combinedStatus = {
337
- ...basicStatus,
338
- storage: storageData.storage,
339
- };
340
- setApiStatus(combinedStatus);
341
- }
342
- else {
343
- console.warn("[LBProvider] Failed to fetch storage status:", response.status);
344
- // Arrêter les tentatives répétées si échec persistant
345
- setStorageLastFetch(now); // Marquer comme essayé pour éviter la boucle
346
- }
302
+ const data = await lbClient.getStorageStatus();
303
+ const storageData = data?.storage ? { storage: data.storage } : data;
304
+ setStorageStatus(storageData);
305
+ setStorageLastFetch(now);
306
+ // Combiner avec le basic status
307
+ const combinedStatus = {
308
+ ...basicStatus,
309
+ storage: storageData?.storage,
310
+ };
311
+ setApiStatus(combinedStatus);
347
312
  }
348
313
  catch (error) {
349
314
  console.error("[LBProvider] Failed to fetch storage status:", error);
@@ -353,7 +318,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
353
318
  finally {
354
319
  setIsLoadingStorage(false);
355
320
  }
356
- }, [proxyUrl, state.status, basicStatus, storageLastFetch]);
321
+ }, [lbClient, state.status, basicStatus, storageLastFetch]);
357
322
  /**
358
323
  * Sélectionne une clé API avec le token déjà stocké (après login)
359
324
  */
@@ -367,35 +332,26 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
367
332
  * Change l'API key active - utilise la bonne méthode selon le contexte
368
333
  */
369
334
  const switchApiKey = useCallback(async (apiKeyId) => {
370
- if (state.status === "ready") {
371
- // Utiliser la route de switch avec session
372
- const response = await fetch(`${proxyUrl}/auth/session/switch-api-key`, {
373
- method: "POST",
374
- credentials: "include",
375
- headers: { "Content-Type": "application/json" },
376
- body: JSON.stringify({ api_key_id: apiKeyId }),
377
- });
378
- if (!response.ok) {
379
- const errorData = await response.json().catch(() => ({}));
380
- throw new Error(errorData.error || "Failed to switch API key");
335
+ if (state.status === "ready" || accessToken) {
336
+ await lbClient.selectApiKey(apiKeyId, accessToken);
337
+ const selectedKey = apiKeys.find((key) => key.id === apiKeyId);
338
+ if (selectedKey) {
339
+ setState((prev) => ({
340
+ ...prev,
341
+ selectedKey,
342
+ }));
381
343
  }
382
- // Refresh le status après le changement
383
344
  await refreshBasicStatus();
384
- // Refresh storage en arrière-plan
385
345
  setTimeout(() => refreshStorageStatus(), 100);
386
346
  }
387
- else if (accessToken) {
388
- // Utiliser la méthode avec access token
389
- await selectApiKey(accessToken, apiKeyId);
390
- }
391
347
  else {
392
348
  throw new Error("No valid authentication method available");
393
349
  }
394
350
  }, [
395
351
  state.status,
396
- proxyUrl,
397
352
  accessToken,
398
- selectApiKey,
353
+ apiKeys,
354
+ lbClient,
399
355
  refreshBasicStatus,
400
356
  refreshStorageStatus,
401
357
  ]);
@@ -404,10 +360,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
404
360
  */
405
361
  const logout = useCallback(async () => {
406
362
  try {
407
- await fetch(`${proxyUrl}/auth/session/logout`, {
408
- method: "POST",
409
- credentials: "include",
410
- });
363
+ await lbClient.logout();
411
364
  }
412
365
  catch (error) {
413
366
  console.error("[LBProvider] Logout failed:", error);
@@ -416,10 +369,15 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
416
369
  setState({ status: "needs_auth" });
417
370
  setApiKeys([]);
418
371
  setAccessToken(undefined);
372
+ // Reset tous les statuts après logout
373
+ setApiStatus(null);
374
+ setBasicStatus(null);
375
+ setStorageStatus(null);
376
+ setStorageLastFetch(0);
419
377
  onStatusChange?.("needs_auth");
420
378
  onAuthChange?.(); // Refresh provider after logout
421
379
  }
422
- }, [proxyUrl, onStatusChange, onAuthChange]);
380
+ }, [lbClient, onStatusChange, onAuthChange]);
423
381
  /**
424
382
  * Recharge la session
425
383
  */
@@ -435,25 +393,14 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
435
393
  return;
436
394
  }
437
395
  try {
438
- console.log("[LBProvider] Fetching API keys with session...");
439
- const response = await fetch(`${proxyUrl}/auth/api-keys`, {
440
- credentials: "include",
441
- });
442
- if (response.ok) {
443
- const data = await response.json();
444
- console.log("[LBProvider] API keys received:", data);
445
- setApiKeys(data.apiKeys || []);
446
- }
447
- else {
448
- console.warn("[LBProvider] Failed to fetch API keys:", response.status);
449
- setApiKeys([]);
450
- }
396
+ const data = await lbClient.getUser();
397
+ setApiKeys(data.apiKeys || []);
451
398
  }
452
399
  catch (error) {
453
400
  console.error("[LBProvider] Failed to fetch API keys:", error);
454
401
  setApiKeys([]);
455
402
  }
456
- }, [proxyUrl, state.status]);
403
+ }, [lbClient, state.status]);
457
404
  // Refresh status quand la session devient ready
458
405
  useEffect(() => {
459
406
  if (state.status === "ready") {
@@ -1 +1 @@
1
- {"version":3,"file":"modelManagement.d.ts","sourceRoot":"","sources":["../../src/utils/modelManagement.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CACR,KAAK,CAAC;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CACH,CA6CA;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAkDnB"}
1
+ {"version":3,"file":"modelManagement.d.ts","sourceRoot":"","sources":["../../src/utils/modelManagement.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CACR,KAAK,CAAC;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CACH,CAsDA;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAkDnB"}
@@ -45,12 +45,12 @@ export async function getAvailableModels(options = {}) {
45
45
  const isExternalProxy = baseUrl && baseUrl.includes("/api/lastbrain");
46
46
  const isPublicApi = baseUrl && baseUrl.includes("/api/public/v1");
47
47
  const endpoint = isExternalProxy
48
- ? `${baseUrl}/ai/models/available` // Proxy routes to public API
48
+ ? `${baseUrl}/auth/models` // Proxy routes to /api/ai/auth/models
49
49
  : isPublicApi
50
- ? `${baseUrl}/ai/models/available` // → /api/public/v1/ai/models/available
50
+ ? `${baseUrl}/gateway-models` // → /api/public/v1/gateway-models
51
51
  : baseUrl
52
- ? `${baseUrl}/auth/ai-models-available` // → /api/ai/auth/ai-models-available
53
- : `/api/ai/auth/ai-models-available`; // fallback
52
+ ? `${baseUrl}/auth/models` // → /api/ai/auth/models
53
+ : `/api/ai/auth/models`; // fallback
54
54
  console.log("[getAvailableModels] isExternalProxy:", isExternalProxy, "isPublicApi:", isPublicApi, "endpoint:", endpoint);
55
55
  const headers = {};
56
56
  // Ajouter la clé API pour les appels publics directs
@@ -66,7 +66,13 @@ export async function getAvailableModels(options = {}) {
66
66
  throw new Error(`Erreur lors de la récupération des modèles: ${response.status}`);
67
67
  }
68
68
  const data = await response.json();
69
- return data.models || [];
69
+ if (Array.isArray(data?.models)) {
70
+ return data.models;
71
+ }
72
+ if (Array.isArray(data?.providers)) {
73
+ return data.providers.flatMap((provider) => Array.isArray(provider.models) ? provider.models : []);
74
+ }
75
+ return [];
70
76
  }
71
77
  /**
72
78
  * Récupère les modèles activés par l'utilisateur avec API key
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/ai-ui-react",
3
- "version": "1.0.62",
3
+ "version": "1.0.64",
4
4
  "description": "Headless React components for LastBrain AI UI Kit",
5
5
  "private": false,
6
6
  "type": "module",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "lucide-react": "^0.257.0",
51
- "@lastbrain/ai-ui-core": "1.0.45"
51
+ "@lastbrain/ai-ui-core": "1.0.48"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/react": "^19.2.0",
@@ -182,11 +182,16 @@ function AiPromptPanelInternal({
182
182
 
183
183
  if (showAllModels) {
184
184
  return categoryModels;
185
- } else {
186
- return categoryModels.filter((m) => effectiveUserModels.includes(m.id));
187
185
  }
186
+
187
+ const enabledModels = categoryModels.filter((m) =>
188
+ effectiveUserModels.includes(m.id)
189
+ );
190
+ return enabledModels.length > 0 ? enabledModels : categoryModels;
188
191
  };
189
192
 
193
+ const modelOptions = getFilteredModels();
194
+
190
195
  // Fetch prompts when modal opens
191
196
  useEffect(() => {
192
197
  if (isOpen && (models.length > 0 || enableModelManagement)) {
@@ -209,7 +214,7 @@ function AiPromptPanelInternal({
209
214
  ]);
210
215
 
211
216
  const handleSubmit = async () => {
212
- const activeModelId = selectedModel || models[0]?.id;
217
+ const activeModelId = selectedModel || modelOptions[0]?.id;
213
218
  if (!activeModelId || !prompt.trim()) return;
214
219
  setIsGenerating(true);
215
220
  try {
@@ -249,6 +254,20 @@ function AiPromptPanelInternal({
249
254
  };
250
255
  }, []);
251
256
 
257
+ useEffect(() => {
258
+ if (!isOpen) {
259
+ return;
260
+ }
261
+ if (modelOptions.length === 0) {
262
+ setSelectedModel("");
263
+ return;
264
+ }
265
+ const hasSelected = modelOptions.some((model) => model.id === selectedModel);
266
+ if (!hasSelected) {
267
+ setSelectedModel(modelOptions[0].id);
268
+ }
269
+ }, [isOpen, modelOptions, selectedModel]);
270
+
252
271
  const handleKeyDown = (e: React.KeyboardEvent) => {
253
272
  if (e.key === "Escape") {
254
273
  handleClose();
@@ -284,7 +303,7 @@ function AiPromptPanelInternal({
284
303
 
285
304
  if (!isOpen) return null;
286
305
 
287
- const activeModelId = selectedModel || models[0]?.id || "";
306
+ const activeModelId = selectedModel || modelOptions[0]?.id || "";
288
307
  const currentModelType = models.find((m) => m.id === activeModelId)?.type;
289
308
  const filteredPrompts = prompts.filter((p: Prompt | PublicPrompt) => {
290
309
  const matchesType =
@@ -562,10 +581,10 @@ function AiPromptPanelInternal({
562
581
  ...(modelFocused && aiStyles.selectFocus),
563
582
  }}
564
583
  >
565
- {getFilteredModels().length === 0 && (
584
+ {modelOptions.length === 0 && (
566
585
  <option value="">Loading models...</option>
567
586
  )}
568
- {getFilteredModels().map((model) => {
587
+ {modelOptions.map((model) => {
569
588
  const isActive = effectiveUserModels.includes(model.id);
570
589
  return (
571
590
  <option