Skip to content

Commit f279893

Browse files
author
false
committed
feat: huggingface provider added
1 parent e407436 commit f279893

File tree

27 files changed

+4785
-105
lines changed

27 files changed

+4785
-105
lines changed

.github/workflows/pr-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ jobs:
115115
COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
116116
VERTEX_CREDENTIALS: ${{ secrets.VERTEX_CREDENTIALS }}
117117
VERTEX_PROJECT_ID: ${{ secrets.VERTEX_PROJECT_ID }}
118+
HUGGING_FACE_API_KEY: ${{ secrets.HUGGING_FACE_API_KEY }}
118119
run: |
119120
echo "Running tests for PR #${{ github.event.pull_request.number || 'manual run' }}"
120121
./.github/workflows/scripts/run-tests.sh

.github/workflows/release-pipeline.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ jobs:
115115
VERTEX_CREDENTIALS: ${{ secrets.VERTEX_CREDENTIALS }}
116116
VERTEX_PROJECT_ID: ${{ secrets.VERTEX_PROJECT_ID }}
117117
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
118+
HUGGING_FACE_API_KEY: ${{ secrets.HUGGING_FACE_API_KEY }}
118119
run: ./.github/workflows/scripts/release-core.sh "${{ needs.detect-changes.outputs.core-version }}"
119120

120121
framework-release:
@@ -187,6 +188,7 @@ jobs:
187188
VERTEX_CREDENTIALS: ${{ secrets.VERTEX_CREDENTIALS }}
188189
VERTEX_PROJECT_ID: ${{ secrets.VERTEX_PROJECT_ID }}
189190
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
191+
HUGGING_FACE_API_KEY: ${{ secrets.HUGGING_FACE_API_KEY }}
190192
run: ./.github/workflows/scripts/release-framework.sh "${{ needs.detect-changes.outputs.framework-version }}"
191193

192194
plugins-release:
@@ -263,6 +265,7 @@ jobs:
263265
VERTEX_CREDENTIALS: ${{ secrets.VERTEX_CREDENTIALS }}
264266
VERTEX_PROJECT_ID: ${{ secrets.VERTEX_PROJECT_ID }}
265267
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
268+
HUGGING_FACE_API_KEY: ${{ secrets.HUGGING_FACE_API_KEY }}
266269
run: ./.github/workflows/scripts/release-all-plugins.sh '${{ needs.detect-changes.outputs.changed-plugins }}'
267270

268271
bifrost-http-release:
@@ -351,6 +354,7 @@ jobs:
351354
VERTEX_CREDENTIALS: ${{ secrets.VERTEX_CREDENTIALS }}
352355
VERTEX_PROJECT_ID: ${{ secrets.VERTEX_PROJECT_ID }}
353356
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
357+
HUGGING_FACE_API_KEY: ${{ secrets.HUGGING_FACE_API_KEY }}
354358
run: ./.github/workflows/scripts/release-bifrost-http.sh "${{ needs.detect-changes.outputs.transport-version }}"
355359

356360
# Docker build amd64

Makefile

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,22 @@ TEST_REPORTS_DIR ?= test-reports
1111
GOTESTSUM_FORMAT ?= testname
1212
VERSION ?= dev-build
1313
LOCAL ?=
14-
DEBUG ?=
14+
15+
# Detect where 'go install' will place binaries. Prefer GOBIN, then GOPATH/bin, then default to $(shell go env GOBIN) or $(shell go env GOPATH)/bin
16+
# Set AIR_BIN to that path plus '/air' so make can invoke it directly without relying on PATH.
17+
GOBIN ?= $(shell go env GOBIN)
18+
GOPATH ?= $(shell go env GOPATH)
19+
DEFAULT_GOBIN := $(if $(strip $(GOBIN)),$(GOBIN),$(if $(strip $(GOPATH)),$(GOPATH)/bin,))
20+
AIR_BIN ?= $(if $(strip $(DEFAULT_GOBIN)),$(DEFAULT_GOBIN)/air,air)
21+
GOTESTSUM_BIN := $(if $(strip $(DEFAULT_GOBIN)),$(DEFAULT_GOBIN)/gotestsum,$(shell which gotestsum 2>/dev/null || echo gotestsum))
1522

