mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 04:11:39 +00:00
improve(setup): clarify local provider actions
This commit is contained in:
@@ -89,6 +89,7 @@ extension OnboardingAISetupModel {
|
||||
let id: String
|
||||
let label: String
|
||||
let hint: String?
|
||||
let actionLabel: String?
|
||||
let brandId: String?
|
||||
let icon: String?
|
||||
let website: String?
|
||||
@@ -117,6 +118,7 @@ extension OnboardingAISetupModel {
|
||||
id: "ollama",
|
||||
label: "Ollama",
|
||||
hint: "Download a tools-capable model from your Ollama server",
|
||||
actionLabel: nil,
|
||||
brandId: "ollama",
|
||||
icon: nil,
|
||||
website: nil),
|
||||
@@ -124,6 +126,7 @@ extension OnboardingAISetupModel {
|
||||
id: "llama-cpp",
|
||||
label: "Local model (llama.cpp)",
|
||||
hint: "Download an approximately 5.0 GB local model; requires 16 GB RAM",
|
||||
actionLabel: nil,
|
||||
brandId: "llama-cpp",
|
||||
icon: nil,
|
||||
website: nil),
|
||||
|
||||
@@ -534,7 +534,7 @@ struct OnboardingAISetupView: View {
|
||||
}
|
||||
}
|
||||
Spacer(minLength: 0)
|
||||
Text("Connect / Set up")
|
||||
Text(option.actionLabel ?? "Connect / Set up")
|
||||
.font(.caption.weight(.semibold))
|
||||
.foregroundStyle(Color.accentColor)
|
||||
}
|
||||
|
||||
@@ -254,17 +254,20 @@ private func detectedSetupResponse(
|
||||
"id": "ollama",
|
||||
"brandId": "ollama",
|
||||
"label": "Ollama",
|
||||
"hint": "Connect to an Ollama server and select a cloud or local model"
|
||||
"hint": "Connect to an Ollama server and select a cloud or local model",
|
||||
"actionLabel": "Choose connection"
|
||||
}, {
|
||||
"id": "llama-cpp",
|
||||
"brandId": "llama-cpp",
|
||||
"label": "Local model (llama.cpp)",
|
||||
"hint": "Download and run a private GGUF model"
|
||||
"hint": "Download and run a private GGUF model",
|
||||
"actionLabel": "Review download"
|
||||
}, {
|
||||
"id": "lmstudio",
|
||||
"brandId": "lmstudio",
|
||||
"label": "LM Studio",
|
||||
"hint": "Connect to a running LM Studio server and use an already loaded model",
|
||||
"actionLabel": "Connect server",
|
||||
"icon": "https://cdn.simpleicons.org/lmstudio",
|
||||
"website": "https://lmstudio.ai/download"
|
||||
}],
|
||||
@@ -681,6 +684,7 @@ struct OnboardingAISetupTests {
|
||||
id: "ollama",
|
||||
label: "Wire Ollama",
|
||||
hint: "Wire hint",
|
||||
actionLabel: "Choose connection",
|
||||
brandId: "ollama",
|
||||
icon: "https://cdn.simpleicons.org/ollama",
|
||||
website: "https://ollama.com/download"),
|
||||
@@ -688,6 +692,7 @@ struct OnboardingAISetupTests {
|
||||
id: "llama-cpp",
|
||||
label: "Local model (llama.cpp)",
|
||||
hint: "Private GGUF model",
|
||||
actionLabel: "Review download",
|
||||
brandId: "llama-cpp",
|
||||
icon: nil,
|
||||
website: nil),
|
||||
@@ -695,6 +700,7 @@ struct OnboardingAISetupTests {
|
||||
id: "lmstudio-local",
|
||||
label: "LM Studio",
|
||||
hint: "Running local service",
|
||||
actionLabel: "Connect server",
|
||||
brandId: "lmstudio",
|
||||
icon: "https://cdn.simpleicons.org/lmstudio",
|
||||
website: "https://lmstudio.ai/download"),
|
||||
@@ -706,6 +712,7 @@ struct OnboardingAISetupTests {
|
||||
|
||||
#expect(options.map(\.id) == ["llama-cpp"])
|
||||
#expect(options.first?.label == "Local model (llama.cpp)")
|
||||
#expect(options.first?.actionLabel == "Review download")
|
||||
#expect(OnboardingAISetupModel.ProviderWizardKind.prepare.startMethod ==
|
||||
"openclaw.setup.prepare.start")
|
||||
}
|
||||
|
||||
@@ -385,30 +385,31 @@ If a tool has no `toolMetadata`, OpenClaw preserves the existing behavior and lo
|
||||
|
||||
Each `providerAuthChoices` entry describes one onboarding or auth choice. OpenClaw reads this before provider runtime loads. Provider setup lists use these manifest choices, descriptor-derived setup choices, and install-catalog metadata without loading provider runtime.
|
||||
|
||||
| Field | Required | Type | What it means |
|
||||
| --------------------- | -------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| `provider` | Yes | `string` | Provider id this choice belongs to. |
|
||||
| `method` | Yes | `string` | Auth method id to dispatch to. |
|
||||
| `choiceId` | Yes | `string` | Stable auth-choice id used by onboarding and CLI flows. |
|
||||
| `choiceLabel` | No | `string` | User-facing label. If omitted, OpenClaw falls back to `choiceId`. |
|
||||
| `choiceHint` | No | `string` | Short helper text for the picker. |
|
||||
| `icon` | No | HTTPS URL | Artwork shown beside this choice in supported onboarding clients. |
|
||||
| `website` | No | HTTPS URL | Product, sign-in, or installation page shown by supported onboarding clients. |
|
||||
| `assistantPriority` | No | `number` | Lower values sort earlier in assistant-driven interactive pickers. |
|
||||
| `assistantVisibility` | No | `"visible"` \| `"manual-only"` | Hide the choice from assistant pickers while still allowing manual CLI selection. |
|
||||
| `deprecatedChoiceIds` | No | `string[]` | Legacy choice ids that should redirect users to this replacement choice. |
|
||||
| `groupId` | No | `string` | Optional group id for grouping related choices. |
|
||||
| `groupLabel` | No | `string` | User-facing label for that group. |
|
||||
| `groupHint` | No | `string` | Short helper text for the group. |
|
||||
| `onboardingFeatured` | No | `boolean` | Surface this group in the featured tier of the interactive onboarding picker, before the "More..." entry. |
|
||||
| `optionKey` | No | `string` | Internal option key for simple one-flag auth flows. |
|
||||
| `cliFlag` | No | `string` | CLI flag name, such as `--openrouter-api-key`. |
|
||||
| `cliOption` | No | `string` | Full CLI option shape, such as `--openrouter-api-key <key>`. |
|
||||
| `cliDescription` | No | `string` | Description used in CLI help. |
|
||||
| `appGuidedSecret` | No | `boolean` | One pasted secret plus provider defaults is sufficient for app-guided setup. |
|
||||
| `appGuidedDiscovery` | No | `boolean` | The matching runtime auth method owns read-only local discovery through `appGuidedSetup`. |
|
||||
| `appGuidedAuth` | No | `"oauth"` \| `"device-code"` | Provider-owned interactive login that native setup clients can render generically. |
|
||||
| `onboardingScopes` | No | `Array<"text-inference" \| "image-generation" \| "music-generation">` | Which onboarding surfaces this choice should appear in. If omitted, it defaults to `["text-inference"]`. |
|
||||
| Field | Required | Type | What it means |
|
||||
| ---------------------- | -------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| `provider` | Yes | `string` | Provider id this choice belongs to. |
|
||||
| `method` | Yes | `string` | Auth method id to dispatch to. |
|
||||
| `choiceId` | Yes | `string` | Stable auth-choice id used by onboarding and CLI flows. |
|
||||
| `choiceLabel` | No | `string` | User-facing label. If omitted, OpenClaw falls back to `choiceId`. |
|
||||
| `choiceHint` | No | `string` | Short helper text for the picker. |
|
||||
| `icon` | No | HTTPS URL | Artwork shown beside this choice in supported onboarding clients. |
|
||||
| `website` | No | HTTPS URL | Product, sign-in, or installation page shown by supported onboarding clients. |
|
||||
| `assistantPriority` | No | `number` | Lower values sort earlier in assistant-driven interactive pickers. |
|
||||
| `assistantVisibility` | No | `"visible"` \| `"manual-only"` | Hide the choice from assistant pickers while still allowing manual CLI selection. |
|
||||
| `deprecatedChoiceIds` | No | `string[]` | Legacy choice ids that should redirect users to this replacement choice. |
|
||||
| `groupId` | No | `string` | Optional group id for grouping related choices. |
|
||||
| `groupLabel` | No | `string` | User-facing label for that group. |
|
||||
| `groupHint` | No | `string` | Short helper text for the group. |
|
||||
| `onboardingFeatured` | No | `boolean` | Surface this group in the featured tier of the interactive onboarding picker, before the "More..." entry. |
|
||||
| `optionKey` | No | `string` | Internal option key for simple one-flag auth flows. |
|
||||
| `cliFlag` | No | `string` | CLI flag name, such as `--openrouter-api-key`. |
|
||||
| `cliOption` | No | `string` | Full CLI option shape, such as `--openrouter-api-key <key>`. |
|
||||
| `cliDescription` | No | `string` | Description used in CLI help. |
|
||||
| `appGuidedSecret` | No | `boolean` | One pasted secret plus provider defaults is sufficient for app-guided setup. |
|
||||
| `appGuidedActionLabel` | No | `string` | Short command label shown when starting provider-owned app-guided setup. |
|
||||
| `appGuidedDiscovery` | No | `boolean` | The matching runtime auth method owns read-only local discovery through `appGuidedSetup`. |
|
||||
| `appGuidedAuth` | No | `"oauth"` \| `"device-code"` | Provider-owned interactive login that native setup clients can render generically. |
|
||||
| `onboardingScopes` | No | `Array<"text-inference" \| "image-generation" \| "music-generation">` | Which onboarding surfaces this choice should appear in. If omitted, it defaults to `["text-inference"]`. |
|
||||
|
||||
When `appGuidedDiscovery` is true, the matching provider auth method must expose
|
||||
`appGuidedSetup.detect` and `appGuidedSetup.prepare`. Detection must be
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"method": "local",
|
||||
"choiceId": "llama-cpp",
|
||||
"appGuidedDiscovery": true,
|
||||
"appGuidedActionLabel": "Review download",
|
||||
"choiceLabel": "Local model (llama.cpp)",
|
||||
"choiceHint": "Downloads an approximately 5.0 GB local model; requires 16 GB RAM",
|
||||
"groupId": "llama-cpp",
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"method": "custom",
|
||||
"choiceId": "lmstudio",
|
||||
"appGuidedDiscovery": true,
|
||||
"appGuidedActionLabel": "Connect server",
|
||||
"appGuidedSecret": true,
|
||||
"choiceLabel": "LM Studio",
|
||||
"choiceHint": "Connect to a running LM Studio server and use an already loaded model",
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"method": "local",
|
||||
"choiceId": "ollama",
|
||||
"appGuidedDiscovery": true,
|
||||
"appGuidedActionLabel": "Choose connection",
|
||||
"choiceLabel": "Ollama",
|
||||
"choiceHint": "Connect to an Ollama server and select a cloud or local model",
|
||||
"icon": "https://cdn.simpleicons.org/ollama",
|
||||
|
||||
@@ -127,6 +127,7 @@ describe("OpenClaw setup detection protocol", () => {
|
||||
brandId: "lmstudio",
|
||||
label: "LM Studio",
|
||||
hint: "Local/self-hosted LM Studio server",
|
||||
actionLabel: "Connect server",
|
||||
icon: "https://cdn.simpleicons.org/lmstudio",
|
||||
website: "https://lmstudio.ai/download",
|
||||
},
|
||||
|
||||
@@ -266,6 +266,7 @@ export const SystemAgentSetupDetectResultSchema = closedObject({
|
||||
brandId: Type.Optional(NonEmptyString),
|
||||
label: NonEmptyString,
|
||||
hint: Type.Optional(Type.String()),
|
||||
actionLabel: Type.Optional(NonEmptyString),
|
||||
icon: Type.Optional(SetupInferenceHttpsUrl),
|
||||
website: Type.Optional(SetupInferenceHttpsUrl),
|
||||
}),
|
||||
|
||||
@@ -1258,6 +1258,7 @@ describe("loadPluginManifestRegistry", () => {
|
||||
assistantPriority: 10,
|
||||
assistantVisibility: "visible",
|
||||
appGuidedSecret: true,
|
||||
appGuidedActionLabel: "Connect account",
|
||||
appGuidedDiscovery: true,
|
||||
},
|
||||
],
|
||||
@@ -1326,6 +1327,7 @@ describe("loadPluginManifestRegistry", () => {
|
||||
assistantPriority: 10,
|
||||
assistantVisibility: "visible",
|
||||
appGuidedSecret: true,
|
||||
appGuidedActionLabel: "Connect account",
|
||||
appGuidedDiscovery: true,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -321,6 +321,7 @@ export function normalizeProviderAuthChoices(
|
||||
const cliOption = normalizeOptionalString(entry.cliOption) ?? "";
|
||||
const cliDescription = normalizeOptionalString(entry.cliDescription) ?? "";
|
||||
const appGuidedSecret = entry.appGuidedSecret === true;
|
||||
const appGuidedActionLabel = normalizeOptionalString(entry.appGuidedActionLabel) ?? "";
|
||||
const appGuidedAuth =
|
||||
entry.appGuidedAuth === "oauth" || entry.appGuidedAuth === "device-code"
|
||||
? entry.appGuidedAuth
|
||||
@@ -351,6 +352,7 @@ export function normalizeProviderAuthChoices(
|
||||
...(cliOption ? { cliOption } : {}),
|
||||
...(cliDescription ? { cliDescription } : {}),
|
||||
...(appGuidedSecret ? { appGuidedSecret: true } : {}),
|
||||
...(appGuidedActionLabel ? { appGuidedActionLabel } : {}),
|
||||
...(appGuidedAuth ? { appGuidedAuth } : {}),
|
||||
...(onboardingScopes.length > 0 ? { onboardingScopes } : {}),
|
||||
});
|
||||
|
||||
@@ -550,6 +550,8 @@ export type PluginManifestProviderAuthChoice = {
|
||||
cliDescription?: string;
|
||||
/** One pasted secret plus provider defaults is sufficient for app-guided setup. */
|
||||
appGuidedSecret?: boolean;
|
||||
/** Short provider-owned command label for starting app-guided setup. */
|
||||
appGuidedActionLabel?: string;
|
||||
/** Provider-owned interactive login that native setup clients can render generically. */
|
||||
appGuidedAuth?: "oauth" | "device-code";
|
||||
/**
|
||||
|
||||
@@ -322,6 +322,7 @@ describe("provider auth choice manifest helpers", () => {
|
||||
cliFlag: "--openai-api-key",
|
||||
cliOption: "--openai-api-key <key>",
|
||||
appGuidedSecret: true,
|
||||
appGuidedActionLabel: "Connect account",
|
||||
appGuidedDiscovery: true,
|
||||
},
|
||||
],
|
||||
@@ -368,6 +369,7 @@ describe("provider auth choice manifest helpers", () => {
|
||||
cliFlag: "--openai-api-key",
|
||||
cliOption: "--openai-api-key <key>",
|
||||
appGuidedSecret: true,
|
||||
appGuidedActionLabel: "Connect account",
|
||||
appGuidedDiscovery: true,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -31,6 +31,7 @@ export type ProviderAuthChoiceMetadata = {
|
||||
cliOption?: string;
|
||||
cliDescription?: string;
|
||||
appGuidedSecret?: boolean;
|
||||
appGuidedActionLabel?: string;
|
||||
appGuidedDiscovery?: boolean;
|
||||
appGuidedAuth?: "oauth" | "device-code";
|
||||
onboardingScopes?: ("text-inference" | "image-generation" | "music-generation")[];
|
||||
@@ -113,6 +114,7 @@ function toProviderAuthChoiceCandidate(params: {
|
||||
...(choice.cliOption ? { cliOption: choice.cliOption } : {}),
|
||||
...(choice.cliDescription ? { cliDescription: choice.cliDescription } : {}),
|
||||
...(choice.appGuidedSecret ? { appGuidedSecret: true } : {}),
|
||||
...(choice.appGuidedActionLabel ? { appGuidedActionLabel: choice.appGuidedActionLabel } : {}),
|
||||
...(choice.appGuidedDiscovery ? { appGuidedDiscovery: true } : {}),
|
||||
...(choice.appGuidedAuth ? { appGuidedAuth: choice.appGuidedAuth } : {}),
|
||||
...(choice.onboardingScopes ? { onboardingScopes: choice.onboardingScopes } : {}),
|
||||
|
||||
@@ -35,6 +35,7 @@ export type SetupInferencePrepareOption = {
|
||||
brandId?: string;
|
||||
label: string;
|
||||
hint?: string;
|
||||
actionLabel?: string;
|
||||
icon?: string;
|
||||
website?: string;
|
||||
};
|
||||
@@ -158,6 +159,9 @@ export function listSetupInferencePrepareOptions(
|
||||
brandId: choice.providerId,
|
||||
label: choice.choiceLabel,
|
||||
...(choice.choiceHint?.trim() ? { hint: choice.choiceHint.trim() } : {}),
|
||||
...(choice.appGuidedActionLabel?.trim()
|
||||
? { actionLabel: choice.appGuidedActionLabel.trim() }
|
||||
: {}),
|
||||
...(choice.icon ? { icon: choice.icon } : {}),
|
||||
...(choice.website ? { website: choice.website } : {}),
|
||||
},
|
||||
|
||||
@@ -540,6 +540,7 @@ describe("detectSetupInference", () => {
|
||||
methodId: "ambient",
|
||||
choiceId: "local-model",
|
||||
choiceLabel: "Local Server",
|
||||
appGuidedActionLabel: "Connect server",
|
||||
appGuidedDiscovery: true,
|
||||
icon: "https://cdn.example.com/local.svg",
|
||||
website: "https://local.example.com/download",
|
||||
@@ -569,6 +570,14 @@ describe("detectSetupInference", () => {
|
||||
]);
|
||||
expect(detect).toHaveBeenCalledOnce();
|
||||
expect(prepare).not.toHaveBeenCalled();
|
||||
expect(detection.prepareOptions).toEqual([
|
||||
expect.objectContaining({
|
||||
id: "local-model",
|
||||
brandId: "local",
|
||||
label: "Local Server",
|
||||
actionLabel: "Connect server",
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("surfaces an invalid existing config instead of treating it as fresh", async () => {
|
||||
|
||||
@@ -22,18 +22,21 @@ const prepareOptions = [
|
||||
brandId: "ollama",
|
||||
label: "Ollama",
|
||||
hint: "Connect to an Ollama server and select a cloud or local model",
|
||||
actionLabel: "Choose connection",
|
||||
},
|
||||
{
|
||||
id: "llama-cpp",
|
||||
brandId: "llama-cpp",
|
||||
label: "Local model (llama.cpp)",
|
||||
hint: "Download and run a private GGUF model",
|
||||
actionLabel: "Review download",
|
||||
},
|
||||
{
|
||||
id: "lmstudio",
|
||||
brandId: "lmstudio",
|
||||
label: "LM Studio",
|
||||
hint: "Connect to a running LM Studio server and use an already loaded model",
|
||||
actionLabel: "Connect server",
|
||||
icon: "https://cdn.simpleicons.org/lmstudio",
|
||||
website: "https://lmstudio.ai/download",
|
||||
},
|
||||
@@ -137,7 +140,7 @@ describeControlUiE2e("Control UI llama.cpp setup mocked Gateway E2E", () => {
|
||||
const response = await page.goto(`${server.baseUrl}settings/model-setup`);
|
||||
expect(response?.status()).toBe(200);
|
||||
const llamaCppRow = page.locator('[data-prepare-choice="llama-cpp"]');
|
||||
await llamaCppRow.getByRole("button", { name: "Check & set up" }).waitFor();
|
||||
await llamaCppRow.getByRole("button", { name: "Review download" }).waitFor();
|
||||
await expect
|
||||
.poll(() => llamaCppRow.locator('[data-provider-icon="llamacpp"]').count())
|
||||
.toBe(1);
|
||||
@@ -154,7 +157,7 @@ describeControlUiE2e("Control UI llama.cpp setup mocked Gateway E2E", () => {
|
||||
});
|
||||
}
|
||||
|
||||
await llamaCppRow.getByRole("button", { name: "Check & set up" }).click();
|
||||
await llamaCppRow.getByRole("button", { name: "Review download" }).click();
|
||||
const start = await gateway.waitForRequest("openclaw.setup.prepare.start");
|
||||
expect(start.params).toMatchObject({ authChoice: "llama-cpp" });
|
||||
await page.getByRole("heading", { name: "Set up a local model" }).waitFor();
|
||||
|
||||
@@ -22,6 +22,7 @@ const prepareOptions = [
|
||||
brandId: "lmstudio",
|
||||
label: "LM Studio",
|
||||
hint: "Connect to a running LM Studio server and use an already loaded model",
|
||||
actionLabel: "Connect server",
|
||||
icon: "https://cdn.simpleicons.org/lmstudio",
|
||||
website: "https://lmstudio.ai/download",
|
||||
},
|
||||
@@ -138,7 +139,7 @@ describeControlUiE2e("Control UI LM Studio setup mocked Gateway E2E", () => {
|
||||
const response = await page.goto(`${server.baseUrl}settings/model-setup`);
|
||||
expect(response?.status()).toBe(200);
|
||||
const lmStudioRow = page.locator('[data-prepare-choice="lmstudio"]');
|
||||
await lmStudioRow.getByRole("button", { name: "Check & set up" }).waitFor();
|
||||
await lmStudioRow.getByRole("button", { name: "Connect server" }).waitFor();
|
||||
await expect
|
||||
.poll(() => lmStudioRow.locator('[data-provider-icon="lmstudio"]').count())
|
||||
.toBe(1);
|
||||
@@ -152,7 +153,7 @@ describeControlUiE2e("Control UI LM Studio setup mocked Gateway E2E", () => {
|
||||
});
|
||||
}
|
||||
|
||||
await lmStudioRow.getByRole("button", { name: "Check & set up" }).click();
|
||||
await lmStudioRow.getByRole("button", { name: "Connect server" }).click();
|
||||
const start = await gateway.waitForRequest("openclaw.setup.prepare.start");
|
||||
expect(start.params).toMatchObject({ authChoice: "lmstudio" });
|
||||
await expect
|
||||
|
||||
@@ -22,18 +22,21 @@ const localPrepareOptions = [
|
||||
brandId: "ollama",
|
||||
label: "Ollama",
|
||||
hint: "Connect to an Ollama server and select a cloud or local model",
|
||||
actionLabel: "Choose connection",
|
||||
},
|
||||
{
|
||||
id: "llama-cpp",
|
||||
brandId: "llama-cpp",
|
||||
label: "Local model (llama.cpp)",
|
||||
hint: "Download and run a private GGUF model",
|
||||
actionLabel: "Review download",
|
||||
},
|
||||
{
|
||||
id: "lmstudio",
|
||||
brandId: "lmstudio",
|
||||
label: "LM Studio",
|
||||
hint: "Connect to a running LM Studio server and use an already loaded model",
|
||||
actionLabel: "Connect server",
|
||||
icon: "https://cdn.simpleicons.org/lmstudio",
|
||||
website: "https://lmstudio.ai/download",
|
||||
},
|
||||
@@ -383,7 +386,7 @@ describeControlUiE2e("Control UI Model Setup mocked Gateway E2E", () => {
|
||||
expect(new Set(localProviderIconColors).size).toBe(1);
|
||||
await page
|
||||
.locator('[data-prepare-choice="ollama"]')
|
||||
.getByRole("button", { name: "Check & set up" })
|
||||
.getByRole("button", { name: "Choose connection" })
|
||||
.click();
|
||||
|
||||
const start = await gateway.waitForRequest("openclaw.setup.prepare.start");
|
||||
|
||||
@@ -6,6 +6,7 @@ export type ModelSetupPrepareOption = {
|
||||
brandId?: string;
|
||||
label: string;
|
||||
hint?: string;
|
||||
actionLabel?: string;
|
||||
icon?: string;
|
||||
website?: string;
|
||||
};
|
||||
|
||||
@@ -69,6 +69,7 @@ const detected: SystemAgentSetupDetectResult = {
|
||||
brandId: "ollama",
|
||||
label: "Ollama",
|
||||
hint: "Connect to an Ollama server and select a cloud or local model",
|
||||
actionLabel: "Choose connection",
|
||||
icon: "https://cdn.simpleicons.org/ollama",
|
||||
website: "https://ollama.com/download",
|
||||
},
|
||||
@@ -77,6 +78,7 @@ const detected: SystemAgentSetupDetectResult = {
|
||||
brandId: "lmstudio",
|
||||
label: "LM Studio",
|
||||
hint: "Connect to a running LM Studio server and use an already loaded model",
|
||||
actionLabel: "Connect server",
|
||||
icon: "https://cdn.simpleicons.org/lmstudio",
|
||||
website: "https://lmstudio.ai/download",
|
||||
},
|
||||
@@ -85,6 +87,7 @@ const detected: SystemAgentSetupDetectResult = {
|
||||
brandId: "llama-cpp",
|
||||
label: "Local model (llama.cpp)",
|
||||
hint: "Download and run a private GGUF model",
|
||||
actionLabel: "Review download",
|
||||
},
|
||||
],
|
||||
recommendedInstalls: [
|
||||
@@ -498,8 +501,12 @@ describe("renderModelSetup", () => {
|
||||
const llamaCpp = container.querySelector<HTMLButtonElement>(
|
||||
'[data-prepare-choice="llama-cpp"] button',
|
||||
);
|
||||
expect(ollama?.textContent).toContain("Check & set up");
|
||||
expect(llamaCpp?.textContent).toContain("Check & set up");
|
||||
expect(ollama?.textContent).toContain("Choose connection");
|
||||
expect(llamaCpp?.textContent).toContain("Review download");
|
||||
expect(
|
||||
container.querySelector<HTMLButtonElement>('[data-prepare-choice="lmstudio"] button')
|
||||
?.textContent,
|
||||
).toContain("Connect server");
|
||||
const llamaCppRow = container.querySelector('[data-prepare-choice="llama-cpp"]');
|
||||
expect(llamaCppRow?.querySelector('[data-provider-icon="llamacpp"]')).not.toBeNull();
|
||||
expect(text(llamaCppRow!)).toContain("llama.cpp");
|
||||
|
||||
@@ -436,7 +436,7 @@ function renderPrepare(props: ModelSetupViewProps, result: SystemAgentSetupDetec
|
||||
?disabled=${props.actionsDisabled}
|
||||
@click=${() => props.onStartPrepare(option)}
|
||||
>
|
||||
${t("modelSetup.prepare.ollamaButton")}
|
||||
${option.actionLabel ?? t("modelSetup.prepare.ollamaButton")}
|
||||
</button>
|
||||
</div>
|
||||
`,
|
||||
|
||||
Reference in New Issue
Block a user