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
122 changes: 120 additions & 2 deletions .github/workflows/transport-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
tags:
- "core/v*" # Triggers dependency update
- "ui/v*" # Triggers UI update
- "transports/v*" # Triggers docker build (for manual tags)

concurrency:
Expand Down Expand Up @@ -121,9 +122,123 @@ jobs:
git tag ${{ steps.next_version.outputs.new_tag }}
git push origin ${{ steps.next_version.outputs.new_tag }}

update-transport-ui:
if: startsWith(github.ref, 'refs/tags/ui/v')
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
new_transport_tag: ${{ steps.next_version.outputs.new_tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.GH_TOKEN }}

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "18"
cache: "npm"
cache-dependency-path: ui/package-lock.json

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.24.1"

- name: Get and validate UI version from tag
id: get_version
run: |
TAG_NAME=${GITHUB_REF#refs/tags/ui/}

# Validate UI tag format
if ! echo "$TAG_NAME" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Error: Invalid UI tag format 'ui/$TAG_NAME'. Expected format: ui/vMAJOR.MINOR.PATCH"
exit 1
fi

echo "version=${TAG_NAME}" >> $GITHUB_OUTPUT
echo "UI version: ${TAG_NAME}"

- name: Configure Git
run: |
git config user.name "GitHub Actions Bot"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Build UI
working-directory: ui
run: |
echo "Installing UI dependencies..."
npm i
echo "Building UI..."
npm run build

- name: Update transports with new UI build
working-directory: transports
run: |
echo "Downloading Go dependencies..."
go mod download
echo "Building transports..."
go build ./...

- name: Get latest transport version and increment
id: next_version
run: |
# Get the latest transport tag (using transports/ prefix to match docker build)
LATEST_TAG=$(git tag -l 'transports/v*' | sort -V | tail -n 1)
if [ -z "$LATEST_TAG" ]; then
# If no transport tag exists, start with v0.1.0
NEW_TAG="transports/v0.1.0"
else
# Extract version numbers
VERSION=${LATEST_TAG#transports/v}

# Validate version format
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Error: Invalid tag format '$LATEST_TAG'. Expected format: transports/vMAJOR.MINOR.PATCH"
exit 1
fi

MAJOR=$(echo $VERSION | cut -d. -f1)
MINOR=$(echo $VERSION | cut -d. -f2)
PATCH=$(echo $VERSION | cut -d. -f3)

# Increment patch version
NEW_PATCH=$((PATCH + 1))
NEW_TAG="transports/v${MAJOR}.${MINOR}.${NEW_PATCH}"
fi

# Check if the new tag already exists
if git tag --list | grep -q "^${NEW_TAG}$"; then
echo "Error: Tag '$NEW_TAG' already exists!"
exit 1
fi

echo "new_tag=${NEW_TAG}" >> $GITHUB_OUTPUT
echo "New transport version will be: ${NEW_TAG}"

- name: Commit and push UI changes
run: |
git add .
if git diff --staged --quiet; then
echo "No changes to commit. UI build is already up to date."
else
git commit -m "chore: update transports with UI build from ${{ steps.get_version.outputs.version }}"
git push
fi

- name: Create and push transport tag
run: |
git tag ${{ steps.next_version.outputs.new_tag }}
git push origin ${{ steps.next_version.outputs.new_tag }}

build-and-push-docker:
if: always() && needs.update-transport-dependency.result != 'failure' && (startsWith(github.ref, 'refs/tags/transports/v') || needs.update-transport-dependency.result == 'success')
needs: [update-transport-dependency]
if: always() && (needs.update-transport-dependency.result != 'failure' && needs.update-transport-ui.result != 'failure') && (startsWith(github.ref, 'refs/tags/transports/v') || needs.update-transport-dependency.result == 'success' || needs.update-transport-ui.result == 'success')
needs: [update-transport-dependency, update-transport-ui]
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -138,6 +253,9 @@ jobs:
if [ "${{ needs.update-transport-dependency.outputs.new_transport_tag }}" != "" ]; then
# Use the tag created by dependency update
TAG="${{ needs.update-transport-dependency.outputs.new_transport_tag }}"
elif [ "${{ needs.update-transport-ui.outputs.new_transport_tag }}" != "" ]; then
# Use the tag created by UI update
TAG="${{ needs.update-transport-ui.outputs.new_transport_tag }}"
else
# Use the tag that triggered this workflow (manual tag)
TAG=${GITHUB_REF#refs/tags/}
Expand Down
175 changes: 175 additions & 0 deletions docs/contributing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Choose your adventure based on what you'd like to work on:
| **🌐 New Providers** | Advanced | 4-8 hours | [Provider Guide →](./provider.md) |
| **🔌 Plugin Development** | Intermediate | 2-6 hours | [Plugin Guide →](./plugin.md) |
| **🌍 HTTP Integrations** | Advanced | 6-12 hours | [Integration Guide →](./http-integration.md) |
| **🎨 UI Development** | Variable | 1-2 hours | [UI Guide →](#-ui-development) |
| **🐛 Bug Fixes** | Variable | 1-4 hours | [Bug Reports →](#-bug-reports) |
| **📝 Documentation** | Beginner | 30-120 min | [Documentation →](#-documentation) |

Expand Down Expand Up @@ -83,6 +84,13 @@ mindmap
Vercel AI SDK
Anthropic Claude API

UI & Frontend
Configuration Pages
Analytics Dashboard
Log Visualization
Plugin Management
Theme & Accessibility

Documentation
Tutorial Videos
Interactive Examples
Expand Down Expand Up @@ -121,6 +129,173 @@ mindmap
- **Examples:** OpenAI API compatibility, Anthropic integration, custom adapters
- **Impact:** Enable seamless migration from existing solutions

### **🎨 UI Development**

**Build and enhance the Bifrost web interface**

- **What:** Develop React components, pages, and user interfaces for Bifrost management
- **Skills:** React/Next.js, TypeScript, Tailwind CSS, UI/UX design
- **Examples:** Configuration panels, analytics dashboards, log viewers, plugin management
- **Impact:** Provide intuitive visual tools for Bifrost administration and monitoring

#### **🚀 UI Quick Start**

```bash
# Navigate to UI directory
cd ui

# Install dependencies
npm install

# Start development server
npm run dev

# Open http://localhost:3000 in your browser
```

#### **🛠️ Tech Stack**

- **Framework:** Next.js 15 with React 19
- **Language:** TypeScript for type safety
- **Styling:** Tailwind CSS with custom design system
- **Components:** Radix UI primitives for accessibility
- **Icons:** Lucide React icon library
- **Charts:** Recharts for data visualization
- **Code Editor:** Monaco Editor for configuration editing

#### **📁 UI Structure**

```
ui/
├── app/ # Next.js app router pages
│ ├── config/ # Provider & plugin configuration
│ ├── docs/ # Documentation viewer
│ ├── plugins/ # Plugin management
│ └── page.tsx # Dashboard homepage
├── components/ # React components
│ ├── config/ # Configuration UI components
│ ├── logs/ # Log viewing & analytics
│ ├── ui/ # Design system components
│ └── [shared components]
├── lib/ # Utilities and API clients
├── hooks/ # Custom React hooks
└── types/ # TypeScript type definitions
```

#### **🎯 UI Contribution Areas**

| **Area** | **Difficulty** | **Description** | **Skills Needed** |
| ------------------------- | -------------- | ----------------------------------------- | ----------------------------- |
| **🎨 Design System** | Beginner | Improve components, themes, accessibility | CSS, Design, Accessibility |
| **📊 Analytics & Charts** | Intermediate | Enhance data visualization and metrics | React, Data Viz, Statistics |
| **⚙️ Configuration UI** | Intermediate | Build provider/plugin setup interfaces | React, Forms, Validation |
| **📝 Log Management** | Advanced | Real-time log viewing and analysis | WebSockets, Performance, UX |
| **🔌 Plugin Interface** | Advanced | Dynamic plugin configuration and status | React, State Management, APIs |
| **🌙 Theming & UX** | Beginner | Dark/light themes, responsive design | CSS, Design, UX Principles |

#### **🧪 UI Testing Guidelines**

```bash
# Run linting
npm run lint

# Run type checking
npx tsc --noEmit

# Run component tests (when available)
npm test

# Build for production
npm run build
```

#### **🎨 UI Design Principles**

- **Accessibility First:** WCAG 2.1 AA compliance, keyboard navigation, screen reader support
- **Responsive Design:** Mobile-first approach with breakpoint considerations
- **Performance:** Optimized bundle size, lazy loading, efficient re-renders
- **Consistency:** Unified design system using Radix UI and Tailwind
- **User Experience:** Intuitive navigation, clear feedback, minimal cognitive load

#### **🔧 Common UI Tasks**

**Adding a New Page:**

```typescript
// app/new-feature/page.tsx
import { Metadata } from "next";

export const metadata: Metadata = {
title: "New Feature - Bifrost",
description: "Description of the new feature",
};

export default function NewFeaturePage() {
return (
<div className="container mx-auto p-6">
<h1 className="text-2xl font-bold">New Feature</h1>
{/* Your component JSX */}
</div>
);
}
```

**Creating a Component:**

```typescript
// components/ui/custom-component.tsx
import { cn } from "@/lib/utils";

interface CustomComponentProps {
className?: string;
children: React.ReactNode;
}

export function CustomComponent({ className, children }: CustomComponentProps) {
return <div className={cn("base-styles", className)}>{children}</div>;
}
```

**Adding API Integration:**

```typescript
// lib/api.ts
export async function fetchBifrostData(endpoint: string) {
const response = await fetch(`/api/bifrost/${endpoint}`);
if (!response.ok) throw new Error("Failed to fetch");
return response.json();
}
```

#### **📋 UI Contribution Checklist**

- [ ] **Code Quality**

- [ ] TypeScript types defined for all props and state
- [ ] ESLint and Prettier formatting passes
- [ ] No console.log statements in production code
- [ ] Error boundaries implemented for fault tolerance

- [ ] **Accessibility**

- [ ] Semantic HTML elements used appropriately
- [ ] ARIA labels and roles where needed
- [ ] Keyboard navigation functional
- [ ] Color contrast meets WCAG standards

- [ ] **Performance**

- [ ] Components use React.memo where appropriate
- [ ] Images optimized with Next.js Image component
- [ ] Bundle impact assessed (avoid heavy dependencies)
- [ ] Loading states implemented for async operations

- [ ] **Design Consistency**
- [ ] Tailwind CSS classes used consistently
- [ ] Radix UI components leveraged where possible
- [ ] Design system patterns followed
- [ ] Responsive design implemented

### **📋 [Code Conventions →](./code-conventions.md)**

**Follow Bifrost's development standards**
Expand Down
8 changes: 4 additions & 4 deletions transports/bifrost-http/handlers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ func NewConfigHandler(client *bifrost.Bifrost, logger schemas.Logger, store *lib
}

// RegisterRoutes registers the configuration-related routes.
// It adds the `PUT /config` endpoint.
// It adds the `PUT /api/config` endpoint.
func (h *ConfigHandler) RegisterRoutes(r *router.Router) {
r.GET("/config", h.GetConfig)
r.PUT("/config", h.handleUpdateConfig)
r.POST("/config/save", h.SaveConfig)
r.GET("/api/config", h.GetConfig)
r.PUT("/api/config", h.handleUpdateConfig)
r.POST("/api/config/save", h.SaveConfig)
}

// GetConfig handles GET /config - Get the current configuration
Expand Down
2 changes: 1 addition & 1 deletion transports/bifrost-http/handlers/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func NewLoggingHandler(logManager logging.LogManager, logger schemas.Logger) *Lo
// RegisterRoutes registers all logging-related routes
func (h *LoggingHandler) RegisterRoutes(r *router.Router) {
// Log retrieval with filtering, search, and pagination
r.GET("/v1/logs", h.GetLogs)
r.GET("/api/logs", h.GetLogs)
}

// GetLogs handles GET /v1/logs - Get logs with filtering, search, and pagination via query parameters
Expand Down
10 changes: 5 additions & 5 deletions transports/bifrost-http/handlers/mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ func NewMCPHandler(client *bifrost.Bifrost, logger schemas.Logger, store *lib.Co
func (h *MCPHandler) RegisterRoutes(r *router.Router) {
// MCP tool execution endpoint
r.POST("/v1/mcp/tool/execute", h.ExecuteTool)
r.GET("/mcp/clients", h.GetMCPClients)
r.POST("/mcp/client", h.AddMCPClient)
r.PUT("/mcp/client/{name}", h.EditMCPClientTools)
r.DELETE("/mcp/client/{name}", h.RemoveMCPClient)
r.POST("/mcp/client/{name}/reconnect", h.ReconnectMCPClient)
r.GET("/api/mcp/clients", h.GetMCPClients)
r.POST("/api/mcp/client", h.AddMCPClient)
r.PUT("/api/mcp/client/{name}", h.EditMCPClientTools)
r.DELETE("/api/mcp/client/{name}", h.RemoveMCPClient)
r.POST("/api/mcp/client/{name}/reconnect", h.ReconnectMCPClient)
}

// ExecuteTool handles POST /v1/mcp/tool/execute - Execute MCP tool
Expand Down
10 changes: 5 additions & 5 deletions transports/bifrost-http/handlers/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ type ErrorResponse struct {
// RegisterRoutes registers all provider management routes
func (h *ProviderHandler) RegisterRoutes(r *router.Router) {
// Provider CRUD operations
r.GET("/providers", h.ListProviders)
r.GET("/providers/{provider}", h.GetProvider)
r.POST("/providers", h.AddProvider)
r.PUT("/providers/{provider}", h.UpdateProvider)
r.DELETE("/providers/{provider}", h.DeleteProvider)
r.GET("/api/providers", h.ListProviders)
r.GET("/api/providers/{provider}", h.GetProvider)
r.POST("/api/providers", h.AddProvider)
r.PUT("/api/providers/{provider}", h.UpdateProvider)
r.DELETE("/api/providers/{provider}", h.DeleteProvider)
}

// ListProviders handles GET /providers - List all providers
Expand Down
Loading