Skip to content

Commit 0f8fac9

Browse files
authored
fix: show tool protocol dropdown for LiteLLM provider (#10053)
1 parent ba7c553 commit 0f8fac9

File tree

2 files changed

+118
-2
lines changed

2 files changed

+118
-2
lines changed

webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
55
import { renderHook } from "@testing-library/react"
66
import type { Mock } from "vitest"
77

8-
import { ProviderSettings, ModelInfo, BEDROCK_1M_CONTEXT_MODEL_IDS } from "@roo-code/types"
8+
import { ProviderSettings, ModelInfo, BEDROCK_1M_CONTEXT_MODEL_IDS, litellmDefaultModelInfo } from "@roo-code/types"
99

1010
import { useSelectedModel } from "../useSelectedModel"
1111
import { useRouterModels } from "../useRouterModels"
@@ -540,4 +540,119 @@ describe("useSelectedModel", () => {
540540
expect(result.current.info?.contextWindow).toBe(200_000)
541541
})
542542
})
543+
544+
describe("litellm provider", () => {
545+
beforeEach(() => {
546+
mockUseOpenRouterModelProviders.mockReturnValue({
547+
data: {},
548+
isLoading: false,
549+
isError: false,
550+
} as any)
551+
})
552+
553+
it("should use litellmDefaultModelInfo as fallback when routerModels.litellm is empty", () => {
554+
mockUseRouterModels.mockReturnValue({
555+
data: {
556+
openrouter: {},
557+
requesty: {},
558+
unbound: {},
559+
litellm: {},
560+
"io-intelligence": {},
561+
},
562+
isLoading: false,
563+
isError: false,
564+
} as any)
565+
566+
const apiConfiguration: ProviderSettings = {
567+
apiProvider: "litellm",
568+
litellmModelId: "some-model",
569+
}
570+
571+
const wrapper = createWrapper()
572+
const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper })
573+
574+
expect(result.current.provider).toBe("litellm")
575+
// Should fall back to default model ID since "some-model" doesn't exist in empty litellm models
576+
expect(result.current.id).toBe("claude-3-7-sonnet-20250219")
577+
// Should use litellmDefaultModelInfo as fallback
578+
expect(result.current.info).toEqual(litellmDefaultModelInfo)
579+
expect(result.current.info?.supportsNativeTools).toBe(true)
580+
})
581+
582+
it("should use litellmDefaultModelInfo when selected model not found in routerModels", () => {
583+
mockUseRouterModels.mockReturnValue({
584+
data: {
585+
openrouter: {},
586+
requesty: {},
587+
unbound: {},
588+
litellm: {
589+
"existing-model": {
590+
maxTokens: 4096,
591+
contextWindow: 8192,
592+
supportsImages: false,
593+
supportsPromptCache: false,
594+
supportsNativeTools: true,
595+
},
596+
},
597+
"io-intelligence": {},
598+
},
599+
isLoading: false,
600+
isError: false,
601+
} as any)
602+
603+
const apiConfiguration: ProviderSettings = {
604+
apiProvider: "litellm",
605+
litellmModelId: "non-existing-model",
606+
}
607+
608+
const wrapper = createWrapper()
609+
const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper })
610+
611+
expect(result.current.provider).toBe("litellm")
612+
// Falls back to default model ID
613+
expect(result.current.id).toBe("claude-3-7-sonnet-20250219")
614+
// Should use litellmDefaultModelInfo as fallback since default model also not in router models
615+
expect(result.current.info).toEqual(litellmDefaultModelInfo)
616+
expect(result.current.info?.supportsNativeTools).toBe(true)
617+
})
618+
619+
it("should use model info from routerModels when model exists", () => {
620+
const customModelInfo: ModelInfo = {
621+
maxTokens: 16384,
622+
contextWindow: 128000,
623+
supportsImages: true,
624+
supportsPromptCache: true,
625+
supportsNativeTools: true,
626+
description: "Custom LiteLLM model",
627+
}
628+
629+
mockUseRouterModels.mockReturnValue({
630+
data: {
631+
openrouter: {},
632+
requesty: {},
633+
unbound: {},
634+
litellm: {
635+
"custom-model": customModelInfo,
636+
},
637+
"io-intelligence": {},
638+
},
639+
isLoading: false,
640+
isError: false,
641+
} as any)
642+
643+
const apiConfiguration: ProviderSettings = {
644+
apiProvider: "litellm",
645+
litellmModelId: "custom-model",
646+
}
647+
648+
const wrapper = createWrapper()
649+
const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper })
650+
651+
expect(result.current.provider).toBe("litellm")
652+
expect(result.current.id).toBe("custom-model")
653+
// Should use the model info from routerModels, not the fallback
654+
expect(result.current.info).toEqual(customModelInfo)
655+
expect(result.current.info?.supportsNativeTools).toBe(true)
656+
})
657+
})
543658
})

webview-ui/src/components/ui/hooks/useSelectedModel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
ioIntelligenceModels,
2828
basetenModels,
2929
qwenCodeModels,
30+
litellmDefaultModelInfo,
3031
BEDROCK_1M_CONTEXT_MODEL_IDS,
3132
isDynamicProvider,
3233
getProviderDefaultModelId,
@@ -164,7 +165,7 @@ function getSelectedModel({
164165
}
165166
case "litellm": {
166167
const id = getValidatedModelId(apiConfiguration.litellmModelId, routerModels.litellm, defaultModelId)
167-
const info = routerModels.litellm?.[id]
168+
const info = routerModels.litellm?.[id] ?? litellmDefaultModelInfo
168169
return { id, info }
169170
}
170171
case "xai": {

0 commit comments

Comments
 (0)