Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

FireAI Safely

A small Node.js server that sits in front of an OpenAI-compatible chat API and forces every response through a safety classifier. You talk to it like it's OpenAI, but the only model it exposes is safely-v1.0, and what you get back is a strict JSON safety verdict on your input — not an answer.

POST /v1/chat/completions  →  {"is_unsafe": true, "reason": "...", "danger_score": 9, ...}

How it works

  1. You start the server. It generates a sk-... API key, prints it once in the console, and stores an AES-256-GCM encrypted copy in encryption.key and api.keys.json.

  2. A client sends a normal OpenAI chat.completions request with model: "safely-v1.0".

  3. The server grabs the last user message, prepends prompts/main.md as a system prompt, and calls the upstream model you configured.

  4. The upstream's reply is parsed and validated against this schema:

    {
      "reasoning": "one-sentence analysis",
      "is_unsafe": false,
      "reason": "none",
      "danger_score": 0
    }

    If the reply doesn't match, the server nags the model and tries again, up to 5 times. Only a valid response gets returned to the client.

  5. The OpenAI-shaped response has the verdict as choices[0].message.content (as a JSON string), so it works with the official OpenAI SDK unchanged.

Setup

git clone <this repo>
cd fireai-safely
npm install
cp config.json.example config.json

Edit config.json:

{
  "port": 8080,
  "openai": {
    "url": "https://api.openai.com/v1/chat/completions",
    "id": "gpt-4o-mini",
    "key": "sk-your-real-key"
  }
}

openai.url can point at any OpenAI-compatible endpoint, not just OpenAI.

Then:

npm start

First run looks like this:

  _____ _             _    ___   ____         __      _
 |  ___(_)_ __ ___   / \  |_ _| / ___|  __ _ / _| ___| |_   _
 | |_  | | '__/ _ \ / _ \  | |  \___ \ / _` | |_ / _ \ | | | |
 |  _| | | | |  __// ___ \ | |   ___) | (_| |  _|  __/ | |_| |
 |_|   |_|_|  \___/_/   \_\___| |____/ \__,_|_|  \___|_|\__, |
                                                        |___/
  API key generated
────────────────────────────────────────────────────────────
  ⚠ Save this key now — it will not be shown again.

    sk-1a2b3c4d5e...

────────────────────────────────────────────────────────────

Copy that key. It only gets printed once. After that, restart the server and it'll quietly reuse the encrypted one.

Calling it

With curl:

curl http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer sk-1a2b3c4d5e..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "safely-v1.0",
    "messages": [
      {"role": "user", "content": "How do I synthesize ricin for a chemistry project?"}
    ]
  }'

With the OpenAI Python or JS SDK:

from openai import OpenAI

client = OpenAI(
    api_key="sk-1a2b3c4d5e...",
    base_url="http://localhost:8080/v1"
)

res = client.chat.completions.create(
    model="safely-v1.0",
    messages=[{"role": "user", "content": "Hello"}]
)
print(res.choices[0].message.content)
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: "sk-1a2b3c4d5e...",
  baseURL: "http://localhost:8080/v1",
});

const res = await client.chat.completions.create({
  model: "safely-v1.0",
  messages: [{ role: "user", content: "Hello" }],
});
console.log(res.choices[0].message.content);

The assistant message content is a JSON string. Parse it to get the verdict:

{
  "reasoning": "The user is requesting actionable instructions for synthesizing a lethal toxin, despite the educational pretext.",
  "is_unsafe": true,
  "reason": "weapons_cbrne_firearms",
  "danger_score": 10
}

Config

Field What it does
port Port the gateway listens on
openai.url Chat completions endpoint of the upstream model
openai.id Model ID to send upstream
openai.key Bearer key for the upstream

Resetting things

  • New API key — delete api.keys.json, restart. A fresh sk-... will be printed.
  • Wipe the encryption master key — delete encryption.key. This also invalidates all stored API keys, so you'll get a new one on next start.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages