mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
fix: include API key in Ollama /api/tags requests (#7903)
Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
parent
80d82e65f0
commit
b576dd9008
6 changed files with 96 additions and 14 deletions
|
|
@ -108,10 +108,10 @@ describe("Ollama Fetcher", () => {
|
|||
const result = await getOllamaModels(baseUrl)
|
||||
|
||||
expect(mockedAxios.get).toHaveBeenCalledTimes(1)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`, { headers: {} })
|
||||
|
||||
expect(mockedAxios.post).toHaveBeenCalledTimes(1)
|
||||
expect(mockedAxios.post).toHaveBeenCalledWith(`${baseUrl}/api/show`, { model: modelName })
|
||||
expect(mockedAxios.post).toHaveBeenCalledWith(`${baseUrl}/api/show`, { model: modelName }, { headers: {} })
|
||||
|
||||
expect(typeof result).toBe("object")
|
||||
expect(result).not.toBeInstanceOf(Array)
|
||||
|
|
@ -130,7 +130,7 @@ describe("Ollama Fetcher", () => {
|
|||
const result = await getOllamaModels(baseUrl)
|
||||
|
||||
expect(mockedAxios.get).toHaveBeenCalledTimes(1)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`, { headers: {} })
|
||||
expect(mockedAxios.post).not.toHaveBeenCalled()
|
||||
expect(result).toEqual({})
|
||||
})
|
||||
|
|
@ -146,7 +146,7 @@ describe("Ollama Fetcher", () => {
|
|||
const result = await getOllamaModels(baseUrl)
|
||||
|
||||
expect(mockedAxios.get).toHaveBeenCalledTimes(1)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`, { headers: {} })
|
||||
expect(mockedAxios.post).not.toHaveBeenCalled()
|
||||
expect(consoleInfoSpy).toHaveBeenCalledWith(`Failed connecting to Ollama at ${baseUrl}`)
|
||||
expect(result).toEqual({})
|
||||
|
|
@ -204,10 +204,10 @@ describe("Ollama Fetcher", () => {
|
|||
const result = await getOllamaModels(baseUrl)
|
||||
|
||||
expect(mockedAxios.get).toHaveBeenCalledTimes(1)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`, { headers: {} })
|
||||
|
||||
expect(mockedAxios.post).toHaveBeenCalledTimes(1)
|
||||
expect(mockedAxios.post).toHaveBeenCalledWith(`${baseUrl}/api/show`, { model: modelName })
|
||||
expect(mockedAxios.post).toHaveBeenCalledWith(`${baseUrl}/api/show`, { model: modelName }, { headers: {} })
|
||||
|
||||
expect(typeof result).toBe("object")
|
||||
expect(result).not.toBeInstanceOf(Array)
|
||||
|
|
@ -217,5 +217,73 @@ describe("Ollama Fetcher", () => {
|
|||
// Verify the model was parsed correctly despite null families
|
||||
expect(result[modelName].description).toBe("Family: llama, Context: 4096, Size: 23.6B")
|
||||
})
|
||||
|
||||
it("should include Authorization header when API key is provided", async () => {
|
||||
const baseUrl = "http://localhost:11434"
|
||||
const apiKey = "test-api-key-123"
|
||||
const modelName = "test-model:latest"
|
||||
|
||||
const mockApiTagsResponse = {
|
||||
models: [
|
||||
{
|
||||
name: modelName,
|
||||
model: modelName,
|
||||
modified_at: "2025-06-03T09:23:22.610222878-04:00",
|
||||
size: 14333928010,
|
||||
digest: "6a5f0c01d2c96c687d79e32fdd25b87087feb376bf9838f854d10be8cf3c10a5",
|
||||
details: {
|
||||
family: "llama",
|
||||
families: ["llama"],
|
||||
format: "gguf",
|
||||
parameter_size: "23.6B",
|
||||
parent_model: "",
|
||||
quantization_level: "Q4_K_M",
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
const mockApiShowResponse = {
|
||||
license: "Mock License",
|
||||
modelfile: "FROM /path/to/blob\nTEMPLATE {{ .Prompt }}",
|
||||
parameters: "num_ctx 4096\nstop_token <eos>",
|
||||
template: "{{ .System }}USER: {{ .Prompt }}ASSISTANT:",
|
||||
modified_at: "2025-06-03T09:23:22.610222878-04:00",
|
||||
details: {
|
||||
parent_model: "",
|
||||
format: "gguf",
|
||||
family: "llama",
|
||||
families: ["llama"],
|
||||
parameter_size: "23.6B",
|
||||
quantization_level: "Q4_K_M",
|
||||
},
|
||||
model_info: {
|
||||
"ollama.context_length": 4096,
|
||||
"some.other.info": "value",
|
||||
},
|
||||
capabilities: ["completion"],
|
||||
}
|
||||
|
||||
mockedAxios.get.mockResolvedValueOnce({ data: mockApiTagsResponse })
|
||||
mockedAxios.post.mockResolvedValueOnce({ data: mockApiShowResponse })
|
||||
|
||||
const result = await getOllamaModels(baseUrl, apiKey)
|
||||
|
||||
const expectedHeaders = { Authorization: `Bearer ${apiKey}` }
|
||||
|
||||
expect(mockedAxios.get).toHaveBeenCalledTimes(1)
|
||||
expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`, { headers: expectedHeaders })
|
||||
|
||||
expect(mockedAxios.post).toHaveBeenCalledTimes(1)
|
||||
expect(mockedAxios.post).toHaveBeenCalledWith(
|
||||
`${baseUrl}/api/show`,
|
||||
{ model: modelName },
|
||||
{ headers: expectedHeaders },
|
||||
)
|
||||
|
||||
expect(typeof result).toBe("object")
|
||||
expect(result).not.toBeInstanceOf(Array)
|
||||
expect(Object.keys(result).length).toBe(1)
|
||||
expect(result[modelName]).toBeDefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ export const getModels = async (options: GetModelsOptions): Promise<ModelRecord>
|
|||
models = await getLiteLLMModels(options.apiKey, options.baseUrl)
|
||||
break
|
||||
case "ollama":
|
||||
models = await getOllamaModels(options.baseUrl)
|
||||
models = await getOllamaModels(options.baseUrl, options.apiKey)
|
||||
break
|
||||
case "lmstudio":
|
||||
models = await getLMStudioModels(options.baseUrl)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,10 @@ export const parseOllamaModel = (rawModel: OllamaModelInfoResponse): ModelInfo =
|
|||
return modelInfo
|
||||
}
|
||||
|
||||
export async function getOllamaModels(baseUrl = "http://localhost:11434"): Promise<Record<string, ModelInfo>> {
|
||||
export async function getOllamaModels(
|
||||
baseUrl = "http://localhost:11434",
|
||||
apiKey?: string,
|
||||
): Promise<Record<string, ModelInfo>> {
|
||||
const models: Record<string, ModelInfo> = {}
|
||||
|
||||
// clearing the input can leave an empty string; use the default in that case
|
||||
|
|
@ -65,7 +68,13 @@ export async function getOllamaModels(baseUrl = "http://localhost:11434"): Promi
|
|||
return models
|
||||
}
|
||||
|
||||
const response = await axios.get<OllamaModelsResponse>(`${baseUrl}/api/tags`)
|
||||
// Prepare headers with optional API key
|
||||
const headers: Record<string, string> = {}
|
||||
if (apiKey) {
|
||||
headers["Authorization"] = `Bearer ${apiKey}`
|
||||
}
|
||||
|
||||
const response = await axios.get<OllamaModelsResponse>(`${baseUrl}/api/tags`, { headers })
|
||||
const parsedResponse = OllamaModelsResponseSchema.safeParse(response.data)
|
||||
let modelInfoPromises = []
|
||||
|
||||
|
|
@ -73,9 +82,13 @@ export async function getOllamaModels(baseUrl = "http://localhost:11434"): Promi
|
|||
for (const ollamaModel of parsedResponse.data.models) {
|
||||
modelInfoPromises.push(
|
||||
axios
|
||||
.post<OllamaModelInfoResponse>(`${baseUrl}/api/show`, {
|
||||
model: ollamaModel.model,
|
||||
})
|
||||
.post<OllamaModelInfoResponse>(
|
||||
`${baseUrl}/api/show`,
|
||||
{
|
||||
model: ollamaModel.model,
|
||||
},
|
||||
{ headers },
|
||||
)
|
||||
.then((ollamaModelInfo) => {
|
||||
models[ollamaModel.name] = parseOllamaModel(ollamaModelInfo.data)
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ export class NativeOllamaHandler extends BaseProvider implements SingleCompletio
|
|||
}
|
||||
|
||||
async fetchModel() {
|
||||
this.models = await getOllamaModels(this.options.ollamaBaseUrl)
|
||||
this.models = await getOllamaModels(this.options.ollamaBaseUrl, this.options.ollamaApiKey)
|
||||
return this.getModel()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -887,6 +887,7 @@ export const webviewMessageHandler = async (
|
|||
const ollamaModels = await getModels({
|
||||
provider: "ollama",
|
||||
baseUrl: ollamaApiConfig.ollamaBaseUrl,
|
||||
apiKey: ollamaApiConfig.ollamaApiKey,
|
||||
})
|
||||
|
||||
if (Object.keys(ollamaModels).length > 0) {
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ export type GetModelsOptions =
|
|||
| { provider: "requesty"; apiKey?: string; baseUrl?: string }
|
||||
| { provider: "unbound"; apiKey?: string }
|
||||
| { provider: "litellm"; apiKey: string; baseUrl: string }
|
||||
| { provider: "ollama"; baseUrl?: string }
|
||||
| { provider: "ollama"; baseUrl?: string; apiKey?: string }
|
||||
| { provider: "lmstudio"; baseUrl?: string }
|
||||
| { provider: "deepinfra"; apiKey?: string; baseUrl?: string }
|
||||
| { provider: "io-intelligence"; apiKey: string }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue