neoagent 2.1.18-beta.2 → 2.1.18-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example CHANGED
@@ -1,6 +1,10 @@
1
1
  PORT=3333
2
2
  NODE_ENV=development
3
3
  SESSION_SECRET=change-this-to-a-random-secret-in-production
4
+ PUBLIC_URL=
5
+ SECURE_COOKIES=false
6
+ NEOAGENT_DEPLOYMENT_MODE=self_hosted
7
+ NEOAGENT_RELEASE_CHANNEL=stable
4
8
 
5
9
  # Comma-separated list of allowed CORS origins (leave empty to block all cross-origin requests)
6
10
  # Example: ALLOWED_ORIGINS=http://localhost:3333,https://yourdomain.com
@@ -12,6 +16,7 @@ ALLOWED_ORIGINS=
12
16
  # • Image vision / analysis (grok-4-1-fast-reasoning has native image input — analyze_image tool, incoming WhatsApp photos)
13
17
  # Get your key at: https://console.x.ai
14
18
  XAI_API_KEY=your-xai-api-key-here
19
+ # XAI_BASE_URL=https://api.x.ai/v1
15
20
 
16
21
  # OpenAI API key — used for:
17
22
  # • Semantic memory embeddings (text-embedding-3-small, 1536 dims)
@@ -21,6 +26,12 @@ XAI_API_KEY=your-xai-api-key-here
21
26
  # Without this key: memory falls back to keyword search, voice calls and WhatsApp audio transcription are unavailable.
22
27
  # Get your key at: https://platform.openai.com/api-keys
23
28
  OPENAI_API_KEY=your-openai-api-key-here
29
+ # OPENAI_BASE_URL=https://your-openai-compatible-endpoint/v1
30
+
31
+ # Anthropic API key — used for:
32
+ # • Claude models for long-context drafting and analysis
33
+ ANTHROPIC_API_KEY=your-anthropic-api-key-here
34
+ # ANTHROPIC_BASE_URL=https://your-anthropic-compatible-endpoint
24
35
 
25
36
  # Google AI Studio API key — used for:
26
37
  # • Gemini models (e.g. gemini-3.1-flash-lite-preview)
@@ -43,5 +54,11 @@ BRAVE_SEARCH_API_KEY=your-brave-search-api-key-here
43
54
  # Without this key: recordings can still be captured and stored, but transcription will fail until retried with a valid key.
44
55
  # Get your key at: https://console.deepgram.com/
45
56
  DEEPGRAM_API_KEY=your-deepgram-api-key-here
57
+ DEEPGRAM_BASE_URL=https://api.deepgram.com
46
58
  DEEPGRAM_MODEL=nova-3
47
59
  DEEPGRAM_LANGUAGE=multi
60
+
61
+ # Optional additional providers and services
62
+ # MINIMAX_API_KEY=your-minimax-api-key-here
63
+ # OLLAMA_URL=http://localhost:11434
64
+ # TELNYX_WEBHOOK_TOKEN=replace-me
@@ -1,6 +1,6 @@
1
1
  # Configuration
2
2
 
3
- All settings live in `~/.neoagent/.env` by default. Run `neoagent setup` to regenerate interactively. If a self-edit or local install issue leaves NeoAgent broken, `neoagent fix` will back up `~/.neoagent`, repair the installation, and restart the service.
3
+ All settings live in `~/.neoagent/.env` by default. Run `neoagent setup` to regenerate interactively. AI provider credentials are configured through the server environment or `neoagent setup`, not through the web UI. If a self-edit or local install issue leaves NeoAgent broken, rerun setup or restore the env file and restart the service.
4
4
  You can override the runtime root with `NEOAGENT_HOME`.
5
5
 
6
6
  ## Variables
@@ -10,27 +10,34 @@ You can override the runtime root with `NEOAGENT_HOME`.
10
10
  | Variable | Default | Description |
11
11
  |---|---|---|
12
12
  | `PORT` | `3333` | HTTP port |
13
+ | `PUBLIC_URL` | *(optional)* | Public base URL used for callbacks and external links |
13
14
  | `SESSION_SECRET` | *(required)* | Random string for session signing — generate with `openssl rand -hex 32` |
