feat(providers): an OpenAI-compatible preset for any vLLM, LM Studio or gateway URL

Step 8 of the provider refactor plan, a new provider made of one record.
'custom' runs on @ai-sdk/openai-compatible with <think> extraction, merges
system messages (open-source chat templates reject several), has no default
URL (so a key alone does not count as connected, and the chat endpoint is
shown under the URL field) and lists models from its /models. Server side:
CUSTOM_API_KEY and CUSTOM_BASE_URL, ADMIN_CUSTOM_* in the admin panel.
env.example and the three provider docs gained a section; the picker count
in the e2e test is 25 and a new e2e test walks through the preset. The
behavior snapshot gained the new provider's 146 rows; its two 'No AI provider
configured' rows list CUSTOM_API_KEY now.
This commit is contained in:
dayuan.jiang
2026-10-12 21:17:51 +09:00
parent 717f7e9445
commit b2cadfa5bf
9 changed files with 246 additions and 9 deletions
+29 -1
View File
@@ -127,7 +127,7 @@ test("the provider picker searches, marks added ones, and Enter picks", async ({
dialog.getByTestId("pick-provider-anthropic"),
).not.toContainText("Added")
await expect(dialog.locator('[data-testid^="pick-provider-"]')).toHaveCount(
24,
25,
)
await search.fill("zzz")
@@ -596,6 +596,34 @@ test("Azure needs its resource URL before it counts as connected", async ({
await expect(dialog.getByTestId("test-models")).toBeEnabled()
})
test("the OpenAI-compatible preset takes any URL and shows where requests go", async ({
page,
}) => {
await openApp(page)
await openSettings(page)
const dialog = settingsDialog(page)
// Not among the popular ones: it is in the full picker
await dialog.getByRole("button", { name: /^See all \d+ providers/ }).click()
await dialog.getByTestId("pick-provider-custom").click()
await expect(
dialog.getByRole("heading", { name: "OpenAI-compatible", exact: true }),
).toBeVisible()
// No URL yet: a key alone does not count as connected
await dialog.locator("#api-key").fill("any")
await expect(dialog.getByTestId("step-1-todo")).toBeVisible()
await expect(
dialog.getByText("Fill in the API key and the base URL first."),
).toBeVisible()
// Its options start open; the URL field shows the chat endpoint
await dialog.locator("#base-url").fill("http://127.0.0.1:1234/v1")
await expect(
dialog.getByText(
"Requests go to http://127.0.0.1:1234/v1/chat/completions",
),
).toBeVisible()
await expect(dialog.getByTestId("step-1-done")).toBeVisible()
})
test("a model id typed for one provider does not follow to the next", async ({
page,
}) => {
+148 -2
View File
@@ -3454,6 +3454,150 @@
{"provider":"atlascloud","modelId":"qwen/qwen3.5-flash","shape":"keyAndPrivateUrl","env":"adminAws","getAIModel":{"provider":"atlascloud","modelId":"qwen/qwen3.5-flash","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"qwen/qwen3.5-flash","options":{"name":"atlascloud","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"atlascloud","modelId":"qwen/qwen3.5-flash","shape":"keyAndPrivateUrl","env":"desktop","getAIModel":{"provider":"atlascloud","modelId":"qwen/qwen3.5-flash","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"qwen/qwen3.5-flash","options":{"name":"atlascloud","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"atlascloud","modelId":"qwen/qwen3.5-flash","shape":"keyAndPrivateUrl","env":"everything","getAIModel":{"provider":"atlascloud","modelId":"qwen/qwen3.5-flash","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"qwen/qwen3.5-flash","options":{"name":"atlascloud","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"none","env":"empty","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"none","env":"serverKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"none","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"none","env":"ollamaKey","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"none","env":"azureResource","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"none","env":"anthropicToken","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"none","env":"adminAws","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"none","env":"desktop","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"none","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"empty","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"serverKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"serverKeyAndUrl","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"ollamaKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"azureResource","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"anthropicToken","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"adminAws","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"desktop","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"key","env":"everything","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"url","env":"empty","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"url","env":"serverKey","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"url","env":"serverKeyAndUrl","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"url","env":"ollamaKey","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"url","env":"azureResource","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"url","env":"anthropicToken","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"url","env":"adminAws","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"url","env":"desktop","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"url","env":"everything","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"empty","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"serverKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"ollamaKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"azureResource","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"anthropicToken","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"adminAws","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"desktop","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndUrl","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"empty","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"serverKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"serverKeyAndUrl","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"ollamaKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"azureResource","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"anthropicToken","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"adminAws","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"desktop","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndSlash","env":"everything","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"empty","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"serverKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"ollamaKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"azureResource","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"anthropicToken","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"adminAws","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"desktop","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPastedPath","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"https://u.example/v1/chat/completions","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"empty","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"serverKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"ollamaKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"azureResource","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"anthropicToken","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"adminAws","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"desktop","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnv","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"empty","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"serverKey","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"serverKeyAndUrl","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"ollamaKey","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"azureResource","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"anthropicToken","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"adminAws","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"desktop","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvEmpty","env":"everything","getAIModel":{"error":"CUSTOM_KEY_EMPTY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"empty","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"serverKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"ollamaKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"azureResource","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"anthropicToken","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"adminAws","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"desktop","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayPartial","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"empty","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"serverKey","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"serverKeyAndUrl","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"ollamaKey","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"azureResource","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"anthropicToken","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"adminAws","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"desktop","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvArrayEmpty","env":"everything","getAIModel":{"error":"At least one of [CUSTOM_KEY_EMPTY, CUSTOM_KEY_EMPTY_2] environment variables is required for custom provider. Please set at least one in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"empty","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"serverKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"ollamaKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"azureResource","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"anthropicToken","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"adminAws","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"desktop","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"keyEnvAndUrlEnv","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"custom-env-key","baseURL":"https://custom-env.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"empty","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"serverKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"ollamaKey","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"azureResource","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"anthropicToken","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"adminAws","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"desktop","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsPair","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"empty","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"serverKey","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"ollamaKey","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"azureResource","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"anthropicToken","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"adminAws","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"desktop","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"awsIdOnly","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://server.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"empty","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"serverKey","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"serverKeyAndUrl","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"ollamaKey","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"azureResource","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"anthropicToken","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"adminAws","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"desktop","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"vertexKeyAndUrl","env":"everything","getAIModel":{"error":"API key is required when using a custom base URL. Please provide your own API key in Settings."},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"empty","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"serverKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://u.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://u.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"ollamaKey","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"azureResource","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"anthropicToken","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"adminAws","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"desktop","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://u.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"trustedUrl","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"server-key","baseURL":"https://u.example/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"https://u.example/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"empty","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"serverKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"serverKeyAndUrl","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"ollamaKey","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"azureResource","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"anthropicToken","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"adminAws","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"desktop","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":false,"chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"provider":"custom","modelId":"test-model","shape":"keyAndPrivateUrl","env":"everything","getAIModel":{"provider":"custom","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"custom","apiKey":"client-key","baseURL":"http://10.0.0.5:8000/v1","fetch":"guarded","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}},"usesServerCredentials":false,"usesServerEndpoint":true,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":"http://10.0.0.5:8000/v1/chat/completions"}
{"noProvider":true,"env":"only OPENAI_API_KEY","serverProvider":"openai","getAIModel":{"provider":"openai","modelId":"test-model","model":{"factory":"openai","method":"default","modelId":"test-model","options":{"apiKey":"server-key"}}}}
{"noProvider":true,"env":"only ANTHROPIC_API_KEY","serverProvider":"anthropic","getAIModel":{"provider":"anthropic","modelId":"test-model","model":{"factory":"anthropic","method":"default","modelId":"test-model","options":{"apiKey":"server-key","baseURL":"https://api.anthropic.com/v1"}}}}
{"noProvider":true,"env":"only GOOGLE_GENERATIVE_AI_API_KEY","serverProvider":"google","getAIModel":{"provider":"google","modelId":"test-model","model":{"factory":"google","method":"default","modelId":"test-model","options":{"apiKey":"server-key"}}}}
@@ -3475,9 +3619,10 @@
{"noProvider":true,"env":"only NOVITA_API_KEY","serverProvider":"novita","getAIModel":{"provider":"novita","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"novita","apiKey":"server-key","baseURL":"https://api.novita.ai/openai","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}}}
{"noProvider":true,"env":"only MIMO_API_KEY","serverProvider":"mimo","getAIModel":{"provider":"mimo","modelId":"test-model","model":{"factory":"deepseek","method":"default","modelId":"test-model","options":{"apiKey":"server-key","baseURL":"https://api.xiaomimimo.com/v1"}}}}
{"noProvider":true,"env":"only ATLASCLOUD_API_KEY","serverProvider":"atlascloud","getAIModel":{"provider":"atlascloud","modelId":"test-model","model":{"wrapped":{"factory":"openai-compatible","method":"default","modelId":"test-model","options":{"name":"atlascloud","apiKey":"server-key","baseURL":"https://api.atlascloud.ai/v1","includeUsage":true}},"middleware":{"middleware":"extractReasoning","tagName":"think"}}}}
{"noProvider":true,"env":"only CUSTOM_API_KEY","serverProvider":"custom","getAIModel":{"error":"OpenAI-compatible needs a base URL. Add it in the model settings."}}
{"noProvider":true,"env":"vertex and openai","serverProvider":null,"getAIModel":{"error":"Multiple AI providers configured (openai, vertexai). Please set AI_PROVIDER to specify which one to use."}}
{"noProvider":true,"env":"only OLLAMA_API_KEY","serverProvider":null,"getAIModel":{"error":"No AI provider configured. Please set one of the following API keys in your .env.local file:\n- OPENAI_API_KEY for openai\n- ANTHROPIC_API_KEY for anthropic\n- GOOGLE_GENERATIVE_AI_API_KEY for google\n- DEEPSEEK_API_KEY for deepseek\n- QWEN_API_KEY for qwen\n- DOUBAO_API_KEY for doubao\n- GLM_API_KEY for glm\n- KIMI_API_KEY for kimi\n- MINIMAX_API_KEY for minimax\n- MIMO_API_KEY for mimo\n- OPENROUTER_API_KEY for openrouter\n- AIHUBMIX_API_KEY for aihubmix\n- SILICONFLOW_API_KEY for siliconflow\n- MODELSCOPE_API_KEY for modelscope\n- NOVITA_API_KEY for novita\n- ATLASCLOUD_API_KEY for atlascloud\n- QINIU_API_KEY for qiniu\n- AI_GATEWAY_API_KEY for gateway\n- GOOGLE_VERTEX_API_KEY for vertexai\n- AZURE_API_KEY for azure\n- SGLANG_API_KEY for sglang\n- AWS_ACCESS_KEY_ID for bedrock\nOr set AI_PROVIDER=ollama for local Ollama."}}
{"noProvider":true,"env":"no key at all","serverProvider":null,"getAIModel":{"error":"No AI provider configured. Please set one of the following API keys in your .env.local file:\n- OPENAI_API_KEY for openai\n- ANTHROPIC_API_KEY for anthropic\n- GOOGLE_GENERATIVE_AI_API_KEY for google\n- DEEPSEEK_API_KEY for deepseek\n- QWEN_API_KEY for qwen\n- DOUBAO_API_KEY for doubao\n- GLM_API_KEY for glm\n- KIMI_API_KEY for kimi\n- MINIMAX_API_KEY for minimax\n- MIMO_API_KEY for mimo\n- OPENROUTER_API_KEY for openrouter\n- AIHUBMIX_API_KEY for aihubmix\n- SILICONFLOW_API_KEY for siliconflow\n- MODELSCOPE_API_KEY for modelscope\n- NOVITA_API_KEY for novita\n- ATLASCLOUD_API_KEY for atlascloud\n- QINIU_API_KEY for qiniu\n- AI_GATEWAY_API_KEY for gateway\n- GOOGLE_VERTEX_API_KEY for vertexai\n- AZURE_API_KEY for azure\n- SGLANG_API_KEY for sglang\n- AWS_ACCESS_KEY_ID for bedrock\nOr set AI_PROVIDER=ollama for local Ollama."}}
{"noProvider":true,"env":"only OLLAMA_API_KEY","serverProvider":null,"getAIModel":{"error":"No AI provider configured. Please set one of the following API keys in your .env.local file:\n- OPENAI_API_KEY for openai\n- ANTHROPIC_API_KEY for anthropic\n- GOOGLE_GENERATIVE_AI_API_KEY for google\n- DEEPSEEK_API_KEY for deepseek\n- QWEN_API_KEY for qwen\n- DOUBAO_API_KEY for doubao\n- GLM_API_KEY for glm\n- KIMI_API_KEY for kimi\n- MINIMAX_API_KEY for minimax\n- MIMO_API_KEY for mimo\n- OPENROUTER_API_KEY for openrouter\n- AIHUBMIX_API_KEY for aihubmix\n- SILICONFLOW_API_KEY for siliconflow\n- MODELSCOPE_API_KEY for modelscope\n- NOVITA_API_KEY for novita\n- ATLASCLOUD_API_KEY for atlascloud\n- QINIU_API_KEY for qiniu\n- AI_GATEWAY_API_KEY for gateway\n- GOOGLE_VERTEX_API_KEY for vertexai\n- AZURE_API_KEY for azure\n- SGLANG_API_KEY for sglang\n- CUSTOM_API_KEY for custom\n- AWS_ACCESS_KEY_ID for bedrock\nOr set AI_PROVIDER=ollama for local Ollama."}}
{"noProvider":true,"env":"no key at all","serverProvider":null,"getAIModel":{"error":"No AI provider configured. Please set one of the following API keys in your .env.local file:\n- OPENAI_API_KEY for openai\n- ANTHROPIC_API_KEY for anthropic\n- GOOGLE_GENERATIVE_AI_API_KEY for google\n- DEEPSEEK_API_KEY for deepseek\n- QWEN_API_KEY for qwen\n- DOUBAO_API_KEY for doubao\n- GLM_API_KEY for glm\n- KIMI_API_KEY for kimi\n- MINIMAX_API_KEY for minimax\n- MIMO_API_KEY for mimo\n- OPENROUTER_API_KEY for openrouter\n- AIHUBMIX_API_KEY for aihubmix\n- SILICONFLOW_API_KEY for siliconflow\n- MODELSCOPE_API_KEY for modelscope\n- NOVITA_API_KEY for novita\n- ATLASCLOUD_API_KEY for atlascloud\n- QINIU_API_KEY for qiniu\n- AI_GATEWAY_API_KEY for gateway\n- GOOGLE_VERTEX_API_KEY for vertexai\n- AZURE_API_KEY for azure\n- SGLANG_API_KEY for sglang\n- CUSTOM_API_KEY for custom\n- AWS_ACCESS_KEY_ID for bedrock\nOr set AI_PROVIDER=ollama for local Ollama."}}
{"noProvider":true,"env":"AI_PROVIDER=openai","getAIModel":{"error":"OPENAI_API_KEY environment variable is required for openai provider. Please set it in your .env.local file."}}
{"noProvider":true,"env":"AI_PROVIDER=anthropic","getAIModel":{"error":"Either ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN environment variable is required for anthropic provider. Please set one in your .env.local file."}}
{"noProvider":true,"env":"AI_PROVIDER=google","getAIModel":{"error":"GOOGLE_GENERATIVE_AI_API_KEY environment variable is required for google provider. Please set it in your .env.local file."}}
@@ -3502,6 +3647,7 @@
{"noProvider":true,"env":"AI_PROVIDER=novita","getAIModel":{"error":"NOVITA_API_KEY environment variable is required for novita provider. Please set it in your .env.local file."}}
{"noProvider":true,"env":"AI_PROVIDER=mimo","getAIModel":{"error":"MIMO_API_KEY environment variable is required for mimo provider. Please set it in your .env.local file."}}
{"noProvider":true,"env":"AI_PROVIDER=atlascloud","getAIModel":{"error":"ATLASCLOUD_API_KEY environment variable is required for atlascloud provider. Please set it in your .env.local file."}}
{"noProvider":true,"env":"AI_PROVIDER=custom","getAIModel":{"error":"CUSTOM_API_KEY environment variable is required for custom provider. Please set it in your .env.local file."}}
{"provider":"openai","modelId":"gpt-5","shape":"none","env":"empty","getAIModel":{"error":"OPENAI_API_KEY environment variable is required for openai provider. Please set it in your .env.local file."},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"openai","modelId":"gpt-5","shape":"none","env":"serverKey","getAIModel":{"provider":"openai","modelId":"gpt-5","model":{"factory":"openai","method":"default","modelId":"gpt-5","options":{"apiKey":"server-key"}},"providerOptions":{"openai":{"reasoningSummary":"auto"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"chatRequestUrl":null}
{"provider":"openai","modelId":"gpt-5","shape":"none","env":"serverKeyAndUrl","getAIModel":{"provider":"openai","modelId":"gpt-5","model":{"factory":"openai","method":"chat","modelId":"gpt-5","options":{"apiKey":"server-key","baseURL":"https://server.example/v1"}},"providerOptions":{"openai":{"reasoningSummary":"auto"}}},"usesServerCredentials":true,"usesServerEndpoint":false,"globalBaseUrl":"https://server.example/v1","chatRequestUrl":null}
+3 -1
View File
@@ -158,6 +158,7 @@ const MATRIX_PROVIDERS: ProviderName[] = [
"novita",
"mimo",
"atlascloud",
"custom",
]
/** The model id each provider runs in the matrix (the first suggested one) */
@@ -186,6 +187,7 @@ const MATRIX_MODEL_IDS: Record<ProviderName, string> = {
novita: "minimax/minimax-m3",
mimo: "mimo-v2.5-pro",
atlascloud: "qwen/qwen3.5-flash",
custom: "test-model",
}
/** Model ids whose providerOptions the snapshot records for openai and google */
@@ -449,7 +451,7 @@ describe("provider behavior snapshot", () => {
})
it("matches the recorded behavior", async () => {
// The matrix: 24 providers, 16 shapes, 9 environments
// The matrix: 25 providers, 16 shapes, 9 environments
for (const provider of MATRIX_PROVIDERS) {
await matrix(provider, MATRIX_MODEL_IDS[provider])
}
+4 -4
View File
@@ -24,16 +24,16 @@ const sorted = (list: Iterable<string>) => [...list].sort()
describe("the provider record", () => {
it("is what the rest of the app imports as PROVIDER_INFO", () => {
expect(PROVIDER_INFO).toBe(PROVIDERS)
expect(PROVIDER_NAMES).toHaveLength(24)
expect(PROVIDER_NAMES).toHaveLength(25)
})
it("has 21 providers taking part in server key auto-detection", () => {
it("has 22 providers taking part in server key auto-detection", () => {
// credential apiKey or vertexKey: the providers whose <P>_API_KEY the
// server must have; aws, optionalKey and none need no key
const detected = PROVIDER_NAMES.filter((p) =>
["apiKey", "vertexKey"].includes(PROVIDERS[p].credential),
)
expect(detected).toHaveLength(21)
expect(detected).toHaveLength(22)
// Ollama has a key variable too, an optional one
const withKeyVar = PROVIDER_NAMES.filter((p) => !!envVarsOf(p).apiKey)
expect(sorted(detected)).toEqual(
@@ -142,7 +142,7 @@ describe("the picker's order", () => {
id: "cloud",
providers: ["bedrock", "vertexai", "azure", "edgeone"],
},
{ id: "selfHosted", providers: ["ollama", "sglang"] },
{ id: "selfHosted", providers: ["ollama", "sglang", "custom"] },
])
})