Require local setup embedding profile selection
This commit is contained in:
+10
-4
@@ -6,13 +6,19 @@
|
|||||||
# Get one at: https://platform.openai.com/api-keys
|
# Get one at: https://platform.openai.com/api-keys
|
||||||
OPENAI_API_KEY=
|
OPENAI_API_KEY=
|
||||||
|
|
||||||
# AI profiles. Defaults keep RA-H on OpenAI plus sqlite-vec.
|
# AI profiles are selected during setup because embedding dimensions shape
|
||||||
LLM_PROFILE=openai
|
# the sqlite-vec tables. Use one:
|
||||||
|
#
|
||||||
|
# npm run setup:local -- --profile openai
|
||||||
|
# npm run setup:local -- --profile qwen-local
|
||||||
|
#
|
||||||
|
# OpenAI profile:
|
||||||
|
# LLM_PROFILE=openai
|
||||||
# LLM_MODEL=gpt-4o-mini
|
# LLM_MODEL=gpt-4o-mini
|
||||||
EMBEDDING_PROFILE=openai
|
# EMBEDDING_PROFILE=openai
|
||||||
# EMBEDDING_MODEL=text-embedding-3-small
|
# EMBEDDING_MODEL=text-embedding-3-small
|
||||||
# EMBEDDING_DIMENSIONS=1536
|
# EMBEDDING_DIMENSIONS=1536
|
||||||
VECTOR_BACKEND=sqlite-vec
|
# VECTOR_BACKEND=sqlite-vec
|
||||||
|
|
||||||
# Supported local profile: point RA-H at OpenAI-compatible local endpoints.
|
# Supported local profile: point RA-H at OpenAI-compatible local endpoints.
|
||||||
# Example Ollama:
|
# Example Ollama:
|
||||||
|
|||||||
@@ -130,6 +130,43 @@ Full install details:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## First-Time Setup
|
||||||
|
|
||||||
|
Pick the embedding profile before the database is created. This matters because
|
||||||
|
the readable `nodes` and `chunks` tables are normal SQLite tables, but the
|
||||||
|
derived sqlite-vec vector tables are created with a fixed embedding width.
|
||||||
|
|
||||||
|
OpenAI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run setup:local -- --profile openai
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Local Qwen with Ollama:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
ollama pull qwen3:4b
|
||||||
|
ollama pull qwen3-embedding:0.6b
|
||||||
|
npm run setup:local -- --profile qwen-local
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
If you run setup without a profile and `.env.local` does not already select one,
|
||||||
|
setup stops before creating vector tables and prints the two supported commands.
|
||||||
|
|
||||||
|
If you change embedding provider, model, dimensions, or vector backend after
|
||||||
|
data exists, your source data stays intact but derived embeddings must be
|
||||||
|
rebuilt:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run rebuild:embeddings
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## OpenAI API Key
|
## OpenAI API Key
|
||||||
|
|
||||||
**Optional but recommended.** Without a key, you can still create and organize nodes manually.
|
**Optional but recommended.** Without a key, you can still create and organize nodes manually.
|
||||||
@@ -149,7 +186,7 @@ Get a key at [platform.openai.com/api-keys](https://platform.openai.com/api-keys
|
|||||||
|
|
||||||
## Local Model Profile
|
## Local Model Profile
|
||||||
|
|
||||||
OpenAI remains the default supported path. If you want local utility LLM calls and local embeddings, run a local OpenAI-compatible model server and point RA-H at it.
|
OpenAI remains the default supported cloud path. If you want local utility LLM calls and local embeddings, run a local OpenAI-compatible model server and point RA-H at it.
|
||||||
|
|
||||||
Supported local contract:
|
Supported local contract:
|
||||||
|
|
||||||
@@ -228,7 +265,7 @@ If you need a clean demo without touching your normal RA-H database:
|
|||||||
git clone https://github.com/bradwmorris/ra-h_os.git ~/Desktop/ra-h_os-demo
|
git clone https://github.com/bradwmorris/ra-h_os.git ~/Desktop/ra-h_os-demo
|
||||||
cd ~/Desktop/ra-h_os-demo
|
cd ~/Desktop/ra-h_os-demo
|
||||||
npm install
|
npm install
|
||||||
SQLITE_DB_PATH="$HOME/Desktop/ra-h_os-demo-data/rah.sqlite" npm run setup:local
|
SQLITE_DB_PATH="$HOME/Desktop/ra-h_os-demo-data/rah.sqlite" npm run setup:local -- --profile qwen-local
|
||||||
npm run dev
|
npm run dev
|
||||||
|
|
||||||
npx -y ra-h-mcp-server@latest setup \
|
npx -y ra-h-mcp-server@latest setup \
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import Database from 'better-sqlite3';
|
|||||||
const repoDir = process.cwd();
|
const repoDir = process.cwd();
|
||||||
const envTemplate = path.join(repoDir, '.env.example');
|
const envTemplate = path.join(repoDir, '.env.example');
|
||||||
const targetEnv = path.join(repoDir, '.env.local');
|
const targetEnv = path.join(repoDir, '.env.local');
|
||||||
|
const supportedProfiles = new Set(['openai', 'qwen-local']);
|
||||||
|
|
||||||
function log(message) {
|
function log(message) {
|
||||||
console.log(`[bootstrap-local] ${message}`);
|
console.log(`[bootstrap-local] ${message}`);
|
||||||
@@ -89,10 +90,12 @@ function ensureEnvValue(key, value) {
|
|||||||
const nextLines = lines.map((line) => {
|
const nextLines = lines.map((line) => {
|
||||||
const trimmed = line.trim();
|
const trimmed = line.trim();
|
||||||
if (trimmed.startsWith(`${key}=`)) {
|
if (trimmed.startsWith(`${key}=`)) {
|
||||||
|
if (found) return line;
|
||||||
found = true;
|
found = true;
|
||||||
return `${key}=${value}`;
|
return `${key}=${value}`;
|
||||||
}
|
}
|
||||||
if (trimmed.startsWith(`# ${key}=`) || trimmed.startsWith(`#${key}=`)) {
|
if (trimmed.startsWith(`# ${key}=`) || trimmed.startsWith(`#${key}=`)) {
|
||||||
|
if (found) return line;
|
||||||
found = true;
|
found = true;
|
||||||
return `${key}=${value}`;
|
return `${key}=${value}`;
|
||||||
}
|
}
|
||||||
@@ -110,6 +113,74 @@ function ensureEnvValue(key, value) {
|
|||||||
log(`Set ${key} in .env.local`);
|
log(`Set ${key} in .env.local`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseArgs(argv) {
|
||||||
|
const args = { profile: undefined };
|
||||||
|
for (let index = 0; index < argv.length; index += 1) {
|
||||||
|
const arg = argv[index];
|
||||||
|
if (arg === '--profile') {
|
||||||
|
args.profile = argv[index + 1];
|
||||||
|
index += 1;
|
||||||
|
} else if (arg.startsWith('--profile=')) {
|
||||||
|
args.profile = arg.slice('--profile='.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSetupProfile(rawProfile) {
|
||||||
|
if (!rawProfile) return undefined;
|
||||||
|
if (rawProfile === 'qwen' || rawProfile === 'local' || rawProfile === 'ollama') {
|
||||||
|
return 'qwen-local';
|
||||||
|
}
|
||||||
|
return rawProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applySetupProfile(profile) {
|
||||||
|
if (!profile) return;
|
||||||
|
if (!supportedProfiles.has(profile)) {
|
||||||
|
throw new Error(`Unsupported setup profile "${profile}". Use "openai" or "qwen-local".`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile === 'openai') {
|
||||||
|
ensureEnvValue('LLM_PROFILE', 'openai');
|
||||||
|
ensureEnvValue('EMBEDDING_PROFILE', 'openai');
|
||||||
|
ensureEnvValue('EMBEDDING_MODEL', 'text-embedding-3-small');
|
||||||
|
ensureEnvValue('EMBEDDING_DIMENSIONS', '1536');
|
||||||
|
ensureEnvValue('VECTOR_BACKEND', 'sqlite-vec');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureEnvValue('LLM_PROFILE', 'openai-compatible');
|
||||||
|
ensureEnvValue('LLM_BASE_URL', 'http://127.0.0.1:11434/v1');
|
||||||
|
ensureEnvValue('LLM_MODEL', 'qwen3:4b');
|
||||||
|
ensureEnvValue('EMBEDDING_PROFILE', 'openai-compatible');
|
||||||
|
ensureEnvValue('EMBEDDING_BASE_URL', 'http://127.0.0.1:11434/v1');
|
||||||
|
ensureEnvValue('EMBEDDING_MODEL', 'qwen3-embedding:0.6b');
|
||||||
|
ensureEnvValue('EMBEDDING_DIMENSIONS', '1024');
|
||||||
|
ensureEnvValue('VECTOR_BACKEND', 'sqlite-vec');
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertEmbeddingProfileSelected(env) {
|
||||||
|
if (env.EMBEDDING_PROFILE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error([
|
||||||
|
'Choose an embedding profile before database setup.',
|
||||||
|
'',
|
||||||
|
'The selected embedding model controls sqlite-vec table dimensions:',
|
||||||
|
' OpenAI text-embedding-3-small -> 1536',
|
||||||
|
' Local Qwen qwen3-embedding:0.6b -> 1024',
|
||||||
|
'',
|
||||||
|
'Run one of:',
|
||||||
|
' npm run setup:local -- --profile openai',
|
||||||
|
' npm run setup:local -- --profile qwen-local',
|
||||||
|
'',
|
||||||
|
'If you change embedding provider later, run:',
|
||||||
|
' npm run rebuild:embeddings',
|
||||||
|
].join('\n'));
|
||||||
|
}
|
||||||
|
|
||||||
function ensureCoreSchema(db) {
|
function ensureCoreSchema(db) {
|
||||||
db.pragma('foreign_keys = ON');
|
db.pragma('foreign_keys = ON');
|
||||||
db.exec(`
|
db.exec(`
|
||||||
@@ -590,9 +661,14 @@ function main() {
|
|||||||
throw new Error(`Node.js 20+ required (found ${process.version})`);
|
throw new Error(`Node.js 20+ required (found ${process.version})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const args = parseArgs(process.argv.slice(2));
|
||||||
|
const setupProfile = normalizeSetupProfile(args.profile);
|
||||||
|
|
||||||
ensureEnvFile();
|
ensureEnvFile();
|
||||||
|
applySetupProfile(setupProfile);
|
||||||
|
|
||||||
const env = { ...parseEnvFile(targetEnv), ...process.env };
|
const env = { ...parseEnvFile(targetEnv), ...process.env };
|
||||||
|
assertEmbeddingProfileSelected(env);
|
||||||
if (process.env.SQLITE_DB_PATH) {
|
if (process.env.SQLITE_DB_PATH) {
|
||||||
ensureEnvValue('SQLITE_DB_PATH', process.env.SQLITE_DB_PATH);
|
ensureEnvValue('SQLITE_DB_PATH', process.env.SQLITE_DB_PATH);
|
||||||
env.SQLITE_DB_PATH = process.env.SQLITE_DB_PATH;
|
env.SQLITE_DB_PATH = process.env.SQLITE_DB_PATH;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ console.log('[setup-local] Rebuilding better-sqlite3 native bindings');
|
|||||||
run('npm', ['rebuild', 'better-sqlite3']);
|
run('npm', ['rebuild', 'better-sqlite3']);
|
||||||
|
|
||||||
console.log('[setup-local] Bootstrapping local RA-H database');
|
console.log('[setup-local] Bootstrapping local RA-H database');
|
||||||
run('npm', ['run', 'bootstrap:local']);
|
run('npm', ['run', 'bootstrap:local', '--', ...process.argv.slice(2)]);
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('[setup-local] Local app setup complete.');
|
console.log('[setup-local] Local app setup complete.');
|
||||||
|
|||||||
Reference in New Issue
Block a user