14
15
  | `NODE_ENV` | `production` | Set to `development` to enable verbose logs |
15
16
  | `SECURE_COOKIES` | `false` | Set `true` when behind a TLS-terminating proxy |
16
17
  | `ALLOWED_ORIGINS` | *(none)* | Comma-separated CORS origins, e.g. `https://example.com` |
18
+ | `NEOAGENT_DEPLOYMENT_MODE` | `self_hosted` | `self_hosted` enables in-app update controls; `managed` hides operator-only controls for SaaS deployments |
19
+ | `NEOAGENT_RELEASE_CHANNEL` | `stable` | Release track used by the self-hosted updater |
17
20
 
18
21
  ### AI Providers
19
22
 
20
- At least one API key is required. The active provider and model are configured in the Flutter app.
23
+ At least one hosted-provider API key is required unless you only use local Ollama. The active provider and model routing are configured in the Flutter app; credentials stay in server-side config.
21
24
 
22
25
  | Variable | Provider |
23
26
  |---|---|
24
27
  | `ANTHROPIC_API_KEY` | Claude (Anthropic) |
25
28
  | `OPENAI_API_KEY` | GPT-4o / Whisper (OpenAI) |
26
29
  | `XAI_API_KEY` | Grok (xAI) |
30
+ | `XAI_BASE_URL` | Optional xAI-compatible base URL override |
27
31
  | `GOOGLE_AI_KEY` | Gemini (Google) |
28
32
  | `GOOGLE_OAUTH_CLIENT_ID` | Google Workspace official integrations OAuth client ID |
29
33
  | `GOOGLE_OAUTH_CLIENT_SECRET` | Google Workspace official integrations OAuth client secret |
30
34
  | `GOOGLE_OAUTH_REDIRECT_URI` | Optional override for the Google Workspace OAuth callback URL |
31
35
  | `MINIMAX_API_KEY` | MiniMax Code (Coding Plan / Token Plan for `MiniMax-M2.7`) |
32
36
  | `BRAVE_SEARCH_API_KEY` | Brave Search API for the native `web_search` tool |
37
+ | `OPENAI_BASE_URL` | Optional OpenAI-compatible base URL override |
38
+ | `ANTHROPIC_BASE_URL` | Optional Anthropic-compatible base URL override |
33
39
  | `DEEPGRAM_API_KEY` | Recordings transcription with Deepgram Nova-3 multilingual |
40
+ | `DEEPGRAM_BASE_URL` | Optional Deepgram API base URL override |
34
41
  | `DEEPGRAM_MODEL` | Deepgram speech model override (defaults to `nova-3`) |
35
42
  | `DEEPGRAM_LANGUAGE` | Deepgram language override (defaults to `multi`) |
36
43
  | `OLLAMA_URL` | Local Ollama (`http://localhost:11434`) |
package/lib/manager.js CHANGED
@@ -31,6 +31,7 @@ const {
31
31
  choosePreferredBranchForChannel,
32
32
  choosePreferredNpmTagForChannel,
33
33
  } = require('../runtime/release_channel');
34
+ const { parseDeploymentMode } = require('../server/utils/deployment');
34
35
 
35
36
  const APP_NAME = 'NeoAgent';
36
37
  const SERVICE_LABEL = 'com.neoagent';
@@ -417,43 +418,110 @@ async function ask(question, fallback = '') {
417
418
  });
418
419
  }
419
420
 
