Disambiguates the Phoenix/auth client lib from lib-arcadia-agents-client. Dir lib-arcadia-client → lib-arcadia-core-client; alias updated in tsconfig paths, vite config, app.css @source, imports, CI and docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
101 lines
3.8 KiB
Markdown
101 lines
3.8 KiB
Markdown
# lib-llm-providers-ui
|
|
|
|
Multi-provider LLM picker + settings card for Crema apps. Sits on top of `@crema/llm-ui` and adds:
|
|
|
|
- A **named provider catalog** (OpenAI, Anthropic, DeepSeek, Qwen, LM Studio) with sensible default base URLs and model lists.
|
|
- An **arcadia-proxy adapter** that routes chat completions through `POST /api/v1/ai/llm/chat`, so API keys never leave the server.
|
|
- A **direct-mode adapter** that resolves the API key from arcadia's Secrets Manager (`GET /api/v1/secrets/:name`) and calls the provider directly from the browser.
|
|
- A **settings card** (`LLMProvidersSettingsCard`) that ties it all together — provider, model, base-URL override, arcadia-secret name, transport toggle, context/response budgets, system prompt.
|
|
- A **persistent settings store** with `useSettings()` / `saveSettings()` / `resetSettings()` and a `crema:llm-providers-change` event for reactive updates across tabs.
|
|
|
|
## Quick start
|
|
|
|
```tsx
|
|
import {
|
|
LLMProvidersSettingsCard,
|
|
buildAdapter,
|
|
useSettings,
|
|
} from "@crema/llm-providers-ui"
|
|
import { LLMProvider, useChat } from "@crema/llm-ui"
|
|
import { useArcadiaClient } from "@crema/arcadia-core-client"
|
|
import { useEffect, useState } from "react"
|
|
|
|
function App() {
|
|
const arcadia = useArcadiaClient()
|
|
const settings = useSettings()
|
|
const [adapter, setAdapter] = useState(null)
|
|
|
|
useEffect(() => {
|
|
buildAdapter({
|
|
settings,
|
|
// Direct mode — fetch the API key from arcadia's vault.
|
|
resolveSecret: async (name) => {
|
|
const res = await arcadia.GET<{ data: { value: string } }>(`/api/v1/secrets/${name}`)
|
|
return res.data.value
|
|
},
|
|
// Or proxy mode (when the backend endpoint exists):
|
|
arcadiaBaseURL: import.meta.env.VITE_ARCADIA_URL,
|
|
arcadiaAuthToken: sessionStorage.getItem("arcadia_access_token") ?? undefined,
|
|
arcadiaTenantId: import.meta.env.VITE_ARCADIA_TENANT,
|
|
}).then(setAdapter)
|
|
}, [settings, arcadia])
|
|
|
|
if (!adapter) return null
|
|
return (
|
|
<LLMProvider adapter={adapter} model={settings.model}>
|
|
<Chat />
|
|
</LLMProvider>
|
|
)
|
|
}
|
|
```
|
|
|
|
For the settings page:
|
|
|
|
```tsx
|
|
<LLMProvidersSettingsCard
|
|
hideTransportToggle={!proxyAvailable}
|
|
onTest={async (s) => {
|
|
// Wire to a one-off completion through buildAdapter.
|
|
// Return { ok: true, message: "Connected." } or { ok: false, message: "..." }.
|
|
}}
|
|
/>
|
|
```
|
|
|
|
## Direct vs proxy
|
|
|
|
| Mode | Where the key lives at call time | When to use |
|
|
|---|---|---|
|
|
| `direct` | Briefly in the browser (fetched from arcadia per-call) | When the backend proxy isn't deployed yet, or for local development. |
|
|
| `proxy` | Server-side only (read by arcadia, never sent to the client) | Production. Requires `POST /api/v1/ai/llm/chat` on arcadia — see `LLM_PROXY_CONTRACT.md` in the consuming app. |
|
|
|
|
The settings card lets the user toggle between them. `buildAdapter()` returns the right adapter automatically.
|
|
|
|
## Provider catalog
|
|
|
|
Edit `PROVIDERS` in `src/index.tsx` to add more. Each entry is:
|
|
|
|
```ts
|
|
{
|
|
id: "deepseek",
|
|
label: "DeepSeek",
|
|
baseURL: "https://api.deepseek.com/v1",
|
|
transport: "openai-compatible", // or "anthropic"
|
|
requiresKey: true,
|
|
defaultModels: ["deepseek-chat", "deepseek-reasoner"],
|
|
hint: "OpenAI-compatible. Create a key at platform.deepseek.com.",
|
|
}
|
|
```
|
|
|
|
Adding a provider with a different shape (e.g. Google AI) means picking the closest existing transport, or extending `@crema/llm-ui` with a new adapter and adding a transport string here.
|
|
|
|
## Wiring into a Crema app
|
|
|
|
1. Clone this lib as a sibling.
|
|
2. Add `@source "../../lib-llm-providers-ui/src";` under `/* CREMA:SOURCES */` in `app/app.css`.
|
|
3. Add the path alias under `// CREMA:PATHS` in `tsconfig.json`:
|
|
```json
|
|
"@crema/llm-providers-ui": ["../lib-llm-providers-ui/src/index.tsx"],
|
|
"@crema/llm-providers-ui/*": ["../lib-llm-providers-ui/src/*"],
|
|
```
|
|
4. `crema add` does this automatically once the manifest knows about the lib.
|