neoagent 2.1.17 → 2.1.18-beta.1
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 +6 -0
- package/docs/configuration.md +3 -0
- package/package.json +2 -1
- package/server/db/database.js +160 -0
- package/server/http/routes.js +1 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +61627 -61079
- package/server/routes/integrations.js +127 -0
- package/server/routes/store.js +2 -121
- package/server/services/ai/capabilityHealth.js +25 -0
- package/server/services/ai/engine.js +9 -1
- package/server/services/ai/tools.js +15 -0
- package/server/services/commands/router.js +6 -3
- package/server/services/integrations/env.js +51 -0
- package/server/services/integrations/google/calendar.js +244 -0
- package/server/services/integrations/google/common.js +106 -0
- package/server/services/integrations/google/docs.js +163 -0
- package/server/services/integrations/google/drive.js +198 -0
- package/server/services/integrations/google/gmail.js +293 -0
- package/server/services/integrations/google/provider.js +409 -0
- package/server/services/integrations/google/sheets.js +158 -0
- package/server/services/integrations/manager.js +395 -0
- package/server/services/integrations/registry.js +21 -0
- package/server/services/manager.js +13 -0
- package/server/services/websocket.js +11 -1
package/.env.example
CHANGED
|
@@ -27,6 +27,12 @@ OPENAI_API_KEY=your-openai-api-key-here
|
|
|
27
27
|
# Get your key at: https://aistudio.google.com/app/apikey
|
|
28
28
|
GOOGLE_AI_KEY=your-google-ai-key-here
|
|
29
29
|
|
|
30
|
+
# Google Workspace official integration OAuth client
|
|
31
|
+
# Redirect URI should match ${PUBLIC_URL:-http://localhost:3333}/api/integrations/oauth/callback
|
|
32
|
+
GOOGLE_OAUTH_CLIENT_ID=your-google-oauth-client-id
|
|
33
|
+
GOOGLE_OAUTH_CLIENT_SECRET=your-google-oauth-client-secret
|
|
34
|
+
# GOOGLE_OAUTH_REDIRECT_URI=http://localhost:3333/api/integrations/oauth/callback
|
|
35
|
+
|
|
30
36
|
# Brave Search API key — used for:
|
|
31
37
|
# • Native web_search tool (search the web without driving the browser)
|
|
32
38
|
# Get your key at: https://api.search.brave.com/
|
package/docs/configuration.md
CHANGED
|
@@ -25,6 +25,9 @@ At least one API key is required. The active provider and model are configured i
|
|
|
25
25
|
| `OPENAI_API_KEY` | GPT-4o / Whisper (OpenAI) |
|
|
26
26
|
| `XAI_API_KEY` | Grok (xAI) |
|
|
27
27
|
| `GOOGLE_AI_KEY` | Gemini (Google) |
|
|
28
|
+
| `GOOGLE_OAUTH_CLIENT_ID` | Google Workspace official integrations OAuth client ID |
|
|
29
|
+
| `GOOGLE_OAUTH_CLIENT_SECRET` | Google Workspace official integrations OAuth client secret |
|
|
30
|
+
| `GOOGLE_OAUTH_REDIRECT_URI` | Optional override for the Google Workspace OAuth callback URL |
|
|
28
31
|
| `MINIMAX_API_KEY` | MiniMax Code (Coding Plan / Token Plan for `MiniMax-M2.7`) |
|
|
29
32
|
| `BRAVE_SEARCH_API_KEY` | Brave Search API for the native `web_search` tool |
|
|
30
33
|
| `DEEPGRAM_API_KEY` | Recordings transcription with Deepgram Nova-3 multilingual |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neoagent",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.18-beta.1",
|
|
4
4
|
"description": "Proactive personal AI agent with no limits",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "server/index.js",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"express": "^4.21.2",
|
|
56
56
|
"express-rate-limit": "^7.5.0",
|
|
57
57
|
"express-session": "^1.18.1",
|
|
58
|
+
"googleapis": "^150.0.1",
|
|
58
59
|
"helmet": "^8.0.0",
|
|
59
60
|
"multer": "^1.4.5-lts.1",
|
|
60
61
|
"node-cron": "^3.0.3",
|
package/server/db/database.js
CHANGED
|
@@ -108,6 +108,35 @@ db.exec(`
|
|
|
108
108
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
109
109
|
);
|
|
110
110
|
|
|
111
|
+
CREATE TABLE IF NOT EXISTS integration_connections (
|
|
112
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
113
|
+
user_id INTEGER NOT NULL,
|
|
114
|
+
provider_key TEXT NOT NULL,
|
|
115
|
+
app_key TEXT NOT NULL DEFAULT 'default',
|
|
116
|
+
status TEXT DEFAULT 'not_connected',
|
|
117
|
+
account_email TEXT,
|
|
118
|
+
scopes_json TEXT DEFAULT '[]',
|
|
119
|
+
credentials_json TEXT DEFAULT '{}',
|
|
120
|
+
metadata_json TEXT DEFAULT '{}',
|
|
121
|
+
last_connected_at TEXT,
|
|
122
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
123
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
124
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
125
|
+
UNIQUE(user_id, provider_key, app_key, account_email)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
CREATE TABLE IF NOT EXISTS integration_oauth_states (
|
|
129
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
130
|
+
user_id INTEGER NOT NULL,
|
|
131
|
+
provider_key TEXT NOT NULL,
|
|
132
|
+
app_key TEXT NOT NULL DEFAULT 'default',
|
|
133
|
+
state TEXT NOT NULL UNIQUE,
|
|
134
|
+
code_verifier TEXT NOT NULL,
|
|
135
|
+
expires_at TEXT NOT NULL,
|
|
136
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
137
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
138
|
+
);
|
|
139
|
+
|
|
111
140
|
CREATE TABLE IF NOT EXISTS scheduled_tasks (
|
|
112
141
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
113
142
|
user_id INTEGER NOT NULL,
|
|
@@ -173,6 +202,8 @@ db.exec(`
|
|
|
173
202
|
CREATE INDEX IF NOT EXISTS idx_agent_runs_user ON agent_runs(user_id, created_at DESC);
|
|
174
203
|
CREATE INDEX IF NOT EXISTS idx_agent_runs_status ON agent_runs(status);
|
|
175
204
|
CREATE INDEX IF NOT EXISTS idx_agent_steps_run ON agent_steps(run_id, step_index);
|
|
205
|
+
CREATE INDEX IF NOT EXISTS idx_integration_connections_user ON integration_connections(user_id, provider_key, app_key);
|
|
206
|
+
CREATE INDEX IF NOT EXISTS idx_integration_oauth_states_state ON integration_oauth_states(state);
|
|
176
207
|
CREATE INDEX IF NOT EXISTS idx_messages_user ON messages(user_id, created_at DESC);
|
|
177
208
|
CREATE INDEX IF NOT EXISTS idx_messages_platform ON messages(platform, platform_chat_id);
|
|
178
209
|
CREATE INDEX IF NOT EXISTS idx_conv_messages ON conversation_messages(conversation_id, created_at);
|
|
@@ -424,6 +455,135 @@ for (const col of [
|
|
|
424
455
|
try { db.exec(col); } catch { /* column already exists */ }
|
|
425
456
|
}
|
|
426
457
|
|
|
458
|
+
function tableHasColumn(tableName, columnName) {
|
|
459
|
+
try {
|
|
460
|
+
return db
|
|
461
|
+
.prepare(`PRAGMA table_info(${tableName})`)
|
|
462
|
+
.all()
|
|
463
|
+
.some((column) => column.name === columnName);
|
|
464
|
+
} catch {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function parseIntegrationMetadata(metadataJson) {
|
|
470
|
+
try {
|
|
471
|
+
const parsed = JSON.parse(metadataJson || '{}');
|
|
472
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
473
|
+
} catch {
|
|
474
|
+
return {};
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function migrateIntegrationConnectionsTable() {
|
|
479
|
+
if (tableHasColumn('integration_connections', 'app_key')) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const legacyRows = db
|
|
484
|
+
.prepare('SELECT * FROM integration_connections ORDER BY id ASC')
|
|
485
|
+
.all();
|
|
486
|
+
|
|
487
|
+
db.exec(`
|
|
488
|
+
ALTER TABLE integration_connections RENAME TO integration_connections_legacy;
|
|
489
|
+
|
|
490
|
+
CREATE TABLE integration_connections (
|
|
491
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
492
|
+
user_id INTEGER NOT NULL,
|
|
493
|
+
provider_key TEXT NOT NULL,
|
|
494
|
+
app_key TEXT NOT NULL DEFAULT 'default',
|
|
495
|
+
status TEXT DEFAULT 'not_connected',
|
|
496
|
+
account_email TEXT,
|
|
497
|
+
scopes_json TEXT DEFAULT '[]',
|
|
498
|
+
credentials_json TEXT DEFAULT '{}',
|
|
499
|
+
metadata_json TEXT DEFAULT '{}',
|
|
500
|
+
last_connected_at TEXT,
|
|
501
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
502
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
503
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
504
|
+
UNIQUE(user_id, provider_key, app_key, account_email)
|
|
505
|
+
);
|
|
506
|
+
`);
|
|
507
|
+
|
|
508
|
+
const insert = db.prepare(`
|
|
509
|
+
INSERT OR REPLACE INTO integration_connections (
|
|
510
|
+
user_id,
|
|
511
|
+
provider_key,
|
|
512
|
+
app_key,
|
|
513
|
+
status,
|
|
514
|
+
account_email,
|
|
515
|
+
scopes_json,
|
|
516
|
+
credentials_json,
|
|
517
|
+
metadata_json,
|
|
518
|
+
last_connected_at,
|
|
519
|
+
created_at,
|
|
520
|
+
updated_at
|
|
521
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
522
|
+
`);
|
|
523
|
+
|
|
524
|
+
const legacyGoogleApps = ['gmail', 'calendar', 'drive', 'docs', 'sheets'];
|
|
525
|
+
for (const row of legacyRows) {
|
|
526
|
+
const metadata = parseIntegrationMetadata(row.metadata_json);
|
|
527
|
+
const appIds = Array.isArray(metadata.apps)
|
|
528
|
+
? metadata.apps
|
|
529
|
+
.map((item) => String(item || '').trim())
|
|
530
|
+
.filter(Boolean)
|
|
531
|
+
: row.provider_key === 'google_workspace'
|
|
532
|
+
? legacyGoogleApps
|
|
533
|
+
: ['default'];
|
|
534
|
+
|
|
535
|
+
for (const appId of appIds) {
|
|
536
|
+
insert.run(
|
|
537
|
+
row.user_id,
|
|
538
|
+
row.provider_key,
|
|
539
|
+
appId,
|
|
540
|
+
row.status || 'not_connected',
|
|
541
|
+
row.account_email || null,
|
|
542
|
+
row.scopes_json || '[]',
|
|
543
|
+
row.credentials_json || '{}',
|
|
544
|
+
row.metadata_json || '{}',
|
|
545
|
+
row.last_connected_at || null,
|
|
546
|
+
row.created_at || null,
|
|
547
|
+
row.updated_at || null,
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
db.exec(`
|
|
553
|
+
DROP TABLE integration_connections_legacy;
|
|
554
|
+
DROP INDEX IF EXISTS idx_integration_connections_user;
|
|
555
|
+
CREATE INDEX IF NOT EXISTS idx_integration_connections_user
|
|
556
|
+
ON integration_connections(user_id, provider_key, app_key);
|
|
557
|
+
`);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function migrateIntegrationOauthStatesTable() {
|
|
561
|
+
if (tableHasColumn('integration_oauth_states', 'app_key')) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
db.exec(`
|
|
566
|
+
ALTER TABLE integration_oauth_states RENAME TO integration_oauth_states_legacy;
|
|
567
|
+
|
|
568
|
+
CREATE TABLE integration_oauth_states (
|
|
569
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
570
|
+
user_id INTEGER NOT NULL,
|
|
571
|
+
provider_key TEXT NOT NULL,
|
|
572
|
+
app_key TEXT NOT NULL DEFAULT 'default',
|
|
573
|
+
state TEXT NOT NULL UNIQUE,
|
|
574
|
+
code_verifier TEXT NOT NULL,
|
|
575
|
+
expires_at TEXT NOT NULL,
|
|
576
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
577
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
DROP TABLE integration_oauth_states_legacy;
|
|
581
|
+
`);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
migrateIntegrationConnectionsTable();
|
|
585
|
+
migrateIntegrationOauthStatesTable();
|
|
586
|
+
|
|
427
587
|
try {
|
|
428
588
|
db.exec(`
|
|
429
589
|
INSERT OR REPLACE INTO conversation_history_fts(rowid, content, role, user_id, agent_run_id)
|
package/server/http/routes.js
CHANGED
|
@@ -10,6 +10,7 @@ const routeRegistry = [
|
|
|
10
10
|
{ basePath: '/api/agents', modulePath: '../routes/agents' },
|
|
11
11
|
{ basePath: '/api/messaging', modulePath: '../routes/messaging' },
|
|
12
12
|
{ basePath: '/api/mcp', modulePath: '../routes/mcp' },
|
|
13
|
+
{ basePath: '/api/integrations', modulePath: '../routes/integrations' },
|
|
13
14
|
{ basePath: '/api/skills', modulePath: '../routes/skills' },
|
|
14
15
|
{ basePath: '/api/store', modulePath: '../routes/store' },
|
|
15
16
|
{ basePath: '/api/memory', modulePath: '../routes/memory' },
|
|
Binary file
|
|
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"425cfb54d01a9472b3e81d9e76fd63a4a44cfb
|
|
|
37
37
|
|
|
38
38
|
_flutter.loader.load({
|
|
39
39
|
serviceWorkerSettings: {
|
|
40
|
-
serviceWorkerVersion: "
|
|
40
|
+
serviceWorkerVersion: "3396890130" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
|
41
41
|
}
|
|
42
42
|
});
|