neoagent 2.4.2-beta.5 → 2.4.2-beta.7
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/README.md +48 -18
- package/flutter_app/lib/main_controller.dart +0 -1
- package/flutter_app/lib/main_models.dart +28 -0
- package/flutter_app/lib/main_operations.dart +1 -1
- package/flutter_app/lib/main_settings.dart +9 -14
- package/flutter_app/lib/main_shared.dart +0 -9
- package/flutter_app/lib/main_unified.dart +0 -2
- package/flutter_app/lib/src/backend_client.dart +8 -0
- package/package.json +1 -1
- package/server/db/database.js +112 -0
- package/server/http/routes.js +1 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/flutter_bootstrap.js +2 -2
- package/server/public/main.dart.js +10083 -10063
- package/server/routes/mcp.js +9 -0
- package/server/routes/memory.js +35 -2
- package/server/routes/runtime.js +7 -1
- package/server/routes/settings.js +34 -1
- package/server/routes/skills.js +42 -0
- package/server/routes/task_webhooks.js +65 -0
- package/server/services/ai/engine.js +525 -24
- package/server/services/ai/learning.js +56 -8
- package/server/services/ai/providers/anthropic.js +40 -8
- package/server/services/ai/providers/google.js +10 -0
- package/server/services/ai/providers/openai.js +3 -15
- package/server/services/ai/providers/openaiCompatible.js +11 -0
- package/server/services/ai/repetitionGuard.js +60 -0
- package/server/services/ai/systemPrompt.js +52 -16
- package/server/services/ai/taskAnalysis.js +15 -6
- package/server/services/ai/toolEvidence.js +3 -1
- package/server/services/ai/toolRunner.js +43 -1
- package/server/services/ai/toolSelector.js +92 -46
- package/server/services/ai/tools.js +89 -9
- package/server/services/ai/usage.js +114 -0
- package/server/services/manager.js +34 -0
- package/server/services/memory/manager.js +170 -4
- package/server/services/security/capability_audit.js +107 -0
- package/server/services/tasks/adapters/index.js +1 -0
- package/server/services/tasks/adapters/webhook.js +14 -0
- package/server/services/tasks/runtime.js +1 -1
- package/server/services/tasks/webhooks.js +146 -0
- package/server/services/workspace/code_navigation.js +194 -0
- package/server/services/workspace/structured_data.js +93 -0
- package/server/utils/cloud-security.js +24 -2
package/README.md
CHANGED
|
@@ -6,53 +6,83 @@
|
|
|
6
6
|
|
|
7
7
|
<p align="center"><strong>Your agent. Your server. Your rules.</strong></p>
|
|
8
8
|
|
|
9
|
+
<p align="center">A self-hosted AI agent that runs as a service, operates Android over ADB, and connects to 15+ messaging platforms while keeping credentials on your server.</p>
|
|
10
|
+
|
|
9
11
|
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/neoagent"><img src="https://img.shields.io/npm/v/neoagent?style=flat-square&label=npm" alt="npm version"></a>
|
|
10
13
|
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node.js-20+-5fa04e?style=flat-square&logo=node.js&logoColor=white" alt="Node.js"></a>
|
|
11
14
|
<a href="https://sqlite.org"><img src="https://img.shields.io/badge/SQLite-WAL-003b57?style=flat-square&logo=sqlite&logoColor=white" alt="SQLite"></a>
|
|
12
15
|
<a href="https://flutter.dev"><img src="https://img.shields.io/badge/Flutter-web%20%2B%20android-02569B?style=flat-square&logo=flutter&logoColor=white" alt="Flutter"></a>
|
|
13
16
|
<a href="LICENSE"><img src="https://img.shields.io/badge/License-AGPL--3.0-a855f7?style=flat-square" alt="License"></a>
|
|
14
17
|
</p>
|
|
15
18
|
|
|
16
|
-
<p align="center">Self-hosted AI agent — runs as a system service, controls Android over ADB, connects to 15+ messaging platforms, all credentials on your server.</p>
|
|
17
|
-
|
|
18
19
|
<p align="center">
|
|
19
20
|
<img src="demo.gif" alt="NeoAgent demo" width="100%">
|
|
20
21
|
</p>
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
| --- | --- | --- | --- |
|
|
24
|
-
| <img alt="WebUI" src="https://github.com/user-attachments/assets/3c76d59a-b6e3-4698-929b-9c94741ccf1e" height="420"> | <img height="494" alt="Android" src="https://github.com/user-attachments/assets/e8a0af7a-6881-485d-ad52-f3bc6f2023ca"> | <img alt="Mobile Telegram" src="https://github.com/user-attachments/assets/1fd41a9b-5452-4aa4-9478-888c8ad7363a" height="420"> | <img height="494" alt="image" src="https://github.com/user-attachments/assets/d5a57282-0851-4902-9588-d8de4b82d45c"> |
|
|
23
|
+
## Why NeoAgent
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- **Browser + shell** — VM-isolated server-side browser automation, full PTY terminal
|
|
30
|
-
- **Runs locally** — Ollama support, no API key required; credentials stay in `~/.neoagent/.env`, never in the client
|
|
25
|
+
| Android that the agent can operate | Credentials that stay server-side |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| NeoAgent can inspect the UI, take screenshots, tap, swipe, type, launch apps, install APKs, and run `adb shell` against a connected device or emulator. | API keys, OAuth tokens, messaging credentials, history, and runtime data are stored under `~/.neoagent` on the server, never in the client. |
|
|
31
28
|
|
|
32
|
-
##
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
Requires Node.js 20 or newer.
|
|
33
32
|
|
|
34
33
|
```bash
|
|
35
34
|
npm install -g neoagent
|
|
36
35
|
neoagent install
|
|
37
36
|
```
|
|
38
37
|
|
|
39
|
-
`neoagent install`
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
`neoagent install` checks the host, creates secure runtime configuration,
|
|
39
|
+
installs dependencies and supported system tools, and starts the service. Open
|
|
40
|
+
**http://localhost:3333** when it finishes.
|
|
41
|
+
|
|
42
|
+
No hosted-model key is required when using local [Ollama](https://ollama.com/).
|
|
43
|
+
See [Getting Started](docs/getting-started.md) for prerequisites and first-run
|
|
44
|
+
setup.
|
|
45
|
+
|
|
46
|
+
## What It Does
|
|
47
|
+
|
|
48
|
+
- **15+ messaging platforms**: Telegram, WhatsApp, Discord, Signal, Slack, Matrix, iMessage, Teams, IRC, LINE, Mattermost, Telnyx Voice, and webhook bridges.
|
|
49
|
+
- **Automation**: cron schedules, integration and weather triggers, reusable skills, MCP tools, and subagents.
|
|
50
|
+
- **Browser and shell**: an isolated browser runtime plus a full PTY terminal on the NeoAgent server.
|
|
51
|
+
- **Integrations**: Google Workspace, Microsoft 365, Notion, Home Assistant, Trello, Spotify, Slack, Figma, GitHub, and more.
|
|
52
|
+
- **Recordings and memory**: audio capture, transcription, transcript search, long-term memory, session history, and health summaries.
|
|
53
|
+
- **Model choice**: Anthropic, OpenAI, Gemini, Grok, MiniMax, NVIDIA NIM, OpenRouter, GitHub Copilot, OpenAI Codex, or local Ollama.
|
|
43
54
|
|
|
44
|
-
##
|
|
55
|
+
## Interfaces
|
|
56
|
+
|
|
57
|
+
| | | | |
|
|
58
|
+
| --- | --- | --- | --- |
|
|
59
|
+
| <img alt="WebUI" src="https://github.com/user-attachments/assets/3c76d59a-b6e3-4698-929b-9c94741ccf1e" height="420"> | <img height="494" alt="Android" src="https://github.com/user-attachments/assets/e8a0af7a-6881-485d-ad52-f3bc6f2023ca"> | <img alt="Mobile Telegram" src="https://github.com/user-attachments/assets/1fd41a9b-5452-4aa4-9478-888c8ad7363a" height="420"> | <img height="494" alt="image" src="https://github.com/user-attachments/assets/d5a57282-0851-4902-9588-d8de4b82d45c"> |
|
|
60
|
+
|
|
61
|
+
## Service Commands
|
|
45
62
|
|
|
46
63
|
```bash
|
|
47
64
|
neoagent status
|
|
65
|
+
neoagent start
|
|
66
|
+
neoagent stop
|
|
67
|
+
neoagent restart
|
|
48
68
|
neoagent update
|
|
49
69
|
neoagent fix
|
|
50
70
|
neoagent logs
|
|
51
71
|
```
|
|
52
72
|
|
|
53
|
-
##
|
|
73
|
+
## Project Status
|
|
74
|
+
|
|
75
|
+
NeoAgent is beta software maintained by one person. Expect rough edges, and
|
|
76
|
+
please report failures with enough detail to reproduce them. Contributions to
|
|
77
|
+
the backend, Flutter clients, integrations, skills, tests, and documentation
|
|
78
|
+
are welcome.
|
|
79
|
+
|
|
80
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. Security
|
|
81
|
+
issues should be reported privately according to [SECURITY.md](SECURITY.md).
|
|
82
|
+
|
|
83
|
+
## Documentation
|
|
54
84
|
|
|
55
|
-
[Docs](https://neolabs-systems.github.io/NeoAgent/docs/) | [Getting Started](docs/getting-started.md) | [Configuration](docs/configuration.md) | [Capabilities](docs/capabilities.md) | [
|
|
85
|
+
[Docs](https://neolabs-systems.github.io/NeoAgent/docs/) | [Getting Started](docs/getting-started.md) | [Configuration](docs/configuration.md) | [Capabilities](docs/capabilities.md) | [Skills and MCP](docs/skills.md) | [Operations](docs/operations.md) | [Discussions](https://github.com/NeoLabs-Systems/NeoAgent/discussions) | [Issues](https://github.com/NeoLabs-Systems/NeoAgent/issues)
|
|
56
86
|
|
|
57
87
|
---
|
|
58
88
|
|
|
@@ -1658,7 +1658,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1658
1658
|
}
|
|
1659
1659
|
|
|
1660
1660
|
void setSelectedSection(AppSection section) {
|
|
1661
|
-
final previousSection = selectedSection;
|
|
1662
1661
|
selectedSection = section;
|
|
1663
1662
|
unawaited(_prefs?.setString(_selectedSectionPrefsKey, section.name));
|
|
1664
1663
|
if (section == AppSection.devices) {
|
|
@@ -2059,6 +2059,7 @@ class ModelMeta {
|
|
|
2059
2059
|
final bool available;
|
|
2060
2060
|
final String providerStatus;
|
|
2061
2061
|
final String providerStatusLabel;
|
|
2062
|
+
|
|
2062
2063
|
/// Pricing tier: 'free' | 'cheap' | 'medium' | 'expensive' | null (unknown)
|
|
2063
2064
|
final String? priceTier;
|
|
2064
2065
|
}
|
|
@@ -2308,18 +2309,33 @@ class TokenUsageSnapshot {
|
|
|
2308
2309
|
required this.avgTokensPerRun,
|
|
2309
2310
|
required this.last7DaysTokens,
|
|
2310
2311
|
required this.last7DaysRuns,
|
|
2312
|
+
required this.cachedReadTokens,
|
|
2313
|
+
required this.cacheWriteTokens,
|
|
2314
|
+
required this.reasoningTokens,
|
|
2315
|
+
required this.modelCallCount,
|
|
2316
|
+
required this.cacheHitRatio,
|
|
2317
|
+
this.estimatedCostUsd,
|
|
2311
2318
|
});
|
|
2312
2319
|
|
|
2313
2320
|
factory TokenUsageSnapshot.fromJson(Map<dynamic, dynamic> json) {
|
|
2314
2321
|
final totals = json['totals'] is Map
|
|
2315
2322
|
? Map<String, dynamic>.from(json['totals'] as Map)
|
|
2316
2323
|
: const <String, dynamic>{};
|
|
2324
|
+
final modelUsage = json['modelUsage'] is Map
|
|
2325
|
+
? Map<String, dynamic>.from(json['modelUsage'] as Map)
|
|
2326
|
+
: const <String, dynamic>{};
|
|
2317
2327
|
return TokenUsageSnapshot(
|
|
2318
2328
|
totalTokens: _asInt(totals['totalTokens']),
|
|
2319
2329
|
totalRuns: _asInt(totals['totalRuns']),
|
|
2320
2330
|
avgTokensPerRun: _asInt(totals['avgTokensPerRun']),
|
|
2321
2331
|
last7DaysTokens: _asInt(totals['last7DaysTokens']),
|
|
2322
2332
|
last7DaysRuns: _asInt(totals['last7DaysRuns']),
|
|
2333
|
+
cachedReadTokens: _asInt(modelUsage['cachedReadTokens']),
|
|
2334
|
+
cacheWriteTokens: _asInt(modelUsage['cacheWriteTokens']),
|
|
2335
|
+
reasoningTokens: _asInt(modelUsage['reasoningTokens']),
|
|
2336
|
+
modelCallCount: _asInt(modelUsage['callCount']),
|
|
2337
|
+
cacheHitRatio: (modelUsage['cacheHitRatio'] as num?)?.toDouble() ?? 0,
|
|
2338
|
+
estimatedCostUsd: (modelUsage['estimatedCostUsd'] as num?)?.toDouble(),
|
|
2323
2339
|
);
|
|
2324
2340
|
}
|
|
2325
2341
|
|
|
@@ -2328,12 +2344,24 @@ class TokenUsageSnapshot {
|
|
|
2328
2344
|
final int avgTokensPerRun;
|
|
2329
2345
|
final int last7DaysTokens;
|
|
2330
2346
|
final int last7DaysRuns;
|
|
2347
|
+
final int cachedReadTokens;
|
|
2348
|
+
final int cacheWriteTokens;
|
|
2349
|
+
final int reasoningTokens;
|
|
2350
|
+
final int modelCallCount;
|
|
2351
|
+
final double cacheHitRatio;
|
|
2352
|
+
final double? estimatedCostUsd;
|
|
2331
2353
|
|
|
2332
2354
|
String get totalTokensLabel => _formatNumber(totalTokens);
|
|
2333
2355
|
String get totalRunsLabel => _formatNumber(totalRuns);
|
|
2334
2356
|
String get avgTokensPerRunLabel => _formatNumber(avgTokensPerRun);
|
|
2335
2357
|
String get last7DaysTokensLabel => _formatNumber(last7DaysTokens);
|
|
2336
2358
|
String get last7DaysRunsLabel => _formatNumber(last7DaysRuns);
|
|
2359
|
+
String get cachedReadTokensLabel => _formatNumber(cachedReadTokens);
|
|
2360
|
+
String get cacheHitRatioLabel =>
|
|
2361
|
+
'${(cacheHitRatio * 100).toStringAsFixed(1)}%';
|
|
2362
|
+
String get estimatedCostLabel => estimatedCostUsd == null
|
|
2363
|
+
? 'Unknown'
|
|
2364
|
+
: '\$${estimatedCostUsd!.toStringAsFixed(4)}';
|
|
2337
2365
|
}
|
|
2338
2366
|
|
|
2339
2367
|
class UpdateStatusSnapshot {
|
|
@@ -5629,7 +5629,7 @@ class _TasksPanelState extends State<TasksPanel> {
|
|
|
5629
5629
|
);
|
|
5630
5630
|
}
|
|
5631
5631
|
return DropdownButtonFormField<int>(
|
|
5632
|
-
|
|
5632
|
+
initialValue: accounts.any((a) => a.id == selectedConnectionId.value)
|
|
5633
5633
|
? selectedConnectionId.value
|
|
5634
5634
|
: null,
|
|
5635
5635
|
isExpanded: true,
|
|
@@ -489,20 +489,6 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
489
489
|
);
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
-
Widget _inlineProgressIndicator() {
|
|
493
|
-
return SizedBox(
|
|
494
|
-
width: 28,
|
|
495
|
-
child: ClipRRect(
|
|
496
|
-
borderRadius: BorderRadius.circular(999),
|
|
497
|
-
child: LinearProgressIndicator(
|
|
498
|
-
minHeight: 3,
|
|
499
|
-
backgroundColor: Colors.white.withValues(alpha: 0.28),
|
|
500
|
-
color: Colors.white,
|
|
501
|
-
),
|
|
502
|
-
),
|
|
503
|
-
);
|
|
504
|
-
}
|
|
505
|
-
|
|
506
492
|
Widget _buildSettingsOverview(
|
|
507
493
|
NeoAgentController controller,
|
|
508
494
|
int availableModelCount,
|
|
@@ -1546,6 +1532,15 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
1546
1532
|
Text(
|
|
1547
1533
|
'Avg/run: ${controller.tokenUsage!.avgTokensPerRunLabel} tokens',
|
|
1548
1534
|
),
|
|
1535
|
+
const SizedBox(height: 6),
|
|
1536
|
+
Text(
|
|
1537
|
+
'Prompt cache: ${controller.tokenUsage!.cachedReadTokensLabel} cached tokens '
|
|
1538
|
+
'(${controller.tokenUsage!.cacheHitRatioLabel} hit ratio)',
|
|
1539
|
+
),
|
|
1540
|
+
const SizedBox(height: 6),
|
|
1541
|
+
Text(
|
|
1542
|
+
'Measured model cost: ${controller.tokenUsage!.estimatedCostLabel}',
|
|
1543
|
+
),
|
|
1549
1544
|
],
|
|
1550
1545
|
),
|
|
1551
1546
|
],
|
|
@@ -3440,15 +3440,6 @@ String _modelLabelForValue(String value, List<ModelMeta> models) {
|
|
|
3440
3440
|
return value;
|
|
3441
3441
|
}
|
|
3442
3442
|
|
|
3443
|
-
String _friendlyBaseUrlLabel(String value) {
|
|
3444
|
-
final uri = Uri.tryParse(value);
|
|
3445
|
-
if (uri == null || uri.host.trim().isEmpty) {
|
|
3446
|
-
return value;
|
|
3447
|
-
}
|
|
3448
|
-
final port = uri.hasPort ? ':${uri.port}' : '';
|
|
3449
|
-
return '${uri.host}$port';
|
|
3450
|
-
}
|
|
3451
|
-
|
|
3452
3443
|
String? _androidRuntimeVersionLabel(Map<String, dynamic> runtime) {
|
|
3453
3444
|
final apiLevel = _asInt(runtime['apiLevel']);
|
|
3454
3445
|
final systemImage = runtime['systemImage']?.toString().trim() ?? '';
|
|
@@ -1055,6 +1055,14 @@ class BackendClient {
|
|
|
1055
1055
|
return getList(baseUrl, '/api/skills');
|
|
1056
1056
|
}
|
|
1057
1057
|
|
|
1058
|
+
Future<List<Map<String, dynamic>>> fetchSkillMetrics(String baseUrl) {
|
|
1059
|
+
return getList(baseUrl, '/api/skills/metrics/summary');
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
Future<List<Map<String, dynamic>>> fetchSkillAudit(String baseUrl) {
|
|
1063
|
+
return getList(baseUrl, '/api/skills/audit/summary');
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1058
1066
|
Future<List<Map<String, dynamic>>> fetchSkillStore(String baseUrl) async {
|
|
1059
1067
|
return getList(baseUrl, '/api/store');
|
|
1060
1068
|
}
|
package/package.json
CHANGED
package/server/db/database.js
CHANGED
|
@@ -764,6 +764,112 @@ db.exec(`
|
|
|
764
764
|
CREATE INDEX IF NOT EXISTS idx_agent_run_events_run ON agent_run_events(run_id, sequence_index, id);
|
|
765
765
|
CREATE INDEX IF NOT EXISTS idx_agent_run_events_user ON agent_run_events(user_id, created_at DESC);
|
|
766
766
|
|
|
767
|
+
CREATE TABLE IF NOT EXISTS agent_model_usage (
|
|
768
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
769
|
+
run_id TEXT NOT NULL,
|
|
770
|
+
step_id TEXT,
|
|
771
|
+
user_id INTEGER NOT NULL,
|
|
772
|
+
agent_id TEXT,
|
|
773
|
+
provider TEXT NOT NULL,
|
|
774
|
+
model TEXT NOT NULL,
|
|
775
|
+
phase TEXT DEFAULT 'model_turn',
|
|
776
|
+
input_tokens INTEGER DEFAULT 0,
|
|
777
|
+
output_tokens INTEGER DEFAULT 0,
|
|
778
|
+
reasoning_tokens INTEGER DEFAULT 0,
|
|
779
|
+
cached_read_tokens INTEGER DEFAULT 0,
|
|
780
|
+
cache_write_tokens INTEGER DEFAULT 0,
|
|
781
|
+
total_tokens INTEGER DEFAULT 0,
|
|
782
|
+
estimated_cost_usd REAL,
|
|
783
|
+
latency_ms INTEGER DEFAULT 0,
|
|
784
|
+
metadata_json TEXT DEFAULT '{}',
|
|
785
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
786
|
+
FOREIGN KEY (run_id) REFERENCES agent_runs(id) ON DELETE CASCADE,
|
|
787
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
788
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL,
|
|
789
|
+
FOREIGN KEY (step_id) REFERENCES agent_steps(id) ON DELETE SET NULL
|
|
790
|
+
);
|
|
791
|
+
|
|
792
|
+
CREATE INDEX IF NOT EXISTS idx_agent_model_usage_run ON agent_model_usage(run_id, id);
|
|
793
|
+
CREATE INDEX IF NOT EXISTS idx_agent_model_usage_user ON agent_model_usage(user_id, created_at DESC);
|
|
794
|
+
|
|
795
|
+
CREATE TABLE IF NOT EXISTS workspace_code_index (
|
|
796
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
797
|
+
user_id INTEGER NOT NULL,
|
|
798
|
+
path TEXT NOT NULL,
|
|
799
|
+
symbol TEXT,
|
|
800
|
+
symbol_type TEXT,
|
|
801
|
+
start_line INTEGER,
|
|
802
|
+
end_line INTEGER,
|
|
803
|
+
content TEXT NOT NULL,
|
|
804
|
+
content_hash TEXT NOT NULL,
|
|
805
|
+
embedding TEXT,
|
|
806
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
807
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
808
|
+
UNIQUE(user_id, path, symbol, start_line)
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
CREATE INDEX IF NOT EXISTS idx_workspace_code_index_user
|
|
812
|
+
ON workspace_code_index(user_id, path);
|
|
813
|
+
|
|
814
|
+
CREATE TABLE IF NOT EXISTS task_webhook_deliveries (
|
|
815
|
+
id TEXT PRIMARY KEY,
|
|
816
|
+
task_id INTEGER NOT NULL,
|
|
817
|
+
user_id INTEGER NOT NULL,
|
|
818
|
+
request_id TEXT NOT NULL,
|
|
819
|
+
payload_hash TEXT NOT NULL,
|
|
820
|
+
status TEXT NOT NULL DEFAULT 'accepted',
|
|
821
|
+
response_json TEXT DEFAULT '{}',
|
|
822
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
823
|
+
completed_at TEXT,
|
|
824
|
+
FOREIGN KEY (task_id) REFERENCES scheduled_tasks(id) ON DELETE CASCADE,
|
|
825
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
826
|
+
UNIQUE(task_id, request_id)
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
CREATE TABLE IF NOT EXISTS task_webhook_secrets (
|
|
830
|
+
task_id INTEGER PRIMARY KEY,
|
|
831
|
+
user_id INTEGER NOT NULL,
|
|
832
|
+
secret_encrypted TEXT NOT NULL,
|
|
833
|
+
secret_fingerprint TEXT NOT NULL,
|
|
834
|
+
rotated_at TEXT DEFAULT (datetime('now')),
|
|
835
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
836
|
+
FOREIGN KEY (task_id) REFERENCES scheduled_tasks(id) ON DELETE CASCADE,
|
|
837
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
838
|
+
);
|
|
839
|
+
|
|
840
|
+
CREATE INDEX IF NOT EXISTS idx_task_webhook_deliveries_task
|
|
841
|
+
ON task_webhook_deliveries(task_id, created_at DESC);
|
|
842
|
+
|
|
843
|
+
CREATE TABLE IF NOT EXISTS skill_metrics (
|
|
844
|
+
user_id INTEGER NOT NULL,
|
|
845
|
+
agent_id TEXT,
|
|
846
|
+
skill_name TEXT NOT NULL,
|
|
847
|
+
invocation_count INTEGER DEFAULT 0,
|
|
848
|
+
success_count INTEGER DEFAULT 0,
|
|
849
|
+
failure_count INTEGER DEFAULT 0,
|
|
850
|
+
correction_count INTEGER DEFAULT 0,
|
|
851
|
+
total_tokens INTEGER DEFAULT 0,
|
|
852
|
+
last_used_at TEXT,
|
|
853
|
+
metadata_json TEXT DEFAULT '{}',
|
|
854
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
855
|
+
PRIMARY KEY (user_id, agent_id, skill_name),
|
|
856
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
857
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL
|
|
858
|
+
);
|
|
859
|
+
|
|
860
|
+
CREATE TABLE IF NOT EXISTS skill_workflow_observations (
|
|
861
|
+
user_id INTEGER NOT NULL,
|
|
862
|
+
agent_id TEXT NOT NULL,
|
|
863
|
+
workflow_signature TEXT NOT NULL,
|
|
864
|
+
observation_count INTEGER DEFAULT 0,
|
|
865
|
+
latest_run_id TEXT,
|
|
866
|
+
first_observed_at TEXT DEFAULT (datetime('now')),
|
|
867
|
+
last_observed_at TEXT DEFAULT (datetime('now')),
|
|
868
|
+
PRIMARY KEY (user_id, agent_id, workflow_signature),
|
|
869
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
870
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE CASCADE
|
|
871
|
+
);
|
|
872
|
+
|
|
767
873
|
CREATE TABLE IF NOT EXISTS agent_settings (
|
|
768
874
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
769
875
|
user_id INTEGER NOT NULL,
|
|
@@ -1159,6 +1265,12 @@ for (const col of [
|
|
|
1159
1265
|
"ALTER TABLE desktop_companion_devices ADD COLUMN last_seen_at TEXT",
|
|
1160
1266
|
"ALTER TABLE desktop_companion_devices ADD COLUMN revoked_at TEXT",
|
|
1161
1267
|
"ALTER TABLE desktop_companion_devices ADD COLUMN updated_at TEXT DEFAULT (datetime('now'))",
|
|
1268
|
+
"ALTER TABLE memory_facts ADD COLUMN valid_from TEXT",
|
|
1269
|
+
"ALTER TABLE memory_facts ADD COLUMN valid_to TEXT",
|
|
1270
|
+
"ALTER TABLE memory_facts ADD COLUMN learned_at TEXT",
|
|
1271
|
+
"ALTER TABLE memory_facts ADD COLUMN invalidated_at TEXT",
|
|
1272
|
+
"ALTER TABLE memory_facts ADD COLUMN status TEXT DEFAULT 'active'",
|
|
1273
|
+
"ALTER TABLE memory_facts ADD COLUMN supersedes_fact_id TEXT",
|
|
1162
1274
|
]) {
|
|
1163
1275
|
try { db.exec(col); } catch { /* column already exists */ }
|
|
1164
1276
|
}
|
package/server/http/routes.js
CHANGED
|
@@ -21,6 +21,7 @@ const routeRegistry = [
|
|
|
21
21
|
{ basePath: '/api/workspace', modulePath: '../routes/workspace' },
|
|
22
22
|
{ basePath: '/api/memory', modulePath: '../routes/memory' },
|
|
23
23
|
{ basePath: '/api/tasks', modulePath: '../routes/tasks' },
|
|
24
|
+
{ basePath: '/api/task-webhooks', modulePath: '../routes/task_webhooks' },
|
|
24
25
|
{ basePath: '/api/widgets', modulePath: '../routes/widgets' },
|
|
25
26
|
{ basePath: '/api/browser', modulePath: '../routes/browser' },
|
|
26
27
|
{ basePath: '/api/browser-extension', modulePath: '../routes/browser_extension' },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
ec945bff38eacd619d4434e746ae61aa
|
|
@@ -33,10 +33,10 @@ addEventListener("message", eventListener);
|
|
|
33
33
|
if (!window._flutter) {
|
|
34
34
|
window._flutter = {};
|
|
35
35
|
}
|
|
36
|
-
_flutter.buildConfig = {"engineRevision":"
|
|
36
|
+
_flutter.buildConfig = {"engineRevision":"77e2e94772b6eb43759e34ed1ad7da4674e19cab","builds":[{"compileTarget":"dart2js","renderer":"canvaskit","mainJsPath":"main.dart.js"},{}]};
|
|
37
37
|
|
|
38
38
|
_flutter.loader.load({
|
|
39
39
|
serviceWorkerSettings: {
|
|
40
|
-
serviceWorkerVersion: "
|
|
40
|
+
serviceWorkerVersion: "1556394997" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
|
41
41
|
}
|
|
42
42
|
});
|