@lastbrain/ai-ui-react 1.0.64 → 1.0.65
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/components/AiChipLabel.d.ts.map +1 -1
- package/dist/components/AiChipLabel.js +1 -1
- package/dist/components/AiInput.d.ts +1 -1
- package/dist/components/AiInput.d.ts.map +1 -1
- package/dist/components/AiInput.js +16 -2
- package/dist/components/AiPromptPanel.d.ts +1 -0
- package/dist/components/AiPromptPanel.d.ts.map +1 -1
- package/dist/components/AiPromptPanel.js +21 -4
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +3 -1
- package/dist/components/AiTextarea.d.ts +1 -1
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +16 -2
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +15 -1
- package/dist/hooks/usePrompts.d.ts.map +1 -1
- package/dist/hooks/usePrompts.js +12 -4
- package/dist/utils/modelManagement.d.ts.map +1 -1
- package/dist/utils/modelManagement.js +12 -3
- package/package.json +2 -2
- package/src/components/AiChipLabel.tsx +2 -0
- package/src/components/AiInput.tsx +18 -2
- package/src/components/AiPromptPanel.tsx +25 -3
- package/src/components/AiStatusButton.tsx +5 -1
- package/src/components/AiTextarea.tsx +18 -2
- package/src/context/LBAuthProvider.tsx +16 -1
- package/src/hooks/usePrompts.ts +11 -4
- package/src/utils/modelManagement.ts +11 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiChipLabel.d.ts","sourceRoot":"","sources":["../../src/components/AiChipLabel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAW/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAmB,EACnB,SAAS,EACT,KAAK,EAAE,WAAW,GACnB,EAAE,gBAAgB,2CAgClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAU,EACV,QAAQ,EACR,WAAoE,EACpE,OAAO,EACP,QAAQ,EACR,eAAuB,EACvB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,GACvB,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"AiChipLabel.d.ts","sourceRoot":"","sources":["../../src/components/AiChipLabel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAW/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAmB,EACnB,SAAS,EACT,KAAK,EAAE,WAAW,GACnB,EAAE,gBAAgB,2CAgClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAU,EACV,QAAQ,EACR,WAAoE,EACpE,OAAO,EACP,QAAQ,EACR,eAAuB,EACvB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,GACvB,EAAE,gBAAgB,2CA+NlB"}
|
|
@@ -182,5 +182,5 @@ Exemple de réponse attendue: javascript, react, frontend, api, development`;
|
|
|
182
182
|
color: "currentColor",
|
|
183
183
|
opacity: 0.7,
|
|
184
184
|
}, title: "Supprimer", children: _jsx(X, { size: 14 }) })] }, index));
|
|
185
|
-
}) })), _jsx(AiPromptPanel, { isOpen: showPromptPanel, onClose: () => setShowPromptPanel(false), onSubmit: handlePromptSubmit, models: models || undefined, baseUrl: baseUrl, sourceText: context ? `Contexte: ${context}` : undefined }), _jsx(LBSigninModal, { isOpen: showSigninModal, onClose: () => setShowSigninModal(false) })] }));
|
|
185
|
+
}) })), _jsx(AiPromptPanel, { isOpen: showPromptPanel, onClose: () => setShowPromptPanel(false), onSubmit: handlePromptSubmit, models: models || undefined, baseUrl: baseUrl, sourceText: context ? `Contexte: ${context}` : undefined, enableModelManagement: true, showOnlyUserModels: true }), _jsx(LBSigninModal, { isOpen: showSigninModal, onClose: () => setShowSigninModal(false) })] }));
|
|
186
186
|
}
|
|
@@ -4,5 +4,5 @@ export interface AiInputProps extends Omit<BaseAiProps, "type">, Omit<InputHTMLA
|
|
|
4
4
|
uiMode?: "modal" | "drawer";
|
|
5
5
|
enableModelManagement?: boolean;
|
|
6
6
|
}
|
|
7
|
-
export declare function AiInput({ baseUrl, apiKeyId, uiMode, context, model, prompt, editMode, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...inputProps }: AiInputProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode, context, model, prompt, editMode, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...inputProps }: AiInputProps): import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
//# sourceMappingURL=AiInput.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiInput.d.ts","sourceRoot":"","sources":["../../src/components/AiInput.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAoB,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAE1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"AiInput.d.ts","sourceRoot":"","sources":["../../src/components/AiInput.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAoB,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAE1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAW5C,MAAM,WAAW,YACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IACxD,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,wBAAgB,OAAO,CAAC,EACtB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAgB,EAChB,qBAA4B,EAC5B,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,UAAU,EACd,EAAE,YAAY,2CAwOd"}
|
|
@@ -10,7 +10,8 @@ import { aiStyles } from "../styles/inline";
|
|
|
10
10
|
import { handleAIError } from "../utils/errorHandler";
|
|
11
11
|
import { useLB } from "../context/LBAuthProvider";
|
|
12
12
|
import { LBSigninModal } from "./LBSigninModal";
|
|
13
|
-
|
|
13
|
+
import { useAiContext } from "../context/AiProvider";
|
|
14
|
+
export function AiInput({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode = "modal", context, model, prompt, editMode = false, enableModelManagement = true, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...inputProps }) {
|
|
14
15
|
const [isOpen, setIsOpen] = useState(false);
|
|
15
16
|
const [showAuthModal, setShowAuthModal] = useState(false);
|
|
16
17
|
const [inputValue, setInputValue] = useState(inputProps.value?.toString() || inputProps.defaultValue?.toString() || "");
|
|
@@ -28,6 +29,19 @@ export function AiInput({ baseUrl, apiKeyId, uiMode = "modal", context, model, p
|
|
|
28
29
|
// LBProvider n'est pas disponible, ignorer
|
|
29
30
|
lbStatus = undefined;
|
|
30
31
|
}
|
|
32
|
+
let ctxBaseUrl;
|
|
33
|
+
let ctxApiKeyId;
|
|
34
|
+
try {
|
|
35
|
+
const aiContext = useAiContext();
|
|
36
|
+
ctxBaseUrl = aiContext.baseUrl;
|
|
37
|
+
ctxApiKeyId = aiContext.apiKeyId;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
ctxBaseUrl = undefined;
|
|
41
|
+
ctxApiKeyId = undefined;
|
|
42
|
+
}
|
|
43
|
+
const baseUrl = propBaseUrl ?? ctxBaseUrl;
|
|
44
|
+
const apiKeyId = propApiKeyId ?? ctxApiKeyId;
|
|
31
45
|
const { models } = useAiModels({
|
|
32
46
|
baseUrl,
|
|
33
47
|
apiKeyId,
|
|
@@ -132,5 +146,5 @@ export function AiInput({ baseUrl, apiKeyId, uiMode = "modal", context, model, p
|
|
|
132
146
|
? "Authentication required"
|
|
133
147
|
: hasConfiguration
|
|
134
148
|
? "Generate with AI"
|
|
135
|
-
: "Setup AI", children: loading ? (_jsx("svg", { style: aiStyles.spinner, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83" }) })) : shouldShowSparkles ? (_jsx(Sparkles, { size: 16 })) : (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), _jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] })) }), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: [], modelCategory: "text", sourceText: inputValue || undefined, apiKey: apiKeyId, baseUrl: baseUrl, enableModelManagement: enableModelManagement })), _jsx(LBSigninModal, { isOpen: showAuthModal, onClose: () => setShowAuthModal(false) }), Boolean(toastData) && (_jsx(UsageToast, { result: toastData, position: "bottom-right", onComplete: clearToast }, toastKey))] }));
|
|
149
|
+
: "Setup AI", children: loading ? (_jsx("svg", { style: aiStyles.spinner, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83" }) })) : shouldShowSparkles ? (_jsx(Sparkles, { size: 16 })) : (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), _jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] })) }), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: [], modelCategory: "text", sourceText: inputValue || undefined, apiKey: apiKeyId, baseUrl: baseUrl, enableModelManagement: enableModelManagement, showOnlyUserModels: true })), _jsx(LBSigninModal, { isOpen: showAuthModal, onClose: () => setShowAuthModal(false) }), Boolean(toastData) && (_jsx(UsageToast, { result: toastData, position: "bottom-right", onComplete: clearToast }, toastKey))] }));
|
|
136
150
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiPromptPanel.d.ts","sourceRoot":"","sources":["../../src/components/AiPromptPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AASvC,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,SAAS,CAAC;IAE1D,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"AiPromptPanel.d.ts","sourceRoot":"","sources":["../../src/components/AiPromptPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AASvC,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,SAAS,CAAC;IAE1D,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;IAExB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CA0BtD"}
|
|
@@ -6,17 +6,29 @@ import { aiStyles } from "../styles/inline";
|
|
|
6
6
|
import { handleAIError } from "../utils/errorHandler";
|
|
7
7
|
import { usePrompts, } from "../hooks/usePrompts";
|
|
8
8
|
import { useModelManagement } from "../hooks/useModelManagement";
|
|
9
|
-
import { AiProvider } from "../context/AiProvider";
|
|
9
|
+
import { AiProvider, useAiContext } from "../context/AiProvider";
|
|
10
10
|
export function AiPromptPanel(props) {
|
|
11
11
|
const { apiKey, baseUrl } = props;
|
|
12
|
-
|
|
12
|
+
let hasContext = false;
|
|
13
|
+
try {
|
|
14
|
+
useAiContext();
|
|
15
|
+
hasContext = true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
hasContext = false;
|
|
19
|
+
}
|
|
20
|
+
// Si un contexte existe déjà, ne pas re-wrapper (évite les refetch multiples).
|
|
21
|
+
if (hasContext) {
|
|
22
|
+
return _jsx(AiPromptPanelInternal, { ...props });
|
|
23
|
+
}
|
|
24
|
+
// Sinon, si apiKey/baseUrl sont fournis, wrapper avec AiProvider
|
|
13
25
|
if (apiKey || baseUrl) {
|
|
14
26
|
return (_jsx(AiProvider, { baseUrl: baseUrl || "", apiKeyId: apiKey || "", children: _jsx(AiPromptPanelInternal, { ...props }) }));
|
|
15
27
|
}
|
|
16
28
|
// Sinon, utiliser le contexte existant
|
|
17
29
|
return _jsx(AiPromptPanelInternal, { ...props });
|
|
18
30
|
}
|
|
19
|
-
function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "modal", models = [], sourceText, children, enableModelManagement = true, modelCategory = "text", availableModels = [], userModels = [], onModelToggle, apiKey, baseUrl, }) {
|
|
31
|
+
function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "modal", models = [], sourceText, children, enableModelManagement = true, modelCategory = "text", availableModels = [], userModels = [], onModelToggle, apiKey, baseUrl, showOnlyUserModels = false, }) {
|
|
20
32
|
const [selectedModel, setSelectedModel] = useState("");
|
|
21
33
|
const [prompt, setPrompt] = useState("");
|
|
22
34
|
const [promptId, setPromptId] = useState(undefined);
|
|
@@ -90,6 +102,9 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
90
102
|
}));
|
|
91
103
|
}
|
|
92
104
|
const categoryModels = effectiveAvailableModels.filter((m) => m.category === modelCategory);
|
|
105
|
+
if (!showAllModels && showOnlyUserModels) {
|
|
106
|
+
return categoryModels.filter((m) => effectiveUserModels.includes(m.id));
|
|
107
|
+
}
|
|
93
108
|
if (showAllModels) {
|
|
94
109
|
return categoryModels;
|
|
95
110
|
}
|
|
@@ -350,7 +365,9 @@ function AiPromptPanelInternal({ isOpen, onClose, onSubmit, uiMode: _uiMode = "m
|
|
|
350
365
|
!effectiveUserModels.includes(m.id)).length] }))] }))] }), _jsxs("select", { id: "model-select", value: activeModelId, onChange: (e) => setSelectedModel(e.target.value), onFocus: () => setModelFocused(true), onBlur: () => setModelFocused(false), style: {
|
|
351
366
|
...aiStyles.select,
|
|
352
367
|
...(modelFocused && aiStyles.selectFocus),
|
|
353
|
-
}, children: [modelOptions.length === 0 && (_jsx("option", { value: "", children:
|
|
368
|
+
}, children: [modelOptions.length === 0 && (_jsx("option", { value: "", children: showOnlyUserModels
|
|
369
|
+
? "No active models. Open 'Gérer les modèles'."
|
|
370
|
+
: "Loading models..." })), modelOptions.map((model) => {
|
|
354
371
|
const isActive = effectiveUserModels.includes(model.id);
|
|
355
372
|
return (_jsxs("option", { value: model.id, style: {
|
|
356
373
|
opacity: showAllModels && !isActive ? 0.6 : 1,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAmBtD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,GACf,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAmBtD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,GACf,EAAE,mBAAmB,2CAssCrB"}
|
|
@@ -232,7 +232,9 @@ export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
|
232
232
|
lbRefreshBasicStatus,
|
|
233
233
|
lbRefreshStorageStatus,
|
|
234
234
|
]);
|
|
235
|
-
if (loading ||
|
|
235
|
+
if (loading ||
|
|
236
|
+
isSelectingApiKey ||
|
|
237
|
+
((isLoadingStatus || lbIsLoadingStatus) && !effectiveStatus)) {
|
|
236
238
|
return (_jsx("button", { ref: buttonRef, style: {
|
|
237
239
|
...aiStyles.statusButton,
|
|
238
240
|
...aiStyles.statusButtonDisabled,
|
|
@@ -3,5 +3,5 @@ import type { BaseAiProps } from "../types";
|
|
|
3
3
|
export interface AiTextareaProps extends Omit<BaseAiProps, "type">, Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "onValue"> {
|
|
4
4
|
uiMode?: "modal" | "drawer";
|
|
5
5
|
}
|
|
6
|
-
export declare function AiTextarea({ baseUrl, apiKeyId, uiMode, context, model, prompt, editMode, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...textareaProps }: AiTextareaProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode, context, model, prompt, editMode, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...textareaProps }: AiTextareaProps): import("react/jsx-runtime").JSX.Element;
|
|
7
7
|
//# sourceMappingURL=AiTextarea.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiTextarea.d.ts","sourceRoot":"","sources":["../../src/components/AiTextarea.tsx"],"names":[],"mappings":"AAEA,OAAc,EAIZ,KAAK,sBAAsB,EAC5B,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"AiTextarea.d.ts","sourceRoot":"","sources":["../../src/components/AiTextarea.tsx"],"names":[],"mappings":"AAEA,OAAc,EAIZ,KAAK,sBAAsB,EAC5B,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAW5C,MAAM,WAAW,eACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAAE,SAAS,CAAC;IAC9D,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC7B;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAgB,EAChB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,aAAa,EACjB,EAAE,eAAe,2CA+OjB"}
|
|
@@ -10,7 +10,8 @@ import { aiStyles } from "../styles/inline";
|
|
|
10
10
|
import { handleAIError } from "../utils/errorHandler";
|
|
11
11
|
import { useLB } from "../context/LBAuthProvider";
|
|
12
12
|
import { LBSigninModal } from "./LBSigninModal";
|
|
13
|
-
|
|
13
|
+
import { useAiContext } from "../context/AiProvider";
|
|
14
|
+
export function AiTextarea({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, uiMode = "modal", context, model, prompt, editMode = false, enableModelManagement, storeOutputs, artifactTitle, onValue, onToast, disabled, className, ...textareaProps }) {
|
|
14
15
|
const [isOpen, setIsOpen] = useState(false);
|
|
15
16
|
const [showAuthModal, setShowAuthModal] = useState(false);
|
|
16
17
|
const [textareaValue, setTextareaValue] = useState(textareaProps.value?.toString() ||
|
|
@@ -30,6 +31,19 @@ export function AiTextarea({ baseUrl, apiKeyId, uiMode = "modal", context, model
|
|
|
30
31
|
// LBProvider n'est pas disponible, ignorer
|
|
31
32
|
lbStatus = undefined;
|
|
32
33
|
}
|
|
34
|
+
let ctxBaseUrl;
|
|
35
|
+
let ctxApiKeyId;
|
|
36
|
+
try {
|
|
37
|
+
const aiContext = useAiContext();
|
|
38
|
+
ctxBaseUrl = aiContext.baseUrl;
|
|
39
|
+
ctxApiKeyId = aiContext.apiKeyId;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
ctxBaseUrl = undefined;
|
|
43
|
+
ctxApiKeyId = undefined;
|
|
44
|
+
}
|
|
45
|
+
const baseUrl = propBaseUrl ?? ctxBaseUrl;
|
|
46
|
+
const apiKeyId = propApiKeyId ?? ctxApiKeyId;
|
|
33
47
|
const { models } = useAiModels({
|
|
34
48
|
baseUrl,
|
|
35
49
|
apiKeyId,
|
|
@@ -146,5 +160,5 @@ export function AiTextarea({ baseUrl, apiKeyId, uiMode = "modal", context, model
|
|
|
146
160
|
? "Authentication required"
|
|
147
161
|
: hasConfiguration
|
|
148
162
|
? "Generate with AI"
|
|
149
|
-
: "Setup AI", children: loading ? (_jsx("svg", { style: aiStyles.spinner, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83" }) })) : shouldShowSparkles ? (_jsx(Sparkles, { size: 16 })) : (_jsx(Lock, { size: 16 })) }), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: [], modelCategory: "text", sourceText: textareaValue || undefined, baseUrl: baseUrl, apiKey: apiKeyId, enableModelManagement: enableModelManagement })), Boolean(toastData) && (_jsx(UsageToast, { result: toastData, position: "bottom-right", onComplete: clearToast }, toastKey)), _jsx(LBSigninModal, { isOpen: showAuthModal, onClose: () => setShowAuthModal(false) })] }));
|
|
163
|
+
: "Setup AI", children: loading ? (_jsx("svg", { style: aiStyles.spinner, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83" }) })) : shouldShowSparkles ? (_jsx(Sparkles, { size: 16 })) : (_jsx(Lock, { size: 16 })) }), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: [], modelCategory: "text", sourceText: textareaValue || undefined, baseUrl: baseUrl, apiKey: apiKeyId, enableModelManagement: enableModelManagement, showOnlyUserModels: true })), Boolean(toastData) && (_jsx(UsageToast, { result: toastData, position: "bottom-right", onComplete: clearToast }, toastKey)), _jsx(LBSigninModal, { isOpen: showAuthModal, onClose: () => setShowAuthModal(false) })] }));
|
|
150
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAIR,QAAQ,EACT,MAAM,uBAAuB,CAAC;AAG/B,UAAU,eAAe;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACzD,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,UAAU,cAAe,SAAQ,WAAW;IAC1C,4BAA4B;IAC5B,KAAK,EAAE,CACL,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,8BAA8B;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,6CAA6C;IAC7C,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC3D,gEAAgE;IAChE,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,mDAAmD;IACnD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,iEAAiE;IACjE,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,oCAAoC;IACpC,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,2BAA2B;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC;IACjB,uCAAuC;IACvC,aAAa,EAAE,GAAG,CAAC;IACnB,gDAAgD;IAChD,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,iEAAiE;IACjE,oBAAoB,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,kEAAkE;IAClE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,8DAA8D;IAC9D,eAAe,EAAE,OAAO,CAAC;IACzB,uDAAuD;IACvD,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAID,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAO,EAAE,QAA2B,EACpC,QAA2B,EAC3B,cAAc,EACd,YAAY,GACb,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAIR,QAAQ,EACT,MAAM,uBAAuB,CAAC;AAG/B,UAAU,eAAe;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACzD,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,UAAU,cAAe,SAAQ,WAAW;IAC1C,4BAA4B;IAC5B,KAAK,EAAE,CACL,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,8BAA8B;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,6CAA6C;IAC7C,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC3D,gEAAgE;IAChE,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,mDAAmD;IACnD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,iEAAiE;IACjE,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,oCAAoC;IACpC,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,2BAA2B;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC;IACjB,uCAAuC;IACvC,aAAa,EAAE,GAAG,CAAC;IACnB,gDAAgD;IAChD,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,iEAAiE;IACjE,oBAAoB,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,kEAAkE;IAClE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,8DAA8D;IAC9D,eAAe,EAAE,OAAO,CAAC;IACzB,uDAAuD;IACvD,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAID,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAO,EAAE,QAA2B,EACpC,QAA2B,EAC3B,cAAc,EACd,YAAY,GACb,EAAE,eAAe,2CAsgBjB;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,cAAc,CAMtC"}
|
|
@@ -333,7 +333,20 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
333
333
|
*/
|
|
334
334
|
const switchApiKey = useCallback(async (apiKeyId) => {
|
|
335
335
|
if (state.status === "ready" || accessToken) {
|
|
336
|
-
|
|
336
|
+
// lb_session / login token flow: persist selection server-side when possible.
|
|
337
|
+
// api_key flow may legitimately reject this route; we still support local selection
|
|
338
|
+
// via x-lb-api-key-selected header on subsequent requests.
|
|
339
|
+
if (accessToken || state.session?.sessionToken) {
|
|
340
|
+
await lbClient.selectApiKey(apiKeyId, accessToken);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
try {
|
|
344
|
+
await lbClient.selectApiKey(apiKeyId, accessToken);
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
console.warn("[LBProvider] selectApiKey API call failed, applying local switch only", error);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
337
350
|
const selectedKey = apiKeys.find((key) => key.id === apiKeyId);
|
|
338
351
|
if (selectedKey) {
|
|
339
352
|
setState((prev) => ({
|
|
@@ -349,6 +362,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
349
362
|
}
|
|
350
363
|
}, [
|
|
351
364
|
state.status,
|
|
365
|
+
state.session?.sessionToken,
|
|
352
366
|
accessToken,
|
|
353
367
|
apiKeys,
|
|
354
368
|
lbClient,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePrompts.d.ts","sourceRoot":"","sources":["../../src/hooks/usePrompts.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAa,SAAQ,MAAM;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,YAAY,EAAE,CACZ,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,KACnD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5E,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,aAAa,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,KAClC,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,wBAAgB,UAAU,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"usePrompts.d.ts","sourceRoot":"","sources":["../../src/hooks/usePrompts.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAa,SAAQ,MAAM;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,YAAY,EAAE,CACZ,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,KACnD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5E,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,aAAa,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,KAClC,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,wBAAgB,UAAU,IAAI,gBAAgB,CAuS7C"}
|
package/dist/hooks/usePrompts.js
CHANGED
|
@@ -7,6 +7,14 @@ export function usePrompts() {
|
|
|
7
7
|
const [prompts, setPrompts] = useState([]);
|
|
8
8
|
const [loading, setLoading] = useState(false);
|
|
9
9
|
const [error, setError] = useState(null);
|
|
10
|
+
const isAuthTokenCandidate = (value) => {
|
|
11
|
+
if (!value)
|
|
12
|
+
return false;
|
|
13
|
+
const token = value.trim();
|
|
14
|
+
if (!token)
|
|
15
|
+
return false;
|
|
16
|
+
return token.startsWith("lb_") || token.split(".").length === 3;
|
|
17
|
+
};
|
|
10
18
|
const fetchPrompts = useCallback(async (options) => {
|
|
11
19
|
try {
|
|
12
20
|
setLoading(true);
|
|
@@ -71,7 +79,7 @@ export function usePrompts() {
|
|
|
71
79
|
console.log("[usePrompts] Fetching prompts from:", endpoint);
|
|
72
80
|
const headers = {};
|
|
73
81
|
// Ajouter l'API key pour les appels publics directs (pas de proxy externe ni auth interne)
|
|
74
|
-
if (isPublicApi && apiKeyId) {
|
|
82
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
75
83
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
76
84
|
}
|
|
77
85
|
const response = await fetch(endpoint, {
|
|
@@ -110,7 +118,7 @@ export function usePrompts() {
|
|
|
110
118
|
? `${baseUrl}/auth/prompts` // Proxy ajoutera /api/ai/
|
|
111
119
|
: "/api/ai/auth/prompts";
|
|
112
120
|
const headers = { "Content-Type": "application/json" };
|
|
113
|
-
if (!isExternalProxy && apiKeyId) {
|
|
121
|
+
if (!isExternalProxy && isAuthTokenCandidate(apiKeyId)) {
|
|
114
122
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
115
123
|
}
|
|
116
124
|
const response = await fetch(endpoint, {
|
|
@@ -148,7 +156,7 @@ export function usePrompts() {
|
|
|
148
156
|
? `${baseUrl}/auth/prompts`
|
|
149
157
|
: "/api/ai/auth/prompts";
|
|
150
158
|
const headers = { "Content-Type": "application/json" };
|
|
151
|
-
if (isPublicApi && apiKeyId) {
|
|
159
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
152
160
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
153
161
|
}
|
|
154
162
|
const response = await fetch(endpoint, {
|
|
@@ -186,7 +194,7 @@ export function usePrompts() {
|
|
|
186
194
|
? `${baseUrl}/auth/prompts?id=${id}`
|
|
187
195
|
: `/api/ai/auth/prompts?id=${id}`;
|
|
188
196
|
const headers = {};
|
|
189
|
-
if (isPublicApi && apiKeyId) {
|
|
197
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
190
198
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
191
199
|
}
|
|
192
200
|
const response = await fetch(endpoint, {
|
|
@@ -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;
|
|
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;AAUD;;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"}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utilitaires pour la gestion des modèles IA
|
|
3
3
|
*/
|
|
4
|
+
function isAuthTokenCandidate(value) {
|
|
5
|
+
if (!value)
|
|
6
|
+
return false;
|
|
7
|
+
const token = value.trim();
|
|
8
|
+
if (!token)
|
|
9
|
+
return false;
|
|
10
|
+
// Raw API key or JWT access token
|
|
11
|
+
return token.startsWith("lb_") || token.split(".").length === 3;
|
|
12
|
+
}
|
|
4
13
|
/**
|
|
5
14
|
* Active ou désactive un modèle pour l'utilisateur courant
|
|
6
15
|
*/
|
|
@@ -10,7 +19,7 @@ export async function toggleUserModel(modelId, isActive, options = {}) {
|
|
|
10
19
|
"Content-Type": "application/json",
|
|
11
20
|
};
|
|
12
21
|
// Ajouter la clé API si fournie
|
|
13
|
-
if (apiKey) {
|
|
22
|
+
if (isAuthTokenCandidate(apiKey)) {
|
|
14
23
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
15
24
|
}
|
|
16
25
|
const isPublicApi = baseUrl && baseUrl.includes("/api/public/v1");
|
|
@@ -54,7 +63,7 @@ export async function getAvailableModels(options = {}) {
|
|
|
54
63
|
console.log("[getAvailableModels] isExternalProxy:", isExternalProxy, "isPublicApi:", isPublicApi, "endpoint:", endpoint);
|
|
55
64
|
const headers = {};
|
|
56
65
|
// Ajouter la clé API pour les appels publics directs
|
|
57
|
-
if (isPublicApi && apiKey) {
|
|
66
|
+
if (isPublicApi && isAuthTokenCandidate(apiKey)) {
|
|
58
67
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
59
68
|
}
|
|
60
69
|
const response = await fetch(endpoint, {
|
|
@@ -92,7 +101,7 @@ export async function getUserModels(options = {}) {
|
|
|
92
101
|
console.log("[getUserModels] isExternalProxy:", isExternalProxy, "isPublicApi:", isPublicApi, "endpoint:", endpoint);
|
|
93
102
|
const headers = {};
|
|
94
103
|
// Ajouter la clé API pour tous les types d'appels si disponible
|
|
95
|
-
if (apiKey) {
|
|
104
|
+
if (isAuthTokenCandidate(apiKey)) {
|
|
96
105
|
if (isPublicApi) {
|
|
97
106
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
98
107
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lastbrain/ai-ui-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.65",
|
|
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.
|
|
51
|
+
"@lastbrain/ai-ui-core": "1.0.49"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/react": "^19.2.0",
|
|
@@ -296,6 +296,8 @@ Exemple de réponse attendue: javascript, react, frontend, api, development`;
|
|
|
296
296
|
models={models || undefined}
|
|
297
297
|
baseUrl={baseUrl}
|
|
298
298
|
sourceText={context ? `Contexte: ${context}` : undefined}
|
|
299
|
+
enableModelManagement={true}
|
|
300
|
+
showOnlyUserModels={true}
|
|
299
301
|
/>
|
|
300
302
|
|
|
301
303
|
{/* Modal signin pour les utilisateurs non connectés */}
|
|
@@ -11,6 +11,7 @@ import { aiStyles } from "../styles/inline";
|
|
|
11
11
|
import { handleAIError } from "../utils/errorHandler";
|
|
12
12
|
import { useLB } from "../context/LBAuthProvider";
|
|
13
13
|
import { LBSigninModal } from "./LBSigninModal";
|
|
14
|
+
import { useAiContext } from "../context/AiProvider";
|
|
14
15
|
|
|
15
16
|
export interface AiInputProps
|
|
16
17
|
extends
|
|
@@ -21,8 +22,8 @@ export interface AiInputProps
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export function AiInput({
|
|
24
|
-
baseUrl,
|
|
25
|
-
apiKeyId,
|
|
25
|
+
baseUrl: propBaseUrl,
|
|
26
|
+
apiKeyId: propApiKeyId,
|
|
26
27
|
uiMode = "modal",
|
|
27
28
|
context,
|
|
28
29
|
model,
|
|
@@ -57,6 +58,20 @@ export function AiInput({
|
|
|
57
58
|
lbStatus = undefined;
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
let ctxBaseUrl: string | undefined;
|
|
62
|
+
let ctxApiKeyId: string | undefined;
|
|
63
|
+
try {
|
|
64
|
+
const aiContext = useAiContext();
|
|
65
|
+
ctxBaseUrl = aiContext.baseUrl;
|
|
66
|
+
ctxApiKeyId = aiContext.apiKeyId;
|
|
67
|
+
} catch {
|
|
68
|
+
ctxBaseUrl = undefined;
|
|
69
|
+
ctxApiKeyId = undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const baseUrl = propBaseUrl ?? ctxBaseUrl;
|
|
73
|
+
const apiKeyId = propApiKeyId ?? ctxApiKeyId;
|
|
74
|
+
|
|
60
75
|
const { models } = useAiModels({
|
|
61
76
|
baseUrl,
|
|
62
77
|
apiKeyId,
|
|
@@ -237,6 +252,7 @@ export function AiInput({
|
|
|
237
252
|
apiKey={apiKeyId}
|
|
238
253
|
baseUrl={baseUrl}
|
|
239
254
|
enableModelManagement={enableModelManagement}
|
|
255
|
+
showOnlyUserModels={true}
|
|
240
256
|
/>
|
|
241
257
|
)}
|
|
242
258
|
<LBSigninModal
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
} from "../hooks/usePrompts";
|
|
20
20
|
import { useModelManagement } from "../hooks/useModelManagement";
|
|
21
21
|
import { type AIModel } from "../context/AiProvider";
|
|
22
|
-
import { AiProvider } from "../context/AiProvider";
|
|
22
|
+
import { AiProvider, useAiContext } from "../context/AiProvider";
|
|
23
23
|
|
|
24
24
|
export interface AiPromptPanelProps {
|
|
25
25
|
isOpen: boolean;
|
|
@@ -37,6 +37,7 @@ export interface AiPromptPanelProps {
|
|
|
37
37
|
onModelToggle?: (modelId: string, isActive: boolean) => Promise<void>;
|
|
38
38
|
apiKey?: string;
|
|
39
39
|
baseUrl?: string;
|
|
40
|
+
showOnlyUserModels?: boolean;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
export interface AiPromptPanelRenderProps {
|
|
@@ -59,8 +60,20 @@ export interface AiPromptPanelRenderProps {
|
|
|
59
60
|
|
|
60
61
|
export function AiPromptPanel(props: AiPromptPanelProps) {
|
|
61
62
|
const { apiKey, baseUrl } = props;
|
|
63
|
+
let hasContext = false;
|
|
64
|
+
try {
|
|
65
|
+
useAiContext();
|
|
66
|
+
hasContext = true;
|
|
67
|
+
} catch {
|
|
68
|
+
hasContext = false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Si un contexte existe déjà, ne pas re-wrapper (évite les refetch multiples).
|
|
72
|
+
if (hasContext) {
|
|
73
|
+
return <AiPromptPanelInternal {...props} />;
|
|
74
|
+
}
|
|
62
75
|
|
|
63
|
-
//
|
|
76
|
+
// Sinon, si apiKey/baseUrl sont fournis, wrapper avec AiProvider
|
|
64
77
|
if (apiKey || baseUrl) {
|
|
65
78
|
return (
|
|
66
79
|
<AiProvider baseUrl={baseUrl || ""} apiKeyId={apiKey || ""}>
|
|
@@ -88,6 +101,7 @@ function AiPromptPanelInternal({
|
|
|
88
101
|
onModelToggle,
|
|
89
102
|
apiKey,
|
|
90
103
|
baseUrl,
|
|
104
|
+
showOnlyUserModels = false,
|
|
91
105
|
}: AiPromptPanelProps) {
|
|
92
106
|
const [selectedModel, setSelectedModel] = useState("");
|
|
93
107
|
const [prompt, setPrompt] = useState("");
|
|
@@ -180,6 +194,10 @@ function AiPromptPanelInternal({
|
|
|
180
194
|
(m) => m.category === modelCategory
|
|
181
195
|
);
|
|
182
196
|
|
|
197
|
+
if (!showAllModels && showOnlyUserModels) {
|
|
198
|
+
return categoryModels.filter((m) => effectiveUserModels.includes(m.id));
|
|
199
|
+
}
|
|
200
|
+
|
|
183
201
|
if (showAllModels) {
|
|
184
202
|
return categoryModels;
|
|
185
203
|
}
|
|
@@ -582,7 +600,11 @@ function AiPromptPanelInternal({
|
|
|
582
600
|
}}
|
|
583
601
|
>
|
|
584
602
|
{modelOptions.length === 0 && (
|
|
585
|
-
<option value="">
|
|
603
|
+
<option value="">
|
|
604
|
+
{showOnlyUserModels
|
|
605
|
+
? "No active models. Open 'Gérer les modèles'."
|
|
606
|
+
: "Loading models..."}
|
|
607
|
+
</option>
|
|
586
608
|
)}
|
|
587
609
|
{modelOptions.map((model) => {
|
|
588
610
|
const isActive = effectiveUserModels.includes(model.id);
|
|
@@ -345,7 +345,11 @@ export function AiStatusButton({
|
|
|
345
345
|
lbRefreshStorageStatus,
|
|
346
346
|
]);
|
|
347
347
|
|
|
348
|
-
if (
|
|
348
|
+
if (
|
|
349
|
+
loading ||
|
|
350
|
+
isSelectingApiKey ||
|
|
351
|
+
((isLoadingStatus || lbIsLoadingStatus) && !effectiveStatus)
|
|
352
|
+
) {
|
|
349
353
|
return (
|
|
350
354
|
<button
|
|
351
355
|
ref={buttonRef}
|
|
@@ -16,6 +16,7 @@ import { aiStyles } from "../styles/inline";
|
|
|
16
16
|
import { handleAIError } from "../utils/errorHandler";
|
|
17
17
|
import { useLB } from "../context/LBAuthProvider";
|
|
18
18
|
import { LBSigninModal } from "./LBSigninModal";
|
|
19
|
+
import { useAiContext } from "../context/AiProvider";
|
|
19
20
|
|
|
20
21
|
export interface AiTextareaProps
|
|
21
22
|
extends
|
|
@@ -25,8 +26,8 @@ export interface AiTextareaProps
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export function AiTextarea({
|
|
28
|
-
baseUrl,
|
|
29
|
-
apiKeyId,
|
|
29
|
+
baseUrl: propBaseUrl,
|
|
30
|
+
apiKeyId: propApiKeyId,
|
|
30
31
|
uiMode = "modal",
|
|
31
32
|
context,
|
|
32
33
|
model,
|
|
@@ -63,6 +64,20 @@ export function AiTextarea({
|
|
|
63
64
|
lbStatus = undefined;
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
let ctxBaseUrl: string | undefined;
|
|
68
|
+
let ctxApiKeyId: string | undefined;
|
|
69
|
+
try {
|
|
70
|
+
const aiContext = useAiContext();
|
|
71
|
+
ctxBaseUrl = aiContext.baseUrl;
|
|
72
|
+
ctxApiKeyId = aiContext.apiKeyId;
|
|
73
|
+
} catch {
|
|
74
|
+
ctxBaseUrl = undefined;
|
|
75
|
+
ctxApiKeyId = undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const baseUrl = propBaseUrl ?? ctxBaseUrl;
|
|
79
|
+
const apiKeyId = propApiKeyId ?? ctxApiKeyId;
|
|
80
|
+
|
|
66
81
|
const { models } = useAiModels({
|
|
67
82
|
baseUrl,
|
|
68
83
|
apiKeyId,
|
|
@@ -248,6 +263,7 @@ export function AiTextarea({
|
|
|
248
263
|
baseUrl={baseUrl}
|
|
249
264
|
apiKey={apiKeyId}
|
|
250
265
|
enableModelManagement={enableModelManagement}
|
|
266
|
+
showOnlyUserModels={true}
|
|
251
267
|
/>
|
|
252
268
|
)}
|
|
253
269
|
{Boolean(toastData) && (
|
|
@@ -483,7 +483,21 @@ export function LBProvider({
|
|
|
483
483
|
const switchApiKey = useCallback(
|
|
484
484
|
async (apiKeyId: string): Promise<void> => {
|
|
485
485
|
if (state.status === "ready" || accessToken) {
|
|
486
|
-
|
|
486
|
+
// lb_session / login token flow: persist selection server-side when possible.
|
|
487
|
+
// api_key flow may legitimately reject this route; we still support local selection
|
|
488
|
+
// via x-lb-api-key-selected header on subsequent requests.
|
|
489
|
+
if (accessToken || state.session?.sessionToken) {
|
|
490
|
+
await lbClient.selectApiKey(apiKeyId, accessToken);
|
|
491
|
+
} else {
|
|
492
|
+
try {
|
|
493
|
+
await lbClient.selectApiKey(apiKeyId, accessToken);
|
|
494
|
+
} catch (error) {
|
|
495
|
+
console.warn(
|
|
496
|
+
"[LBProvider] selectApiKey API call failed, applying local switch only",
|
|
497
|
+
error
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
487
501
|
const selectedKey = apiKeys.find((key) => key.id === apiKeyId);
|
|
488
502
|
if (selectedKey) {
|
|
489
503
|
setState((prev) => ({
|
|
@@ -499,6 +513,7 @@ export function LBProvider({
|
|
|
499
513
|
},
|
|
500
514
|
[
|
|
501
515
|
state.status,
|
|
516
|
+
state.session?.sessionToken,
|
|
502
517
|
accessToken,
|
|
503
518
|
apiKeys,
|
|
504
519
|
lbClient,
|
package/src/hooks/usePrompts.ts
CHANGED
|
@@ -59,6 +59,13 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
59
59
|
const [loading, setLoading] = useState(false);
|
|
60
60
|
const [error, setError] = useState<string | null>(null);
|
|
61
61
|
|
|
62
|
+
const isAuthTokenCandidate = (value?: string): boolean => {
|
|
63
|
+
if (!value) return false;
|
|
64
|
+
const token = value.trim();
|
|
65
|
+
if (!token) return false;
|
|
66
|
+
return token.startsWith("lb_") || token.split(".").length === 3;
|
|
67
|
+
};
|
|
68
|
+
|
|
62
69
|
const fetchPrompts = useCallback(
|
|
63
70
|
async (options?: UsePromptsOptions) => {
|
|
64
71
|
try {
|
|
@@ -133,7 +140,7 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
133
140
|
|
|
134
141
|
const headers: HeadersInit = {};
|
|
135
142
|
// Ajouter l'API key pour les appels publics directs (pas de proxy externe ni auth interne)
|
|
136
|
-
if (isPublicApi && apiKeyId) {
|
|
143
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
137
144
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
138
145
|
}
|
|
139
146
|
|
|
@@ -179,7 +186,7 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
179
186
|
: "/api/ai/auth/prompts";
|
|
180
187
|
|
|
181
188
|
const headers: HeadersInit = { "Content-Type": "application/json" };
|
|
182
|
-
if (!isExternalProxy && apiKeyId) {
|
|
189
|
+
if (!isExternalProxy && isAuthTokenCandidate(apiKeyId)) {
|
|
183
190
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
184
191
|
}
|
|
185
192
|
|
|
@@ -225,7 +232,7 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
225
232
|
: "/api/ai/auth/prompts";
|
|
226
233
|
|
|
227
234
|
const headers: HeadersInit = { "Content-Type": "application/json" };
|
|
228
|
-
if (isPublicApi && apiKeyId) {
|
|
235
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
229
236
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
230
237
|
}
|
|
231
238
|
|
|
@@ -271,7 +278,7 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
271
278
|
: `/api/ai/auth/prompts?id=${id}`;
|
|
272
279
|
|
|
273
280
|
const headers: HeadersInit = {};
|
|
274
|
-
if (isPublicApi && apiKeyId) {
|
|
281
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
275
282
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
276
283
|
}
|
|
277
284
|
|
|
@@ -7,6 +7,14 @@ export interface ModelToggleOptions {
|
|
|
7
7
|
baseUrl?: string; // URL de base de l'API
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
function isAuthTokenCandidate(value?: string): boolean {
|
|
11
|
+
if (!value) return false;
|
|
12
|
+
const token = value.trim();
|
|
13
|
+
if (!token) return false;
|
|
14
|
+
// Raw API key or JWT access token
|
|
15
|
+
return token.startsWith("lb_") || token.split(".").length === 3;
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
/**
|
|
11
19
|
* Active ou désactive un modèle pour l'utilisateur courant
|
|
12
20
|
*/
|
|
@@ -22,7 +30,7 @@ export async function toggleUserModel(
|
|
|
22
30
|
};
|
|
23
31
|
|
|
24
32
|
// Ajouter la clé API si fournie
|
|
25
|
-
if (apiKey) {
|
|
33
|
+
if (isAuthTokenCandidate(apiKey)) {
|
|
26
34
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
27
35
|
}
|
|
28
36
|
|
|
@@ -96,7 +104,7 @@ export async function getAvailableModels(
|
|
|
96
104
|
const headers: Record<string, string> = {};
|
|
97
105
|
|
|
98
106
|
// Ajouter la clé API pour les appels publics directs
|
|
99
|
-
if (isPublicApi && apiKey) {
|
|
107
|
+
if (isPublicApi && isAuthTokenCandidate(apiKey)) {
|
|
100
108
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
101
109
|
}
|
|
102
110
|
|
|
@@ -157,7 +165,7 @@ export async function getUserModels(
|
|
|
157
165
|
const headers: Record<string, string> = {};
|
|
158
166
|
|
|
159
167
|
// Ajouter la clé API pour tous les types d'appels si disponible
|
|
160
|
-
if (apiKey) {
|
|
168
|
+
if (isAuthTokenCandidate(apiKey)) {
|
|
161
169
|
if (isPublicApi) {
|
|
162
170
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
163
171
|
} else {
|