From 69134c59035ca28f724d5e9f2677936892c45d77 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sat, 20 Dec 2025 17:53:34 +0000 Subject: [PATCH 1/3] feat: add native tool calling support to HuggingFace provider --- src/api/providers/fetchers/huggingface.ts | 5 ++++ src/api/providers/huggingface.ts | 36 +++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/api/providers/fetchers/huggingface.ts b/src/api/providers/fetchers/huggingface.ts index 1a7a995bc6e..20875461744 100644 --- a/src/api/providers/fetchers/huggingface.ts +++ b/src/api/providers/fetchers/huggingface.ts @@ -87,6 +87,9 @@ function parseHuggingFaceModel(model: HuggingFaceModel, provider?: HuggingFacePr const pricing = provider?.pricing || model.providers.find((p) => p.pricing)?.pricing + // Check if any provider supports tools + const supportsTools = provider?.supports_tools ?? model.providers.some((p) => p.supports_tools === true) + // Include provider name in description if specific provider is given. const description = provider ? `${model.id} via ${provider.provider}` : `${model.id} via HuggingFace` @@ -95,6 +98,8 @@ function parseHuggingFaceModel(model: HuggingFaceModel, provider?: HuggingFacePr contextWindow: contextLength, supportsImages: false, // HuggingFace API doesn't provide this info yet. supportsPromptCache: false, + supportsNativeTools: supportsTools, + defaultToolProtocol: supportsTools ? ("native" as const) : undefined, inputPrice: pricing?.input, outputPrice: pricing?.output, description, diff --git a/src/api/providers/huggingface.ts b/src/api/providers/huggingface.ts index 7b62046b99e..70f2e1adf09 100644 --- a/src/api/providers/huggingface.ts +++ b/src/api/providers/huggingface.ts @@ -9,6 +9,9 @@ import { DEFAULT_HEADERS } from "./constants" import { BaseProvider } from "./base-provider" import { getHuggingFaceModels, getCachedHuggingFaceModels } from "./fetchers/huggingface" import { handleOpenAIError } from "./utils/openai-error-handler" +import { resolveToolProtocol } from "../../utils/resolveToolProtocol" +import { TOOL_PROTOCOL } from "@roo-code/types" +import { NativeToolCallParser } from "../../core/assistant-message/NativeToolCallParser" export class HuggingFaceHandler extends BaseProvider implements SingleCompletionHandler { private client: OpenAI @@ -53,12 +56,23 @@ export class HuggingFaceHandler extends BaseProvider implements SingleCompletion const modelId = this.options.huggingFaceModelId || "meta-llama/Llama-3.3-70B-Instruct" const temperature = this.options.modelTemperature ?? 0.7 + // Get model info to check tool support + const model = this.getModel() + const toolProtocol = resolveToolProtocol(this.options, model.info, metadata?.toolProtocol) + + // Check if model supports native tools and tools are provided with native protocol + const supportsNativeTools = model.info.supportsNativeTools ?? false + const useNativeTools = + supportsNativeTools && metadata?.tools && metadata.tools.length > 0 && toolProtocol === TOOL_PROTOCOL.NATIVE + const params: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = { model: modelId, temperature, messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)], stream: true, stream_options: { include_usage: true }, + ...(useNativeTools && { tools: this.convertToolsForOpenAI(metadata.tools) }), + ...(useNativeTools && metadata.tool_choice && { tool_choice: metadata.tool_choice }), } // Add max_tokens if specified @@ -75,6 +89,7 @@ export class HuggingFaceHandler extends BaseProvider implements SingleCompletion for await (const chunk of stream) { const delta = chunk.choices[0]?.delta + const finishReason = chunk.choices[0]?.finish_reason if (delta?.content) { yield { @@ -83,6 +98,27 @@ export class HuggingFaceHandler extends BaseProvider implements SingleCompletion } } + // Handle tool calls in stream - emit partial chunks for NativeToolCallParser + if (delta?.tool_calls) { + for (const toolCall of delta.tool_calls) { + yield { + type: "tool_call_partial", + index: toolCall.index, + id: toolCall.id, + name: toolCall.function?.name, + arguments: toolCall.function?.arguments, + } + } + } + + // Process finish_reason to emit tool_call_end events + if (finishReason) { + const endEvents = NativeToolCallParser.processFinishReason(finishReason) + for (const event of endEvents) { + yield event + } + } + if (chunk.usage) { yield { type: "usage", From 474e3a92b35af78476ca61715d2a8113ce2b31a5 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sat, 20 Dec 2025 17:58:18 +0000 Subject: [PATCH 2/3] refactor: remove unnecessary as const assertion --- src/api/providers/fetchers/huggingface.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/api/providers/fetchers/huggingface.ts b/src/api/providers/fetchers/huggingface.ts index 20875461744..d31ebcf2f0f 100644 --- a/src/api/providers/fetchers/huggingface.ts +++ b/src/api/providers/fetchers/huggingface.ts @@ -99,13 +99,12 @@ function parseHuggingFaceModel(model: HuggingFaceModel, provider?: HuggingFacePr supportsImages: false, // HuggingFace API doesn't provide this info yet. supportsPromptCache: false, supportsNativeTools: supportsTools, - defaultToolProtocol: supportsTools ? ("native" as const) : undefined, + defaultToolProtocol: supportsTools ? "native" : undefined, inputPrice: pricing?.input, outputPrice: pricing?.output, description, } } - /** * Fetches available models from HuggingFace * From 6f73c2e692dbdf25c2f81122abbcd4a7950d8986 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sat, 20 Dec 2025 18:02:44 +0000 Subject: [PATCH 3/3] refactor: enable native tool calling for all HuggingFace models by default --- src/api/providers/fetchers/huggingface.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/api/providers/fetchers/huggingface.ts b/src/api/providers/fetchers/huggingface.ts index d31ebcf2f0f..bb4e1e0b4d3 100644 --- a/src/api/providers/fetchers/huggingface.ts +++ b/src/api/providers/fetchers/huggingface.ts @@ -87,9 +87,6 @@ function parseHuggingFaceModel(model: HuggingFaceModel, provider?: HuggingFacePr const pricing = provider?.pricing || model.providers.find((p) => p.pricing)?.pricing - // Check if any provider supports tools - const supportsTools = provider?.supports_tools ?? model.providers.some((p) => p.supports_tools === true) - // Include provider name in description if specific provider is given. const description = provider ? `${model.id} via ${provider.provider}` : `${model.id} via HuggingFace` @@ -98,8 +95,8 @@ function parseHuggingFaceModel(model: HuggingFaceModel, provider?: HuggingFacePr contextWindow: contextLength, supportsImages: false, // HuggingFace API doesn't provide this info yet. supportsPromptCache: false, - supportsNativeTools: supportsTools, - defaultToolProtocol: supportsTools ? "native" : undefined, + supportsNativeTools: true, + defaultToolProtocol: "native", inputPrice: pricing?.input, outputPrice: pricing?.output, description,