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
4 changes: 3 additions & 1 deletion .github/workflows/transports-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ jobs:
# Strip 'transports/' prefix and add 'v' prefix for upload script
VERSION_ONLY="${{ steps.manage_versions.outputs.transport_version }}"
VERSION_ONLY=${VERSION_ONLY#transports/v}
node upload-builds.mjs v${VERSION_ONLY}
npm ci
cd ../..
node ci/scripts/upload-builds.mjs v${VERSION_ONLY}
Comment thread
Pratham-Mishra04 marked this conversation as resolved.

# Second job: Build and push Docker image
# Runs after transport build completes successfully
Expand Down
40 changes: 15 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,30 @@ Bifrost is a high-performance AI gateway that connects you to 10+ providers (Ope
**What You Need**

- Any AI provider API key (OpenAI, Anthropic, Bedrock, etc.)
- Docker **OR** Go 1.23+ installed
- 30 seconds of your time ⏰
- Node.js 18+ installed (or use Docker instead via [Docker installation](#using-bifrost-http-transport))
- 20 seconds of your time ⏰

### Using Bifrost HTTP Transport

📖 For detailed setup guides with multiple providers, advanced configuration, and language examples, see [Quick Start Documentation](./docs/quickstart/README.md)
📖 For detailed setup guides with multiple providers, advanced configuration, and language examples, see [Quick Start Documentation](./docs/quickstart/http-transport.md)

**Step 1:** Start Bifrost (choose one)
**Step 1:** Start Bifrost

```bash
# 🐳 Docker (easiest - zero config needed!)
docker pull maximhq/bifrost
docker run -p 8080:8080 maximhq/bifrost

# 🔧 Or install Go binary (Make sure Go is in your PATH)
go install github.com/maximhq/bifrost/transports/bifrost-http@latest
bifrost-http -port 8080
# 🔧 Run Bifrost binary
npx @maximhq/bifrost
```

**Step 2:** Open the built-in web interface
**Step 2:** Open the built-in web interface and configure bifrost

```bash
# 🖥️ Configure visually - no config files needed!
# 🖥️ Open the web interface in your browser
open http://localhost:8080

# Or simply open http://localhost:8080 manually in your browser
```
Comment thread
Pratham-Mishra04 marked this conversation as resolved.

**Step 3:** Add your provider via the web UI or API

Via Web UI: Just Go to providers tab and click "Add Provider" to configure your provider.

Note: If using environment variables (e.g. `env.OPENAI_API_KEY`), make sure to set the corresponding environment variable in bifrost's session, or pass it as a flag in Docker (`docker run -e OPENAI_API_KEY maximhq/bifrost`).

**Step 4:** Test it works
**Step 3:** Test it works

```bash
curl -X POST http://localhost:8080/v1/chat/completions \
Expand Down Expand Up @@ -122,6 +111,8 @@ Bifrost is built with a modular architecture:

```text
bifrost/
├── ci/ # CI/CD pipeline scripts and npx configuration
├── core/ # Core functionality and shared components
│ ├── providers/ # Provider-specific implementations
│ ├── schemas/ # Interfaces and structs used in bifrost
Expand All @@ -137,6 +128,9 @@ bifrost/
│ ├── bifrost-http/ # HTTP transport implementation
│ └── ...
├── ui/ # UI files for the web interface of the HTTP transport
│ └── ...
└── plugins/ # Plugin Implementations
├── maxim/
└── ...
Expand Down Expand Up @@ -171,11 +165,7 @@ For language-agnostic integration and microservices architecture.
Quick example:

```bash
docker pull maximhq/bifrost
docker run -p 8080:8080 \
-v $(pwd)/config.json:/app/config/config.json \
-e OPENAI_API_KEY \
maximhq/bifrost
npx @maximhq/bifrost
```

### 3. As a Drop-in Replacement (Zero Code Changes)
Expand Down
137 changes: 137 additions & 0 deletions ci/npx/bin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#!/usr/bin/env node

import { execSync } from "child_process";
import { chmodSync, createWriteStream } from "fs";
import fetch from "node-fetch";
import { tmpdir } from "os";
import { join } from "path";

const BASE_URL = "https://downloads.getmaxim.ai";

Comment thread
Pratham-Mishra04 marked this conversation as resolved.
// Parse transport version from command line arguments
function parseTransportVersion() {
const args = process.argv.slice(2);
let transportVersion = "latest"; // Default to latest

// Find --transport-version argument
const versionArgIndex = args.findIndex(arg => arg.startsWith("--transport-version"));

if (versionArgIndex !== -1) {
const versionArg = args[versionArgIndex];

if (versionArg.includes("=")) {
// Format: --transport-version=v1.2.3
transportVersion = versionArg.split("=")[1];
} else if (versionArgIndex + 1 < args.length) {
// Format: --transport-version v1.2.3
transportVersion = args[versionArgIndex + 1];
}

// Remove the transport-version arguments from args array so they don't get passed to the binary
if (versionArg.includes("=")) {
args.splice(versionArgIndex, 1);
} else {
args.splice(versionArgIndex, 2);
}
}

return { version: validateTransportVersion(transportVersion), remainingArgs: args };
}

// Validate transport version format
function validateTransportVersion(version) {
if (version === "latest") {
return version;
}

// Check if version matches v{x.x.x} format
const versionRegex = /^v\d+\.\d+\.\d+$/;
if (versionRegex.test(version)) {
return version;
}

console.error(`Invalid transport version format: ${version}`);
console.error(`Transport version must be either "latest" or in format v1.2.3`);
process.exit(1);
}
Comment thread
Pratham-Mishra04 marked this conversation as resolved.

const { version: VERSION, remainingArgs } = parseTransportVersion();

function getPlatformArchAndBinary() {
const platform = process.platform;
const arch = process.arch;

let platformDir;
let archDir;
let binaryName;

if (platform === "darwin") {
platformDir = "darwin";
if (arch === "arm64") archDir = "arm64";
else archDir = "amd64";
binaryName = "bifrost-http";
} else if (platform === "linux") {
platformDir = "linux";
if (arch === "x64") archDir = "amd64";
else if (arch === "ia32") archDir = "386";
else archDir = arch; // fallback
binaryName = "bifrost-http";
} else if (platform === "win32") {
platformDir = "windows";
if (arch === "x64") archDir = "amd64";
else if (arch === "ia32") archDir = "386";
else archDir = arch; // fallback
binaryName = "bifrost-http.exe";
} else {
console.error(`Unsupported platform/arch: ${platform}/${arch}`);
process.exit(1);
}

return { platformDir, archDir, binaryName };
}

async function downloadBinary(url, dest) {
const res = await fetch(url);

if (!res.ok) {
console.error(`Download failed: ${res.status} ${res.statusText}`);
process.exit(1);
}

const fileStream = createWriteStream(dest);
Comment thread
Pratham-Mishra04 marked this conversation as resolved.
await new Promise((resolve, reject) => {
res.body.pipe(fileStream);
res.body.on("error", reject);
fileStream.on("finish", resolve);
});
Comment thread
Pratham-Mishra04 marked this conversation as resolved.

chmodSync(dest, 0o755);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Comment thread
Pratham-Mishra04 marked this conversation as resolved.

(async () => {
const { platformDir, archDir, binaryName } = getPlatformArchAndBinary();
const binaryPath = join(tmpdir(), binaryName);

Comment thread
Pratham-Mishra04 marked this conversation as resolved.
// The download URL now matches the CI pipeline's S3 structure with arch
// Example: https://downloads.getmaxim.ai/bifrost/latest/darwin/arm64/bifrost
const downloadUrl = `${BASE_URL}/bifrost/${VERSION}/${platformDir}/${archDir}/${binaryName}`;

try {
await downloadBinary(downloadUrl, binaryPath);
} catch (error) {
console.error(`❌ Failed to download binary from ${downloadUrl}:`, error.message);
process.exit(1);
}

// Get command-line arguments to pass to the binary (excluding --transport-version)
const args = remainingArgs.join(" ");

// Execute the binary, forwarding the arguments
try {
execSync(`${binaryPath} ${args}`, { stdio: "inherit" });
} catch (error) {
// The child process will have already printed its error message.
// Exit with the same status code as the child process.
process.exit(error.status || 1);
}
Comment thread
Pratham-Mishra04 marked this conversation as resolved.
})();
19 changes: 19 additions & 0 deletions ci/npx/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions ci/npx/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@maximhq/bifrost",
"version": "1.0.1",
"description": "High-performance AI gateway CLI - connect to 10+ providers through a single API",
"keywords": ["ai", "gateway", "openai", "anthropic", "cli", "bifrost"],
"homepage": "https://github.com/maximhq/bifrost",
"repository": {
"type": "git",
"url": "https://github.com/maximhq/bifrost.git"
},
"license": "Apache-2.0",
"author": "Maxim HQ",
"engines": {
"node": ">=18.0.0"
},
"publishConfig": {
"access": "public"
},
"bin": {
"bifrost": "bin.js"
},
Comment thread
Pratham-Mishra04 marked this conversation as resolved.
"type": "module",
"dependencies": {}
Comment thread
Pratham-Mishra04 marked this conversation as resolved.
}
Comment thread
Pratham-Mishra04 marked this conversation as resolved.
Loading