Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cli-nano-gpt-router-models.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@kilocode/cli": patch
---

Fix CLI `/model list` returning "No models available" for nano-gpt provider
1 change: 1 addition & 0 deletions cli/src/commands/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ async function ensureRouterModels(context: CommandContext): Promise<boolean> {
"io-intelligence",
"vercel-ai-gateway",
"ovhcloud",
"nano-gpt",
].includes(routerName)

if (!needsRouterModels) {
Expand Down
65 changes: 65 additions & 0 deletions cli/src/constants/providers/__tests__/models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,20 @@ describe("Static Provider Models", () => {
deepinfra: {},
"vercel-ai-gateway": {},
ovhcloud: {},
"nano-gpt": {
"deepseek/deepseek-v3.2": {
contextWindow: 128000,
supportsPromptCache: false,
inputPrice: 0.14,
outputPrice: 0.28,
},
"openai/gpt-4o": {
contextWindow: 128000,
supportsPromptCache: false,
inputPrice: 2.5,
outputPrice: 10,
},
},
}

it("should return router models for openrouter provider", () => {
Expand Down Expand Up @@ -261,6 +275,41 @@ describe("Static Provider Models", () => {
expect(result.models).toBeDefined()
expect(Object.keys(result.models).length).toBe(0)
})

describe("nano-gpt provider", () => {
it("should return router models for nano-gpt provider", () => {
const result = getModelsByProvider({
provider: "nano-gpt",
routerModels: mockRouterModels,
kilocodeDefaultModel: "",
})

expect(result.models).toBe(mockRouterModels["nano-gpt"])
expect(Object.keys(result.models)).toContain("deepseek/deepseek-v3.2")
expect(Object.keys(result.models)).toContain("openai/gpt-4o")
})

it("should return empty models when routerModels is null", () => {
const result = getModelsByProvider({
provider: "nano-gpt",
routerModels: null,
kilocodeDefaultModel: "",
})

expect(result.models).toEqual({})
})

it("should have correct default model for nano-gpt", () => {
const result = getModelsByProvider({
provider: "nano-gpt",
routerModels: mockRouterModels,
kilocodeDefaultModel: "",
})

// Default model should be defined
expect(result.defaultModel).toBeDefined()
})
})
})

describe("getModelsByProvider - Edge Cases", () => {
Expand Down Expand Up @@ -350,6 +399,10 @@ describe("Static Provider Models", () => {
expect(PROVIDER_TO_ROUTER_NAME.litellm).toBe("litellm")
})

it("should map nano-gpt to nano-gpt router name", () => {
expect(PROVIDER_TO_ROUTER_NAME["nano-gpt"]).toBe("nano-gpt")
})

it("should map static providers to null", () => {
expect(PROVIDER_TO_ROUTER_NAME.anthropic).toBeNull()
expect(PROVIDER_TO_ROUTER_NAME.gemini).toBeNull()
Expand All @@ -366,6 +419,10 @@ describe("Static Provider Models", () => {
expect(providerSupportsModelList("litellm")).toBe(true)
})

it("should return true for nano-gpt provider", () => {
expect(providerSupportsModelList("nano-gpt")).toBe(true)
})

it("should return false for static providers", () => {
expect(providerSupportsModelList("anthropic")).toBe(false)
expect(providerSupportsModelList("gemini")).toBe(false)
Expand All @@ -380,6 +437,10 @@ describe("Static Provider Models", () => {
expect(getRouterNameForProvider("ollama")).toBe("ollama")
})

it("should return nano-gpt for nano-gpt provider", () => {
expect(getRouterNameForProvider("nano-gpt")).toBe("nano-gpt")
})

it("should return null for static providers", () => {
expect(getRouterNameForProvider("anthropic")).toBeNull()
expect(getRouterNameForProvider("gemini")).toBeNull()
Expand All @@ -392,6 +453,10 @@ describe("Static Provider Models", () => {
expect(getModelFieldForProvider("ollama")).toBe("ollamaModelId")
})

it("should return nanoGptModelId for nano-gpt provider", () => {
expect(getModelFieldForProvider("nano-gpt")).toBe("nanoGptModelId")
})

it("should return null for static providers", () => {
expect(getModelFieldForProvider("anthropic")).toBeNull()
expect(getModelFieldForProvider("gemini")).toBeNull()
Expand Down
5 changes: 4 additions & 1 deletion cli/src/constants/providers/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export type RouterName =
| "deepinfra"
| "vercel-ai-gateway"
| "ovhcloud"
| "nano-gpt"

/**
* ModelInfo interface - mirrors the one from packages/types/src/model.ts
Expand Down Expand Up @@ -125,7 +126,7 @@ export const PROVIDER_TO_ROUTER_NAME: Record<ProviderName, RouterName | null> =
lmstudio: "lmstudio",
litellm: "litellm",
glama: "glama",
"nano-gpt": null,
"nano-gpt": "nano-gpt",
unbound: "unbound",
requesty: "requesty",
deepinfra: "deepinfra",
Expand Down Expand Up @@ -461,6 +462,8 @@ export function getModelIdKey(provider: ProviderName): string {
return "vercelAiGatewayModelId"
case "ovhcloud":
return "ovhCloudAiEndpointsModelId"
case "nano-gpt":
return "nanoGptModelId"
default:
return "apiModelId"
}
Expand Down