diff --git a/packages/core/src/plugin/provider/lmstudio.ts b/packages/core/src/plugin/provider/lmstudio.ts index ada8996bb98..3266f302615 100644 --- a/packages/core/src/plugin/provider/lmstudio.ts +++ b/packages/core/src/plugin/provider/lmstudio.ts @@ -70,13 +70,11 @@ export function make(origin = "http://127.0.0.1:1234", interval: Duration.Input input: ["text", ...(item.capabilities?.vision ? ["image"] : [])], output: ["text"], } - model.limit = { - context: - item.loaded_instances.length === 0 - ? item.max_context_length - : Math.min(...item.loaded_instances.map((instance) => instance.config.context_length)), - output: 0, - } + const context = + item.loaded_instances.length === 0 + ? item.max_context_length + : Math.min(...item.loaded_instances.map((instance) => instance.config.context_length)) + if (context > 0) model.limit.context = context }) } }) diff --git a/packages/core/src/plugin/provider/ollama.ts b/packages/core/src/plugin/provider/ollama.ts index 2b0e03def91..3e6bc8648ad 100644 --- a/packages/core/src/plugin/provider/ollama.ts +++ b/packages/core/src/plugin/provider/ollama.ts @@ -96,13 +96,10 @@ export function make(origin = "http://127.0.0.1:11434", interval: Duration.Input input: ["text", ...(item.show.capabilities?.includes("vision") ? ["image"] : [])], output: ["text"], } - model.limit = { - context: - Object.entries(item.show.model_info ?? {}).flatMap(([key, value]) => - key.endsWith(".context_length") && typeof value === "number" && value > 0 ? [value] : [], - )[0] ?? 0, - output: 0, - } + const context = Object.entries(item.show.model_info ?? {}).flatMap(([key, value]) => + key.endsWith(".context_length") && typeof value === "number" && value > 0 ? [value] : [], + )[0] + if (context !== undefined) model.limit.context = context }) } }) diff --git a/packages/core/src/plugin/provider/vllm.ts b/packages/core/src/plugin/provider/vllm.ts index 0950f4e0b0c..3f723870b14 100644 --- a/packages/core/src/plugin/provider/vllm.ts +++ b/packages/core/src/plugin/provider/vllm.ts @@ -55,7 +55,8 @@ export function make(origin = "http://127.0.0.1:8000", interval: Duration.Input model.name = item.id // Tool calling depends on vLLM server flags and parsers that model discovery does not report. model.capabilities = { tools: false, input: ["text"], output: ["text"] } - model.limit = { context: item.max_model_len ?? 0, output: 0 } + if (typeof item.max_model_len === "number" && item.max_model_len > 0) + model.limit.context = item.max_model_len }) } }) diff --git a/packages/core/test/plugin/provider-lmstudio.test.ts b/packages/core/test/plugin/provider-lmstudio.test.ts index f2b4b423c8e..e434b0899b3 100644 --- a/packages/core/test/plugin/provider-lmstudio.test.ts +++ b/packages/core/test/plugin/provider-lmstudio.test.ts @@ -71,6 +71,13 @@ describe("LMStudioPlugin", () => { max_context_length: 131_072, capabilities: { vision: false, trained_for_tool_use: false }, }, + { + type: "llm", + key: "unknown-context", + display_name: "Unknown Context", + loaded_instances: [], + max_context_length: 0, + }, { type: "embedding", key: "nomic-embed", @@ -104,11 +111,14 @@ describe("LMStudioPlugin", () => { family: "gemma4", name: "Gemma 4 26B A4B", capabilities: { tools: true, input: ["text", "image"], output: ["text"] }, - limit: { context: 16_384, output: 0 }, + limit: { context: 16_384, output: 32_000 }, }) expect(yield* catalog.model.get(providerID, Model.ID.make("deepseek-r1"))).toMatchObject({ capabilities: { tools: false, input: ["text"], output: ["text"] }, - limit: { context: 131_072, output: 0 }, + limit: { context: 131_072, output: 32_000 }, + }) + expect(yield* catalog.model.get(providerID, Model.ID.make("unknown-context"))).toMatchObject({ + limit: { context: 200_000, output: 32_000 }, }) expect(yield* catalog.model.get(providerID, Model.ID.make("nomic-embed"))).toBeUndefined() }), diff --git a/packages/core/test/plugin/provider-ollama.test.ts b/packages/core/test/plugin/provider-ollama.test.ts index f3f00ebe41e..1db57979df6 100644 --- a/packages/core/test/plugin/provider-ollama.test.ts +++ b/packages/core/test/plugin/provider-ollama.test.ts @@ -54,6 +54,7 @@ describe("OllamaPlugin", () => { return Response.json({ models: [ summary("gemma3:4b", "gemma-digest", "gemma3"), + summary("unknown-context", "unknown-digest"), summary("nomic-embed", "embed-digest"), summary("removed-model", "removed-digest"), ], @@ -68,6 +69,8 @@ describe("OllamaPlugin", () => { capabilities: ["completion", "tools", "vision"], model_info: { "gemma3.context_length": 131_072 }, } + : body.model === "unknown-context" + ? show({ family: "unknown", capabilities: ["completion"], context: 0 }) : show({ family: "nomic-bert", capabilities: ["embedding"], context: 8192 }), ) }, @@ -98,7 +101,10 @@ describe("OllamaPlugin", () => { name: "gemma3:4b", family: "gemma3", capabilities: { tools: true, input: ["text", "image"], output: ["text"] }, - limit: { context: 131_072, output: 0 }, + limit: { context: 131_072, output: 32_000 }, + }) + expect(yield* catalog.model.get(providerID, Model.ID.make("unknown-context"))).toMatchObject({ + limit: { context: 200_000, output: 32_000 }, }) expect(yield* catalog.model.get(providerID, Model.ID.make("nomic-embed"))).toBeUndefined() expect(requests).toContainEqual({ method: "GET", path: "/api/tags" }) diff --git a/packages/core/test/plugin/provider-vllm.test.ts b/packages/core/test/plugin/provider-vllm.test.ts index fb70390360c..3554e45fb4e 100644 --- a/packages/core/test/plugin/provider-vllm.test.ts +++ b/packages/core/test/plugin/provider-vllm.test.ts @@ -63,7 +63,11 @@ describe("VLLMPlugin", () => { state.models++ return Response.json({ object: "list", - data: [remoteModel("Qwen/Qwen3-Coder", 65_536), remoteModel("foreign-model", 4096, "other")], + data: [ + remoteModel("Qwen/Qwen3-Coder", 65_536), + remoteModel("unknown-limit", 0), + remoteModel("foreign-model", 4096, "other"), + ], }) }, }), @@ -97,7 +101,10 @@ describe("VLLMPlugin", () => { modelID: "Qwen/Qwen3-Coder", name: "Qwen/Qwen3-Coder", capabilities: { tools: false, input: ["text"], output: ["text"] }, - limit: { context: 65_536, output: 0 }, + limit: { context: 65_536, output: 32_000 }, + }) + expect(yield* catalog.model.get(providerID, Model.ID.make("unknown-limit"))).toMatchObject({ + limit: { context: 200_000, output: 32_000 }, }) expect(yield* catalog.model.get(providerID, Model.ID.make("foreign-model"))).toBeUndefined() }),