1623
# Colors for output
17-
RED=\033[0;31m
18-
GREEN=\033[0;32m
19-
YELLOW=\033[1;33m
20-
BLUE=\033[0;34m
21-
CYAN=\033[0;36m
22-
NC=\033[0m # No Color
24+
RED=$(shell printf '\033[0;31m')
25+
GREEN=$(shell printf '\033[0;32m')
26+
YELLOW=$(shell printf '\033[1;33m')
27+
BLUE=$(shell printf '\033[0;34m')
28+
CYAN=$(shell printf '\033[0;36m')
29+
NC=$(shell printf '\033[0m')
2330

2431
# Include deployment recipes
2532
include recipes/fly.mk
@@ -56,24 +63,54 @@ cleanup-enterprise: ## Clean up enterprise directories if present
5663
@echo "$(GREEN)Enterprise cleaned up$(NC)"
5764

5865
install-ui: cleanup-enterprise
66+
# Do not run install-ui as root on developer machines - this causes global npm installs to fail (Nix, etc.)
67+
@if [ -z "$$CI" ] && [ -z "$$GITHUB_ACTIONS" ] && [ "$$(id -u)" -eq 0 ]; then \
68+
echo "$(RED)Error: Running 'make' as root is not supported for local development. Run as your user (without sudo).$(NC)"; \
69+
exit 1; \
70+
fi
5971
@which node > /dev/null || (echo "$(RED)Error: Node.js is not installed. Please install Node.js first.$(NC)" && exit 1)
6072
@which npm > /dev/null || (echo "$(RED)Error: npm is not installed. Please install npm first.$(NC)" && exit 1)
6173
@echo "$(GREEN)Node.js and npm are installed$(NC)"
6274
@cd ui && npm install
63-
@which next > /dev/null || (echo "$(YELLOW)Installing nextjs...$(NC)" && npm install -g next)
75+
# Prefer a local next installation (works on systems without global npm dirs, e.g. Nix)
76+
@cd ui && \
77+
if [ -x "./node_modules/.bin/next" ]; then \
78+
echo "$(GREEN)next is available locally in ui/node_modules/.bin$(NC)"; \
79+
elif which npx > /dev/null 2>&1; then \
80+
echo "$(YELLOW)Installing next locally using npm...$(NC)"; \
81+
npm --prefix . install next || true; \
82+
else \
83+
echo "$(YELLOW)npx not found and local next missing; attempting global install (may fail on Nix)...$(NC)"; \
84+
npm install -g next || true; \
85+
fi
6486
@echo "$(GREEN)UI deps are in sync$(NC)"
6587

6688
install-air: ## Install air for hot reloading (if not already installed)
67-
@which air > /dev/null || (echo "$(YELLOW)Installing air for hot reloading...$(NC)" && go install github.com/air-verse/air@latest)
68-
@echo "$(GREEN)Air is ready$(NC)"
69-
70-
install-delve: ## Install delve for debugging (if not already installed)
71-
@which dlv > /dev/null || (echo "$(YELLOW)Installing delve for debugging...$(NC)" && go install github.com/go-delve/delve/cmd/dlv@latest)
72-
@echo "$(GREEN)Delve is ready$(NC)"
89+
@echo "$(YELLOW)Checking for air binary...$(NC)"
90+
@if [ -x "$(AIR_BIN)" ]; then \
91+
echo "$(GREEN)air is available at: $(AIR_BIN)$(NC)"; \
92+
else \
93+
echo "$(YELLOW)Installing air for hot reloading...$(NC)"; \
94+
go install github.com/air-verse/air@latest; \
95+
INSTALLED=$$(if [ -n "$(GOBIN)" ]; then echo "$(GOBIN)/air"; elif [ -n "$(GOPATH)" ]; then echo "$(GOPATH)/bin/air"; else echo "$$(go env GOBIN)/air"; fi); \
96+
echo "$(GREEN)air installed (expected path: $$INSTALLED)$(NC)"; \
97+
if ! which $$INSTALLED >/dev/null 2>&1 && [ ! -x "$$INSTALLED" ]; then \
98+
echo "$(YELLOW)Note: the installed air binary may not be on your PATH. Add its directory to PATH to run 'make dev' without errors.$(NC)"; \
99+
fi; \
100+
fi
73101

74102
install-gotestsum: ## Install gotestsum for test reporting (if not already installed)
75-
@which gotestsum > /dev/null || (echo "$(YELLOW)Installing gotestsum for test reporting...$(NC)" && go install gotest.tools/gotestsum@latest)
76-
@echo "$(GREEN)gotestsum is ready$(NC)"
103+
@if [ -x "$(GOTESTSUM_BIN)" ] || which $(GOTESTSUM_BIN) > /dev/null 2>&1; then \
104+
echo "$(GREEN)gotestsum is available at: $(GOTESTSUM_BIN)$(NC)"; \
105+
else \
106+
echo "$(YELLOW)Installing gotestsum for test reporting...$(NC)"; \
107+
go install gotest.tools/gotestsum@latest; \
108+
INSTALLED=$$(if [ -n "$(GOBIN)" ]; then echo "$(GOBIN)/gotestsum"; elif [ -n "$(GOPATH)" ]; then echo "$(GOPATH)/bin/gotestsum"; else echo "$$(go env GOBIN)/gotestsum"; fi); \
109+
echo "$(GREEN)gotestsum installed (expected path: $$INSTALLED)$(NC)"; \
110+
if ! which $$INSTALLED >/dev/null 2>&1 && [ ! -x "$$INSTALLED" ]; then \
111+
echo "$(YELLOW)Note: the installed gotestsum binary may not be on your PATH. Add its directory to PATH to run 'make test' without errors or run tests via $(GOTESTSUM_BIN)$(NC)"; \
112+
fi; \
113+
fi
77114

78115
install-junit-viewer: ## Install junit-viewer for HTML report generation (if not already installed)
79116
@if [ -z "$$CI" ] && [ -z "$$GITHUB_ACTIONS" ] && [ -z "$$GITLAB_CI" ] && [ -z "$$CIRCLECI" ] && [ -z "$$JENKINS_HOME" ]; then \
@@ -115,15 +152,15 @@ dev: install-ui install-air setup-workspace $(if $(DEBUG),install-delve) ## Star
115152
if [ -n "$(DEBUG)" ]; then \
116153
echo "$(CYAN)Starting with air + delve debugger on port 2345...$(NC)"; \
117154
echo "$(YELLOW)Attach your debugger to localhost:2345$(NC)"; \
118-
cd transports/bifrost-http && BIFROST_UI_DEV=true air -c .air.debug.toml -- \
119-
-host "$(HOST)" \
120-
-port "$(PORT)" \
121-
-log-style "$(LOG_STYLE)" \
122-
-log-level "$(LOG_LEVEL)" \
123-
$(if $(PROMETHEUS_LABELS),-prometheus-labels "$(PROMETHEUS_LABELS)") \
155+
cd transports/bifrost-http && BIFROST_UI_DEV=true $(AIR_BIN) -c .air.debug.toml -- \
156+
-host "$(HOST)" \
157+
-port "$(PORT)" \
158+
-log-style "$(LOG_STYLE)" \
159+
-log-level "$(LOG_LEVEL)" \
160+
$(if $(PROMETHEUS_LABELS),-prometheus-labels "$(PROMETHEUS_LABELS)") \
124161
$(if $(APP_DIR),-app-dir "$(APP_DIR)"); \
125162
else \
126-
cd transports/bifrost-http && BIFROST_UI_DEV=true air -c .air.toml -- \
163+
cd transports/bifrost-http && BIFROST_UI_DEV=true $(AIR_BIN) -c .air.toml -- \
127164
-host "$(HOST)" \
128165
-port "$(PORT)" \
129166
-log-style "$(LOG_STYLE)" \
@@ -309,7 +346,7 @@ generate-html-reports: ## Convert existing XML reports to HTML
309346
test: install-gotestsum ## Run tests for bifrost-http
310347
@echo "$(GREEN)Running bifrost-http tests...$(NC)"
311348
@mkdir -p $(TEST_REPORTS_DIR)
312-
@cd transports/bifrost-http && GOWORK=off gotestsum \
349+
@cd transports/bifrost-http && GOWORK=off $(GOTESTSUM_BIN) \
313350
--format=$(GOTESTSUM_FORMAT) \
314351
--junitfile=../../$(TEST_REPORTS_DIR)/bifrost-http.xml \
315352
-- -v ./...
@@ -361,7 +398,7 @@ test-core: install-gotestsum ## Run core tests (Usage: make test-core PROVIDER=o
361398
CLEAN_TESTCASE=$$(echo "$$CLEAN_TESTCASE" | sed 's|^Test[A-Z][A-Za-z]*/[A-Z][A-Za-z]*Tests/||'); \
362399
echo "$(CYAN)Running Test$${PROVIDER_TEST_NAME}/$${PROVIDER_TEST_NAME}Tests/$$CLEAN_TESTCASE...$(NC)"; \
363400
REPORT_FILE="$(TEST_REPORTS_DIR)/core-$(PROVIDER)-$$(echo $$CLEAN_TESTCASE | sed 's|/|_|g').xml"; \
364-
cd core/providers/$(PROVIDER) && GOWORK=off gotestsum \
401+
cd core/providers/$(PROVIDER) && GOWORK=off $(GOTESTSUM_BIN) \
365402
--format=$(GOTESTSUM_FORMAT) \
366403
--junitfile=../../../$$REPORT_FILE \
367404
-- -v -run "^Test$${PROVIDER_TEST_NAME}$$/.*Tests/$$CLEAN_TESTCASE$$" || TEST_FAILED=1; \
@@ -385,7 +422,7 @@ test-core: install-gotestsum ## Run core tests (Usage: make test-core PROVIDER=o
385422
else \
386423
echo "$(CYAN)Running Test$${PROVIDER_TEST_NAME}...$(NC)"; \
387424
REPORT_FILE="$(TEST_REPORTS_DIR)/core-$(PROVIDER).xml"; \
388-
cd core/providers/$(PROVIDER) && GOWORK=off gotestsum \
425+
cd core/providers/$(PROVIDER) && GOWORK=off $(GOTESTSUM_BIN) \
389426
--format=$(GOTESTSUM_FORMAT) \
390427
--junitfile=../../../$$REPORT_FILE \
391428
-- -v -run "^Test$${PROVIDER_TEST_NAME}$$" || TEST_FAILED=1; \
@@ -414,7 +451,7 @@ test-core: install-gotestsum ## Run core tests (Usage: make test-core PROVIDER=o
414451
exit 1; \
415452
fi; \
416453
REPORT_FILE="$(TEST_REPORTS_DIR)/core-all.xml"; \
417-
cd core && GOWORK=off gotestsum \
454+
cd core && GOWORK=off $(GOTESTSUM_BIN) \
418455
--format=$(GOTESTSUM_FORMAT) \
419456
--junitfile=../$$REPORT_FILE \
420457
-- -v ./providers/... || TEST_FAILED=1; \
@@ -508,7 +545,7 @@ test-plugins: install-gotestsum ## Run plugin tests
508545
for dir in $$(find . -name "*_test.go" -exec dirname {} \; | sort -u); do \
509546
plugin_name=$$(echo $$dir | sed 's|^\./||' | sed 's|/|-|g'); \
510547
echo "Testing $$dir..."; \
511-
cd $$dir && gotestsum \
548+
cd $$dir && $(GOTESTSUM_BIN) \
512549
--format=$(GOTESTSUM_FORMAT) \
513550
--junitfile=../../$(TEST_REPORTS_DIR)/plugin-$$plugin_name.xml \
514551
-- -v ./... && cd - > /dev/null; \

core/bifrost.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/maximhq/bifrost/core/providers/elevenlabs"
2424
"github.com/maximhq/bifrost/core/providers/gemini"
2525
"github.com/maximhq/bifrost/core/providers/groq"
26+
"github.com/maximhq/bifrost/core/providers/huggingface"
2627
"github.com/maximhq/bifrost/core/providers/mistral"
2728
"github.com/maximhq/bifrost/core/providers/ollama"
2829
"github.com/maximhq/bifrost/core/providers/openai"
@@ -1323,6 +1324,8 @@ func (bifrost *Bifrost) createBaseProvider(providerKey schemas.ModelProvider, co
13231324
return openrouter.NewOpenRouterProvider(config, bifrost.logger), nil
13241325
case schemas.Elevenlabs:
13251326
return elevenlabs.NewElevenlabsProvider(config, bifrost.logger), nil
1327+
case schemas.HuggingFace:
1328+
return huggingface.NewHuggingFaceProvider(config, bifrost.logger), nil
13261329
default:
13271330
return nil, fmt.Errorf("unsupported provider: %s", targetProviderKey)
13281331
}

core/internal/testutil/account.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ func (account *ComprehensiveTestAccount) GetConfiguredProviders() ([]schemas.Mod
9393
schemas.Cerebras,
9494
schemas.Gemini,
9595
schemas.OpenRouter,
96+
schemas.HuggingFace,
9697
ProviderOpenAICustom,
9798
}, nil
9899
}
@@ -255,6 +256,14 @@ func (account *ComprehensiveTestAccount) GetKeysForProvider(ctx *context.Context
255256
Weight: 1.0,
256257
},
257258
}, nil
259+
case schemas.HuggingFace:
260+
return []schemas.Key{
261+
{
262+
Value: os.Getenv("HUGGING_FACE_API_KEY"),
263+
Models: []string{},
264+
Weight: 1.0,
265+
},
266+
}, nil
258267
default:
259268
return nil, fmt.Errorf("unsupported provider: %s", providerKey)
260269
}
@@ -500,6 +509,19 @@ func (account *ComprehensiveTestAccount) GetConfigForProvider(providerKey schema
500509
BufferSize: 10,
501510
},
502511
}, nil
512+
case schemas.HuggingFace:
513+
return &schemas.ProviderConfig{
514+
NetworkConfig: schemas.NetworkConfig{
515+
DefaultRequestTimeoutInSeconds: 300,
516+
MaxRetries: 10, // HuggingFace can be variable
517+
RetryBackoffInitial: 2 * time.Second,
518+
RetryBackoffMax: 30 * time.Second,
519+
},
520+
ConcurrencyAndBufferSize: schemas.ConcurrencyAndBufferSize{
521+
Concurrency: Concurrency,
522+
BufferSize: 10,
523+
},
524+
}, nil
503525
default:
504526
return nil, fmt.Errorf("unsupported provider: %s", providerKey)
505527
}

core/internal/testutil/responses_stream.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ func RunResponsesStreamTest(t *testing.T, client *bifrost.Bifrost, ctx context.C
690690
}
691691

692692
// Safety check to prevent infinite loops
693-
if responseCount > 100 {
693+
if responseCount > 300 {
694694
goto lifecycleComplete
695695
}
696696

core/internal/testutil/scenarios/media/lion_base64.txt

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)