421
+ async function askSecret(question, currentValue = '') {
422
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
423
+ return new Promise((resolve) => {
424
+ const suffix = currentValue ? ' [configured]' : '';
425
+ rl.question(` ? ${question}${suffix}: `, (answer) => {
426
+ rl.close();
427
+ const trimmed = answer.trim();
428
+ resolve(trimmed || currentValue);
429
+ });
430
+ });
431
+ }
432
+
420
433
  async function cmdSetup() {
421
434
  heading('Environment Setup');
422
435
  ensureRuntimeDirs();
423
436
 
424
- const current = {};
425
- if (fs.existsSync(ENV_FILE)) {
426
- const lines = fs.readFileSync(ENV_FILE, 'utf8').split('\n');
427
- for (const line of lines) {
428
- if (!line || line.startsWith('#') || !line.includes('=')) continue;
429
- const idx = line.indexOf('=');
430
- const key = line.slice(0, idx).trim();
431
- const value = line.slice(idx + 1).trim();
432
- current[key] = value;
433
- }
434
- }
437
+ const current = Object.fromEntries(parseEnv(readEnvFileRaw()).entries());
438
+
439
+ logInfo('Press Enter to keep the current value shown in brackets.');
435
440
 
441
+ heading('Core');
436
442
  const port = await ask('Server port', current.PORT || '3333');
437
- const sessionSecret = await ask('Session secret', current.SESSION_SECRET || randomSecret());
438
- const anthropic = await ask('Anthropic API key', current.ANTHROPIC_API_KEY || '');
439
- const openai = await ask('OpenAI API key', current.OPENAI_API_KEY || '');
440
- const xai = await ask('xAI API key', current.XAI_API_KEY || '');
441
- const google = await ask('Google API key', current.GOOGLE_AI_KEY || '');
442
- const minimax = await ask('MiniMax Code key', current.MINIMAX_API_KEY || '');
443
- const brave = await ask('Brave Search API key', current.BRAVE_SEARCH_API_KEY || '');
444
- const ollama = await ask('Ollama URL', current.OLLAMA_URL || 'http://localhost:11434');
443
+ const publicUrl = await ask('Public base URL', current.PUBLIC_URL || '');
444
+ const secureCookiesDefault = current.SECURE_COOKIES ||
445
+ (String(publicUrl || '').trim().startsWith('https://') ? 'true' : 'false');
446
+ const secureCookies = await ask('Secure cookies (true/false)', secureCookiesDefault);
447
+ const sessionSecret = await askSecret('Session secret', current.SESSION_SECRET || randomSecret());
448
+ const deploymentMode = await ask(
449
+ 'Deployment mode (self_hosted/managed)',
450
+ current.NEOAGENT_DEPLOYMENT_MODE || 'self_hosted'
451
+ );
452
+ const releaseChannel = await ask(
453
+ 'Release channel (stable/beta)',
454
+ current.NEOAGENT_RELEASE_CHANNEL || 'stable'
455
+ );
445
456
  const origins = await ask('Allowed CORS origins', current.ALLOWED_ORIGINS || '');
446
457
 
458
+ heading('AI Providers');
459
+ const anthropic = await askSecret('Anthropic API key', current.ANTHROPIC_API_KEY || '');
460
+ const anthropicBaseUrl = await ask('Anthropic base URL', current.ANTHROPIC_BASE_URL || '');
461
+ const openai = await askSecret('OpenAI API key', current.OPENAI_API_KEY || '');
462
+ const openaiBaseUrl = await ask('OpenAI base URL', current.OPENAI_BASE_URL || '');
463
+ const xai = await askSecret('xAI API key', current.XAI_API_KEY || '');
464
+ const xaiBaseUrl = await ask('xAI base URL', current.XAI_BASE_URL || 'https://api.x.ai/v1');
465
+ const google = await askSecret('Google API key', current.GOOGLE_AI_KEY || '');
466
+ const minimax = await askSecret('MiniMax Code key', current.MINIMAX_API_KEY || '');
467
+ const brave = await askSecret('Brave Search API key', current.BRAVE_SEARCH_API_KEY || '');
468
+ const ollama = await ask('Ollama URL', current.OLLAMA_URL || 'http://localhost:11434');
469
+
470
+ heading('Official Integrations');
471
+ const googleOauthClientId = await askSecret(
472
+ 'Google OAuth client ID',
473
+ current.GOOGLE_OAUTH_CLIENT_ID || ''
474
+ );
475
+ const googleOauthClientSecret = await askSecret(
476
+ 'Google OAuth client secret',
477
+ current.GOOGLE_OAUTH_CLIENT_SECRET || ''
478
+ );
479
+ const googleOauthRedirectUri = await ask(
480
+ 'Google OAuth redirect URI',
481
+ current.GOOGLE_OAUTH_REDIRECT_URI || ''
482
+ );
483
+
484
+ heading('Voice And Recording');
485
+ const deepgramApiKey = await askSecret('Deepgram API key', current.DEEPGRAM_API_KEY || '');
486
+ const deepgramBaseUrl = await ask(
487
+ 'Deepgram base URL',
488
+ current.DEEPGRAM_BASE_URL || 'https://api.deepgram.com'
489
+ );
490
+ const deepgramModel = await ask('Deepgram model', current.DEEPGRAM_MODEL || 'nova-3');
491
+ const deepgramLanguage = await ask('Deepgram language', current.DEEPGRAM_LANGUAGE || 'multi');
492
+ const telnyxWebhookToken = await askSecret(
493
+ 'Telnyx webhook token',
494
+ current.TELNYX_WEBHOOK_TOKEN || ''
495
+ );
496
+ const normalizedSecureCookies = String(secureCookies || '').trim().toLowerCase() === 'true' ? 'true' : 'false';
497
+ const normalizedDeploymentMode = parseDeploymentMode(deploymentMode);
498
+ const normalizedReleaseChannel = parseReleaseChannel(releaseChannel) || 'stable';
499
+
447
500
  const lines = [
448
501
  `NODE_ENV=production`,
449
502
  `PORT=${port}`,
503
+ publicUrl ? `PUBLIC_URL=${publicUrl}` : '',
504
+ `SECURE_COOKIES=${normalizedSecureCookies}`,
450
505
  `SESSION_SECRET=${sessionSecret}`,
506
+ `NEOAGENT_DEPLOYMENT_MODE=${normalizedDeploymentMode}`,
507
+ `NEOAGENT_RELEASE_CHANNEL=${normalizedReleaseChannel}`,
451
508
  anthropic ? `ANTHROPIC_API_KEY=${anthropic}` : '',
509
+ anthropicBaseUrl ? `ANTHROPIC_BASE_URL=${anthropicBaseUrl}` : '',
452
510
  openai ? `OPENAI_API_KEY=${openai}` : '',
511
+ openaiBaseUrl ? `OPENAI_BASE_URL=${openaiBaseUrl}` : '',
453
512
  xai ? `XAI_API_KEY=${xai}` : '',
513
+ xaiBaseUrl ? `XAI_BASE_URL=${xaiBaseUrl}` : '',
454
514
  google ? `GOOGLE_AI_KEY=${google}` : '',
455
515
  minimax ? `MINIMAX_API_KEY=${minimax}` : '',
456
516
  brave ? `BRAVE_SEARCH_API_KEY=${brave}` : '',
517
+ googleOauthClientId ? `GOOGLE_OAUTH_CLIENT_ID=${googleOauthClientId}` : '',
518
+ googleOauthClientSecret ? `GOOGLE_OAUTH_CLIENT_SECRET=${googleOauthClientSecret}` : '',
519
+ googleOauthRedirectUri ? `GOOGLE_OAUTH_REDIRECT_URI=${googleOauthRedirectUri}` : '',
520
+ deepgramApiKey ? `DEEPGRAM_API_KEY=${deepgramApiKey}` : '',
521
+ deepgramBaseUrl ? `DEEPGRAM_BASE_URL=${deepgramBaseUrl}` : '',
522
+ deepgramModel ? `DEEPGRAM_MODEL=${deepgramModel}` : '',
523
+ deepgramLanguage ? `DEEPGRAM_LANGUAGE=${deepgramLanguage}` : '',
524
+ telnyxWebhookToken ? `TELNYX_WEBHOOK_TOKEN=${telnyxWebhookToken}` : '',
457
525
  ollama ? `OLLAMA_URL=${ollama}` : '',
458
526
  origins ? `ALLOWED_ORIGINS=${origins}` : ''
459
527
  ].filter(Boolean);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.1.18-beta.2",
3
+ "version": "2.1.18-beta.4",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "MIT",
6
6
  "main": "server/index.js",
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"425cfb54d01a9472b3e81d9e76fd63a4a44cfb
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "102737039" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "474089705" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });