bloby-bot 0.47.8 → 0.47.9
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-bloby/assets/{bloby-E-QLmQDW.js → bloby-BOSem5eq.js} +4 -4
- package/dist-bloby/assets/globals-CZdsyZot.css +2 -0
- package/dist-bloby/assets/globals-CgIIDNVG.js +18 -0
- package/dist-bloby/assets/{highlighted-body-OFNGDK62-CTiboTVa.js → highlighted-body-OFNGDK62-DpMYfn6Z.js} +1 -1
- package/dist-bloby/assets/mermaid-GHXKKRXX-B5_2sDIG.js +1 -0
- package/dist-bloby/assets/{onboard-C1uMxuk2.js → onboard-8AOYU7vY.js} +1 -1
- package/dist-bloby/bloby.html +3 -3
- package/dist-bloby/onboard.html +3 -3
- package/package.json +4 -4
- package/supervisor/chat/OnboardWizard.tsx +121 -178
- package/supervisor/harnesses/pi/providers/stream-anthropic.ts +318 -0
- package/supervisor/harnesses/pi/providers/stream-openai-completions.ts +328 -0
- package/supervisor/harnesses/pi/providers/stream.ts +4 -2
- package/workspace/client/public/icons/pi.svg +20 -0
- package/dist-bloby/assets/globals-Ci0CEj1X.js +0 -18
- package/dist-bloby/assets/globals-DriF_8Q_.css +0 -2
- package/dist-bloby/assets/mermaid-GHXKKRXX-CgVqYCFU.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e,r as t,t as n}from"./jsx-runtime-C0W9Wf2W.js";import{n as r,r as i,t as a}from"./bloby-
|
|
1
|
+
import{c as e,r as t,t as n}from"./jsx-runtime-C0W9Wf2W.js";import{n as r,r as i,t as a}from"./bloby-BOSem5eq.js";var o=e(t(),1),s=n(),c=({code:e,language:t,raw:n,className:c,startLine:l,lineNumbers:u,...d})=>{let{shikiTheme:f}=(0,o.useContext)(i),p=r(),[m,h]=(0,o.useState)(n);return(0,o.useEffect)(()=>{if(!p){h(n);return}let r=p.highlight({code:e,language:t,themes:f},e=>{h(e)});r&&h(r)},[e,t,f,p,n]),(0,s.jsx)(a,{className:c,language:t,lineNumbers:u,result:m,startLine:l,...d})};export{c as HighlightedCodeBlockBody};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{i as e}from"./bloby-BOSem5eq.js";export{e as Mermaid};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e,r as t,t as n}from"./jsx-runtime-C0W9Wf2W.js";import{p as r,t as i}from"./globals-
|
|
1
|
+
import{c as e,r as t,t as n}from"./jsx-runtime-C0W9Wf2W.js";import{p as r,t as i}from"./globals-CgIIDNVG.js";var a=e(t(),1),o=e(r(),1),s=n();function c(){return(0,s.jsx)(i,{onComplete:()=>{window.parent?.postMessage({type:`bloby:onboard-complete`},`*`)},isInitialSetup:!0})}o.createRoot(document.getElementById(`root`)).render((0,s.jsx)(a.StrictMode,{children:(0,s.jsx)(c,{})}));
|
package/dist-bloby/bloby.html
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
|
|
6
6
|
<title>Bloby Chat</title>
|
|
7
|
-
<script type="module" crossorigin src="/bloby/assets/bloby-
|
|
7
|
+
<script type="module" crossorigin src="/bloby/assets/bloby-BOSem5eq.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="/bloby/assets/jsx-runtime-C0W9Wf2W.js">
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/bloby/assets/globals-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/bloby/assets/globals-CgIIDNVG.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-CZdsyZot.css">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/bloby/assets/bloby-DkK0ymA2.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body class="bg-background text-foreground">
|
package/dist-bloby/onboard.html
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
|
|
6
6
|
<title>Bloby Setup</title>
|
|
7
|
-
<script type="module" crossorigin src="/bloby/assets/onboard-
|
|
7
|
+
<script type="module" crossorigin src="/bloby/assets/onboard-8AOYU7vY.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="/bloby/assets/jsx-runtime-C0W9Wf2W.js">
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/bloby/assets/globals-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/bloby/assets/globals-CgIIDNVG.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-CZdsyZot.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body class="bg-background text-foreground">
|
|
13
13
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bloby-bot",
|
|
3
|
-
"version": "0.47.
|
|
3
|
+
"version": "0.47.9",
|
|
4
4
|
"releaseNotes": [
|
|
5
|
-
"1.
|
|
6
|
-
"2.
|
|
7
|
-
"3.
|
|
5
|
+
"1. Something great..",
|
|
6
|
+
"2. ",
|
|
7
|
+
"3. ",
|
|
8
8
|
"4. "
|
|
9
9
|
],
|
|
10
10
|
"description": "Self-hosted, self-evolving AI agent with its own dashboard.",
|
|
@@ -46,9 +46,10 @@ const ACCESS_LABELS: Record<AccessMethod, string> = {
|
|
|
46
46
|
/* ── Provider config ── */
|
|
47
47
|
|
|
48
48
|
const PROVIDERS = [
|
|
49
|
-
{ id: 'pi', name: '
|
|
50
|
-
{ id: '
|
|
51
|
-
{ id: '
|
|
49
|
+
{ id: 'pi', name: 'Pi', subtitle: 'Bring your own model', icon: '/icons/pi.svg', comingSoon: false },
|
|
50
|
+
{ id: 'bloby', name: 'Bloby', subtitle: 'Coming Soon..', icon: '/bloby-icon-192.png', comingSoon: true },
|
|
51
|
+
{ id: 'anthropic', name: 'Claude', subtitle: 'by Anthropic', icon: '/icons/claude.png', comingSoon: false },
|
|
52
|
+
{ id: 'openai', name: 'OpenAI Codex', subtitle: 'ChatGPT Plus / Pro', icon: '/icons/codex.png', comingSoon: false },
|
|
52
53
|
] as const;
|
|
53
54
|
|
|
54
55
|
const MODELS: Record<string, { id: string; label: string }[]> = {
|
|
@@ -196,8 +197,6 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
196
197
|
const [piShowKey, setPiShowKey] = useState(false);
|
|
197
198
|
const [piConnecting, setPiConnecting] = useState(false);
|
|
198
199
|
const [piError, setPiError] = useState<string | undefined>();
|
|
199
|
-
const [piTestRunning, setPiTestRunning] = useState(false);
|
|
200
|
-
const [piTestResult, setPiTestResult] = useState<{ ok: boolean; text?: string; error?: string } | null>(null);
|
|
201
200
|
const [piSavedStatus, setPiSavedStatus] = useState<{ subProvider?: string; modelId?: string; baseUrl?: string } | null>(null);
|
|
202
201
|
|
|
203
202
|
// Anthropic/Claude-specific
|
|
@@ -601,7 +600,6 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
601
600
|
setOpenaiError(undefined);
|
|
602
601
|
// Pi flow cleanup is per-sub-provider; the load effect handles re-hydration.
|
|
603
602
|
setPiError(undefined);
|
|
604
|
-
setPiTestResult(null);
|
|
605
603
|
};
|
|
606
604
|
|
|
607
605
|
/* ── Bloby (pi) handlers ── */
|
|
@@ -648,7 +646,6 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
648
646
|
setPiBaseUrl(next?.baseUrl || '');
|
|
649
647
|
setPiModelId(next?.defaultModel || '');
|
|
650
648
|
setPiError(undefined);
|
|
651
|
-
setPiTestResult(null);
|
|
652
649
|
// Picking a new sub-provider invalidates the previously saved auth.
|
|
653
650
|
if (authState.pi === 'connected') {
|
|
654
651
|
setAuthState((s) => ({ ...s, pi: 'idle' }));
|
|
@@ -659,7 +656,6 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
659
656
|
const handlePiConnect = async () => {
|
|
660
657
|
if (!piSubProvider) return;
|
|
661
658
|
setPiError(undefined);
|
|
662
|
-
setPiTestResult(null);
|
|
663
659
|
setPiConnecting(true);
|
|
664
660
|
try {
|
|
665
661
|
const payload = {
|
|
@@ -703,28 +699,9 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
703
699
|
try { await fetch('/api/auth/pi', { method: 'DELETE' }); } catch {}
|
|
704
700
|
setAuthState((s) => ({ ...s, pi: 'idle' }));
|
|
705
701
|
setPiSavedStatus(null);
|
|
706
|
-
setPiTestResult(null);
|
|
707
702
|
setModel('');
|
|
708
703
|
};
|
|
709
704
|
|
|
710
|
-
const handlePiTestCompletion = async () => {
|
|
711
|
-
setPiTestRunning(true);
|
|
712
|
-
setPiTestResult(null);
|
|
713
|
-
try {
|
|
714
|
-
const res = await fetch('/api/auth/pi/completion', {
|
|
715
|
-
method: 'POST',
|
|
716
|
-
headers: { 'Content-Type': 'application/json' },
|
|
717
|
-
body: JSON.stringify({}),
|
|
718
|
-
});
|
|
719
|
-
const data = await res.json();
|
|
720
|
-
setPiTestResult({ ok: !!data?.ok, text: data?.text, error: data?.error });
|
|
721
|
-
} catch (err: any) {
|
|
722
|
-
setPiTestResult({ ok: false, error: err?.message || 'Request failed' });
|
|
723
|
-
} finally {
|
|
724
|
-
setPiTestRunning(false);
|
|
725
|
-
}
|
|
726
|
-
};
|
|
727
|
-
|
|
728
705
|
/* ── Auth handlers: Anthropic/Claude ── */
|
|
729
706
|
|
|
730
707
|
const openExternal = (url: string) => {
|
|
@@ -2241,180 +2218,146 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
2241
2218
|
|
|
2242
2219
|
<div className="border-t border-white/[0.06] mt-4 mb-3" />
|
|
2243
2220
|
|
|
2244
|
-
{/* ── Auth flow:
|
|
2221
|
+
{/* ── Auth flow: Pi (bring your own model) ── */}
|
|
2245
2222
|
{provider === 'pi' && (
|
|
2246
|
-
<div className="space-y-
|
|
2223
|
+
<div className="space-y-2">
|
|
2247
2224
|
{authState.pi === 'connected' && piSavedStatus ? (
|
|
2248
|
-
|
|
2249
|
-
<
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
</p>
|
|
2254
|
-
</div>
|
|
2255
|
-
|
|
2256
|
-
<div className="bg-white/[0.03] border border-white/[0.06] rounded-xl p-3.5 space-y-2.5">
|
|
2257
|
-
<p className="text-[12px] text-white/55">
|
|
2258
|
-
Send a quick test request to confirm the model is reachable.
|
|
2259
|
-
</p>
|
|
2260
|
-
<button
|
|
2261
|
-
onClick={handlePiTestCompletion}
|
|
2262
|
-
disabled={piTestRunning}
|
|
2263
|
-
className="w-full py-2 px-4 bg-white/[0.06] hover:bg-white/[0.1] text-white text-[12px] font-medium rounded-xl transition-colors flex items-center justify-center gap-2 disabled:opacity-60"
|
|
2264
|
-
>
|
|
2265
|
-
{piTestRunning ? (
|
|
2266
|
-
<><LoaderCircle className="h-3.5 w-3.5 animate-spin" />Sending test request…</>
|
|
2267
|
-
) : (
|
|
2268
|
-
<>Send test request<ArrowRight className="h-3.5 w-3.5 opacity-60" /></>
|
|
2269
|
-
)}
|
|
2270
|
-
</button>
|
|
2271
|
-
{piTestResult && piTestResult.ok && (
|
|
2272
|
-
<div className="bg-emerald-500/5 border border-emerald-500/15 rounded-lg px-3 py-2">
|
|
2273
|
-
<p className="text-[11px] text-emerald-400/70 mb-1">Model reply</p>
|
|
2274
|
-
<p className="text-[12px] text-white/85 whitespace-pre-wrap">{piTestResult.text}</p>
|
|
2275
|
-
</div>
|
|
2276
|
-
)}
|
|
2277
|
-
{piTestResult && !piTestResult.ok && (
|
|
2278
|
-
<div className="bg-red-500/8 border border-red-500/15 rounded-lg px-3 py-2">
|
|
2279
|
-
<p className="text-[12px] text-red-400/90">{piTestResult.error}</p>
|
|
2280
|
-
</div>
|
|
2281
|
-
)}
|
|
2282
|
-
</div>
|
|
2283
|
-
|
|
2225
|
+
<div className="flex items-center justify-between bg-emerald-500/8 border border-emerald-500/15 rounded-lg px-3 py-2">
|
|
2226
|
+
<p className="text-emerald-400/90 text-[12px] truncate">
|
|
2227
|
+
Connected — {piSubProviders.find((p) => p.id === piSavedStatus.subProvider)?.name || piSavedStatus.subProvider}
|
|
2228
|
+
{piSavedStatus.modelId ? <> · <span className="font-mono">{piSavedStatus.modelId}</span></> : null}
|
|
2229
|
+
</p>
|
|
2284
2230
|
<button
|
|
2285
2231
|
onClick={handlePiDisconnect}
|
|
2286
|
-
className="
|
|
2232
|
+
className="text-white/30 hover:text-white/60 text-[11px] flex items-center gap-1 shrink-0 ml-2"
|
|
2287
2233
|
>
|
|
2288
2234
|
<RefreshCw className="h-3 w-3" />
|
|
2289
|
-
|
|
2235
|
+
Change
|
|
2290
2236
|
</button>
|
|
2291
|
-
|
|
2237
|
+
</div>
|
|
2292
2238
|
) : (
|
|
2293
2239
|
<>
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
<div
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
piSubProvider === sp.id
|
|
2304
|
-
? 'border-[#AF27E3]/50 bg-[#AF27E3]/10'
|
|
2305
|
-
: 'border-white/[0.08] bg-white/[0.02] hover:bg-white/[0.04]'
|
|
2306
|
-
}`}
|
|
2307
|
-
>
|
|
2308
|
-
<p className="text-[12.5px] text-white font-medium leading-tight">{sp.name}</p>
|
|
2309
|
-
<p className="text-[10.5px] text-white/40 mt-0.5 leading-tight">{sp.subtitle}</p>
|
|
2310
|
-
{piSubProvider === sp.id && (
|
|
2311
|
-
<div className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-gradient-brand" />
|
|
2312
|
-
)}
|
|
2313
|
-
</button>
|
|
2314
|
-
))}
|
|
2240
|
+
{/* Two-column compact row: provider dropdown + model picker */}
|
|
2241
|
+
<div className="grid grid-cols-2 gap-2">
|
|
2242
|
+
<div>
|
|
2243
|
+
<label className="text-[11px] text-white/40 font-medium mb-1 block">Provider</label>
|
|
2244
|
+
<ModelDropdown
|
|
2245
|
+
models={piSubProviders.map((sp) => ({ id: sp.id, label: sp.name }))}
|
|
2246
|
+
value={piSubProvider}
|
|
2247
|
+
onChange={choosePiSubProvider}
|
|
2248
|
+
/>
|
|
2315
2249
|
</div>
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
</div>
|
|
2250
|
+
<div>
|
|
2251
|
+
<label className="text-[11px] text-white/40 font-medium mb-1 block">Model</label>
|
|
2252
|
+
{selectedPiSub && Array.isArray(selectedPiSub.models) ? (
|
|
2253
|
+
<ModelDropdown
|
|
2254
|
+
models={selectedPiSub.models}
|
|
2255
|
+
value={piModelId}
|
|
2256
|
+
onChange={setPiModelId}
|
|
2257
|
+
/>
|
|
2258
|
+
) : (
|
|
2259
|
+
<input
|
|
2260
|
+
type="text"
|
|
2261
|
+
value={piModelId}
|
|
2262
|
+
onChange={(e) => setPiModelId(e.target.value)}
|
|
2263
|
+
placeholder={selectedPiSub?.defaultModel || 'model-id'}
|
|
2264
|
+
className={inputSmCls + ' font-mono'}
|
|
2265
|
+
/>
|
|
2333
2266
|
)}
|
|
2267
|
+
</div>
|
|
2268
|
+
</div>
|
|
2334
2269
|
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
>
|
|
2345
|
-
Get a key <ExternalLink className="h-3 w-3" />
|
|
2346
|
-
</button>
|
|
2347
|
-
)}
|
|
2348
|
-
</label>
|
|
2349
|
-
<div className="relative">
|
|
2350
|
-
<input
|
|
2351
|
-
type={piShowKey ? 'text' : 'password'}
|
|
2352
|
-
value={piApiKey}
|
|
2353
|
-
onChange={(e) => setPiApiKey(e.target.value)}
|
|
2354
|
-
onKeyDown={(e) => e.key === 'Enter' && handlePiConnect()}
|
|
2355
|
-
placeholder="sk-..."
|
|
2356
|
-
className={inputSmCls + ' pr-10 font-mono'}
|
|
2357
|
-
/>
|
|
2358
|
-
<button
|
|
2359
|
-
type="button"
|
|
2360
|
-
onClick={() => setPiShowKey((v) => !v)}
|
|
2361
|
-
className="absolute right-3 top-1/2 -translate-y-1/2 text-white/20 hover:text-white/50 transition-colors"
|
|
2362
|
-
>
|
|
2363
|
-
{piShowKey ? <EyeOff className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
|
|
2364
|
-
</button>
|
|
2365
|
-
</div>
|
|
2366
|
-
</div>
|
|
2367
|
-
)}
|
|
2270
|
+
{selectedPiSub?.needsBaseUrl && (
|
|
2271
|
+
<input
|
|
2272
|
+
type="text"
|
|
2273
|
+
value={piBaseUrl}
|
|
2274
|
+
onChange={(e) => setPiBaseUrl(e.target.value)}
|
|
2275
|
+
placeholder={selectedPiSub.baseUrl || 'https://example.com/v1'}
|
|
2276
|
+
className={inputSmCls + ' font-mono'}
|
|
2277
|
+
/>
|
|
2278
|
+
)}
|
|
2368
2279
|
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2280
|
+
{selectedPiSub?.needsApiKey && (
|
|
2281
|
+
<div className="relative">
|
|
2282
|
+
<input
|
|
2283
|
+
type={piShowKey ? 'text' : 'password'}
|
|
2284
|
+
value={piApiKey}
|
|
2285
|
+
onChange={(e) => setPiApiKey(e.target.value)}
|
|
2286
|
+
onKeyDown={(e) => e.key === 'Enter' && handlePiConnect()}
|
|
2287
|
+
placeholder="API key…"
|
|
2288
|
+
className={inputSmCls + ' pr-16 font-mono'}
|
|
2289
|
+
/>
|
|
2290
|
+
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-1.5">
|
|
2291
|
+
{selectedPiSub.apiKeyUrl && (
|
|
2292
|
+
<button
|
|
2293
|
+
type="button"
|
|
2294
|
+
onClick={() => openExternal(selectedPiSub.apiKeyUrl!)}
|
|
2295
|
+
className="text-white/25 hover:text-white/55 transition-colors"
|
|
2296
|
+
title="Get a key"
|
|
2297
|
+
>
|
|
2298
|
+
<ExternalLink className="h-3.5 w-3.5" />
|
|
2299
|
+
</button>
|
|
2385
2300
|
)}
|
|
2301
|
+
<button
|
|
2302
|
+
type="button"
|
|
2303
|
+
onClick={() => setPiShowKey((v) => !v)}
|
|
2304
|
+
className="text-white/25 hover:text-white/55 transition-colors"
|
|
2305
|
+
>
|
|
2306
|
+
{piShowKey ? <EyeOff className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
|
|
2307
|
+
</button>
|
|
2386
2308
|
</div>
|
|
2309
|
+
</div>
|
|
2310
|
+
)}
|
|
2387
2311
|
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
</div>
|
|
2392
|
-
)}
|
|
2393
|
-
|
|
2394
|
-
<button
|
|
2395
|
-
onClick={handlePiConnect}
|
|
2396
|
-
disabled={
|
|
2397
|
-
piConnecting ||
|
|
2398
|
-
!piSubProvider ||
|
|
2399
|
-
(selectedPiSub.needsApiKey && !piApiKey.trim()) ||
|
|
2400
|
-
(selectedPiSub.needsBaseUrl && !piBaseUrl.trim()) ||
|
|
2401
|
-
!piModelId.trim()
|
|
2402
|
-
}
|
|
2403
|
-
className="w-full py-2.5 px-4 bg-gradient-brand hover:opacity-90 text-white text-[13px] font-medium rounded-xl transition-colors flex items-center justify-center gap-2 disabled:opacity-40"
|
|
2404
|
-
>
|
|
2405
|
-
{piConnecting ? (
|
|
2406
|
-
<><LoaderCircle className="h-3.5 w-3.5 animate-spin" />Connecting…</>
|
|
2407
|
-
) : (
|
|
2408
|
-
<>Test & connect<ArrowRight className="h-3.5 w-3.5 opacity-60" /></>
|
|
2409
|
-
)}
|
|
2410
|
-
</button>
|
|
2312
|
+
{piError && (
|
|
2313
|
+
<div className="bg-red-500/8 border border-red-500/15 rounded-lg px-3 py-2">
|
|
2314
|
+
<p className="text-[12px] text-red-400/90 break-words">{piError}</p>
|
|
2411
2315
|
</div>
|
|
2412
2316
|
)}
|
|
2317
|
+
|
|
2318
|
+
<button
|
|
2319
|
+
onClick={handlePiConnect}
|
|
2320
|
+
disabled={
|
|
2321
|
+
piConnecting ||
|
|
2322
|
+
!piSubProvider ||
|
|
2323
|
+
(!!selectedPiSub?.needsApiKey && !piApiKey.trim()) ||
|
|
2324
|
+
(!!selectedPiSub?.needsBaseUrl && !piBaseUrl.trim()) ||
|
|
2325
|
+
!piModelId.trim()
|
|
2326
|
+
}
|
|
2327
|
+
className="w-full py-2.5 px-4 bg-gradient-brand hover:opacity-90 text-white text-[13px] font-medium rounded-xl transition-colors flex items-center justify-center gap-2 disabled:opacity-40"
|
|
2328
|
+
>
|
|
2329
|
+
{piConnecting ? (
|
|
2330
|
+
<><LoaderCircle className="h-3.5 w-3.5 animate-spin" />Connecting…</>
|
|
2331
|
+
) : (
|
|
2332
|
+
<>Test & connect<ArrowRight className="h-3.5 w-3.5 opacity-60" /></>
|
|
2333
|
+
)}
|
|
2334
|
+
</button>
|
|
2413
2335
|
</>
|
|
2414
2336
|
)}
|
|
2415
2337
|
</div>
|
|
2416
2338
|
)}
|
|
2417
2339
|
|
|
2340
|
+
{/* ── Auth flow: Bloby (coming soon placeholder) ── */}
|
|
2341
|
+
{provider === 'bloby' && (
|
|
2342
|
+
<div className="space-y-3">
|
|
2343
|
+
<p className="text-[12px] text-white/40 leading-relaxed">
|
|
2344
|
+
Bloby (managed) is on the way. Sign in with Google once it ships and your bot will be hosted, updated, and billed by us — no API keys to manage.
|
|
2345
|
+
</p>
|
|
2346
|
+
<button
|
|
2347
|
+
type="button"
|
|
2348
|
+
disabled
|
|
2349
|
+
title="Coming soon"
|
|
2350
|
+
className="w-full py-2.5 px-4 bg-white/[0.04] border border-white/[0.06] text-white/35 text-[13px] font-medium rounded-xl flex items-center justify-center gap-2 cursor-not-allowed"
|
|
2351
|
+
>
|
|
2352
|
+
<svg viewBox="0 0 24 24" className="h-4 w-4 opacity-50" fill="currentColor">
|
|
2353
|
+
<path d="M21.35 11.1h-9.17v2.96h5.27c-.23 1.39-1.62 4.08-5.27 4.08-3.17 0-5.76-2.62-5.76-5.85s2.59-5.85 5.76-5.85c1.81 0 3.02.77 3.71 1.43l2.53-2.43C16.85 3.91 14.74 3 12.18 3 7.03 3 2.86 7.17 2.86 12.29s4.17 9.29 9.32 9.29c5.38 0 8.94-3.79 8.94-9.12 0-.61-.07-1.08-.17-1.55Z"/>
|
|
2354
|
+
</svg>
|
|
2355
|
+
Login with Google
|
|
2356
|
+
</button>
|
|
2357
|
+
<p className="text-[10.5px] text-white/25 text-center">Not available yet.</p>
|
|
2358
|
+
</div>
|
|
2359
|
+
)}
|
|
2360
|
+
|
|
2418
2361
|
{/* ── Auth flow: Anthropic ── */}
|
|
2419
2362
|
{provider === 'anthropic' && (
|
|
2420
2363
|
<div className="space-y-2.5">
|