neoagent 2.1.18-beta.36 → 2.1.18-beta.38

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 CHANGED
@@ -3,7 +3,7 @@
3
3
  <p align="center"><strong>Your agent. Your server. Your rules.</strong></p>
4
4
 
5
5
  <p align="center">
6
- <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node.js-18+-5fa04e?style=flat-square&logo=node.js&logoColor=white" alt="Node.js"></a>
6
+ <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>
7
7
  <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>
8
8
  <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>
9
9
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-a855f7?style=flat-square" alt="License"></a>
@@ -4,7 +4,7 @@ NeoAgent installs as a Node CLI and runs a self-hosted server with a bundled Flu
4
4
 
5
5
  ## Requirements
6
6
 
7
- - Node.js 18 or newer.
7
+ - Node.js 20 or newer.
8
8
  - A reachable server URL if you want OAuth callbacks, mobile access, or messaging webhooks.
9
9
  - At least one hosted AI provider API key, unless you only use local Ollama.
10
10
  - Android Studio or a Flutter Android toolchain if you build the Android client yourself.
package/docs/index.md CHANGED
@@ -1,47 +1,14 @@
1
1
  ---
2
- layout: home
2
+ slug: /
3
+ title: NeoAgent
4
+ sidebar_label: Overview
5
+ ---
3
6
 
4
- hero:
5
- name: NeoAgent
6
- text: Self-hosted proactive AI agent
7
- tagline: Run your own server, keep credentials server-side, and operate browser, Android, recordings, schedules, integrations, memory, MCP, and messaging from one Flutter UI.
8
- actions:
9
- - theme: brand
10
- text: Get Started
11
- link: /getting-started
12
- - theme: alt
13
- text: Capabilities
14
- link: /capabilities
15
- - theme: alt
16
- text: Why NeoAgent
17
- link: /why-neoagent
7
+ # NeoAgent
18
8
 
19
- features:
20
- - title: Android Control
21
- details: Let the AI operate a server-attached Android emulator or device with screenshots, UI dumps, app launch, intents, taps, typing, swipes, APK installs, and ADB shell.
22
- link: /capabilities#android-control
23
- linkText: Android Control
24
- - title: Recordings
25
- details: Capture web, Android, and wearable audio as sessions with transcripts, searchable segments, playback, retry, cleanup, and AI-generated insights.
26
- link: /capabilities#recordings
27
- linkText: Recordings
28
- - title: Proactive Automation
29
- details: Create recurring tasks and one-time runs that can use browser, files, CLI, memory, MCP, integrations, subagents, health summaries, and messaging delivery.
30
- link: /automation
31
- linkText: Automation
32
- - title: Official Integrations
33
- details: Use OAuth-backed Google Workspace, Microsoft 365, Notion, Slack, and Figma tools instead of brittle browser automation where possible.
34
- link: /integrations
35
- linkText: Integrations
36
- - title: Server-Side Secrets
37
- details: Keep AI provider keys, OAuth client secrets, Telnyx tokens, runtime settings, and deployment controls on the NeoAgent server.
38
- link: /configuration
39
- linkText: Configuration
40
- - title: Recovery Path
41
- details: Operate self-hosted installs with status, logs, release channels, update, fix, runtime paths, and the remote-server log caveat.
42
- link: /operations
43
- linkText: Operations
44
- ---
9
+ NeoAgent is a self-hosted proactive AI agent with a bundled Flutter client for web and Android. It runs on your server, keeps credentials server-side, and gives you an operator UI for chat, runs, logs, scheduler tasks, skills, integrations, MCP, memory, Android control, recordings, Health Connect data, wearables, and settings.
10
+
11
+ It is designed for people who want a focused personal automation server rather than a broad gateway platform. NeoAgent can run scheduled tasks, control a browser, operate a server-attached Android emulator or device, manage files, remember long-term context, connect to hosted AI providers or local Ollama, search recordings, read synced health summaries, and send results through Telegram, Discord, WhatsApp, or Telnyx Voice.
45
12
 
46
13
  ## Quick Start
47
14
 
@@ -52,7 +19,21 @@ neoagent install
52
19
 
53
20
  Open the server URL, sign in, configure providers and messaging, then create a scheduled task or chat run.
54
21
 
55
- ## Navigation
22
+ ## What NeoAgent Does
23
+
24
+ | Area | Capability |
25
+ |---|---|
26
+ | AI providers | OpenAI, Anthropic, xAI, Google, MiniMax Code, and local Ollama |
27
+ | Operator UI | Chat, live runs, logs, scheduler, skills, integrations, MCP, memory, devices, recordings, health, wearables, settings |
28
+ | Automation | Recurring scheduled tasks, one-time runs, browser control, file access, CLI skills, subagents, and messaging delivery |
29
+ | Android control | AI control of a server-attached Android emulator or device: screenshots, UI dumps, taps, typing, intents, APK installs, and ADB shell |
30
+ | Recordings | Web, Android, and wearable audio sessions with transcript search and AI insights |
31
+ | Integrations | Google Workspace, Notion, Microsoft 365, Slack, Figma, and remote MCP servers |
32
+ | Messaging | Telegram, Discord, WhatsApp text/media, and Telnyx Voice calls |
33
+ | Outputs | Artifacts, Grok image generation, vision analysis, markdown tables, and Mermaid graphs |
34
+ | Recovery | `neoagent status`, `neoagent logs`, `neoagent update`, release channels, and `neoagent fix` |
35
+
36
+ ## Main Paths
56
37
 
57
38
  | Need | Start here |
58
39
  |---|---|
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.1.18-beta.36",
3
+ "version": "2.1.18-beta.38",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "MIT",
6
6
  "main": "server/index.js",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
7
10
  "bin": {
8
11
  "neoagent": "bin/neoagent.js"
9
12
  },
@@ -28,9 +31,9 @@
28
31
  "dev:stack": "./dev/stack.sh",
29
32
  "dev:build": "./dev/build.sh",
30
33
  "dev:test": "./dev/test.sh",
31
- "docs:dev": "vitepress dev docs",
32
- "docs:build": "vitepress build docs",
33
- "docs:preview": "vitepress preview docs",
34
+ "docs:dev": "docusaurus start",
35
+ "docs:build": "docusaurus build",
36
+ "docs:preview": "docusaurus serve build",
34
37
  "flutter:run:web": "cd flutter_app && flutter run -d chrome",
35
38
  "flutter:build:web": "cd flutter_app && flutter build web --output ../server/public --dart-define=NEOAGENT_BACKEND_URL=${NEOAGENT_BACKEND_URL:-}",
36
39
  "manage": "node bin/neoagent.js",
@@ -83,6 +86,9 @@
83
86
  "undici": "^6.24.0"
84
87
  },
85
88
  "devDependencies": {
86
- "vitepress": "1.6.4"
89
+ "@docusaurus/core": "3.8.1",
90
+ "@docusaurus/preset-classic": "3.8.1",
91
+ "react": "18.3.1",
92
+ "react-dom": "18.3.1"
87
93
  }
88
94
  }
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"425cfb54d01a9472b3e81d9e76fd63a4a44cfb
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "1390596255" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "2247189506" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });
@@ -173,10 +173,10 @@ function joinSentMessages(messages = []) {
173
173
 
174
174
  function buildBlankMessagingReplyPrompt(attempt) {
175
175
  if (attempt <= 1) {
176
- return 'You must send one non-empty plain-text reply for the external messaging user right now. Do not call tools. Do not use markdown. Give either: (a) the concrete outcome, or (b) a clear blocker and the next action. If tool work already happened, summarize what you actually tried and where it got blocked. Do not ask the user to repeat the original request.';
176
+ return 'You must send one non-empty plain-text reply for the external messaging user right now. Do not call tools. Do not use markdown. Give either: (a) the concrete outcome, or (b) a clear blocker. If tool work already happened, summarize what you actually tried and where it got blocked. Do not ask the user to repeat the original request. Do not promise future work unless that work already happened in this run or will happen automatically before this reply is sent.';
177
177
  }
178
178
 
179
- return 'Your previous reply was empty. Return one non-empty plain-text message now. Do not call tools. Do not use markdown. If needed, apologize briefly, explain the blocker in one sentence, and tell the user what to do next. Use the run evidence already in the conversation instead of asking the user to restate the task.';
179
+ return 'Your previous reply was empty. Return one non-empty plain-text message now. Do not call tools. Do not use markdown. If needed, apologize briefly and explain the blocker in one sentence. Use the run evidence already in the conversation instead of asking the user to restate the task. Do not promise future work unless that work already happened in this run or will happen automatically before this reply is sent.';
180
180
  }
181
181
 
182
182
  function parseToolExecutionSummary(item) {
@@ -280,21 +280,35 @@ function buildDeterministicMessagingFallback({ failedStepCount, stepIndex, toolE
280
280
  return 'I could not produce a reliable final reply just now.';
281
281
  }
282
282
 
283
- function buildModelFailureLoopPrompt({ failedModel, nextModel, errorMessage }) {
284
- return [
285
- `The previous model call on "${failedModel}" failed with: ${summarizeForLog(errorMessage, 220)}.`,
286
- `Continue on "${nextModel}" and recover autonomously.`,
287
- 'If a previous plan depended on that failed call, adjust your approach and proceed end-to-end.',
288
- 'Only ask the user for help if no safe path remains.'
289
- ].join(' ');
290
- }
283
+ function buildMessagingFailureScenario({ err, failedStepCount, stepIndex, toolExecutions = [] }) {
284
+ const parts = [];
285
+ const runtimeError = normalizeOutgoingMessage(err?.message || '');
286
+ const workSummary = summarizeRecentWork(toolExecutions);
287
+ const blocker = [...toolExecutions].reverse()
288
+ .map((item) => extractToolFailureMessage(item))
289
+ .find(Boolean);
291
290
 
292
- function buildMessagingErrorReply(err) {
293
- const message = String(err?.message || '').trim();
294
- if (!message) {
295
- return 'I ran into an internal error while processing your request and could not finish it reliably.';
291
+ if (runtimeError) {
292
+ parts.push(`Runtime error: ${summarizeForLog(runtimeError, 260)}.`);
293
+ }
294
+ if (workSummary) {
295
+ parts.push(`Observed work before failure: ${workSummary}.`);
296
+ }
297
+ if (blocker) {
298
+ parts.push(`Most specific blocker from run evidence: ${summarizeForLog(blocker, 260)}.`);
299
+ }
300
+ if (stepIndex > 0) {
301
+ parts.push(`Completed steps before failure: ${stepIndex}.`);
302
+ }
303
+ if (failedStepCount > 0) {
304
+ parts.push(`Failed tool steps: ${failedStepCount}.`);
296
305
  }
297
306
 
307
+ return parts.join(' ');
308
+ }
309
+
310
+ function buildDeterministicMessagingErrorReply({ err, failedStepCount, stepIndex, toolExecutions = [] }) {
311
+ const message = normalizeOutgoingMessage(err?.message || '');
298
312
  if (/no ai providers? are currently available/i.test(message)) {
299
313
  return 'I cannot continue right now because no AI provider is available for this account. Please check the provider settings.';
300
314
  }
@@ -303,7 +317,27 @@ function buildMessagingErrorReply(err) {
303
317
  return 'I hit a timeout while processing your request and could not finish it reliably.';
304
318
  }
305
319
 
306
- return 'I ran into an internal error while processing your request and could not finish it reliably.';
320
+ const blocker = [...toolExecutions].reverse()
321
+ .map((item) => extractToolFailureMessage(item))
322
+ .find(Boolean);
323
+ if (blocker) {
324
+ return `I got blocked while checking this: ${blocker}.`;
325
+ }
326
+
327
+ if (message) {
328
+ return `I got blocked while working on this: ${message}.`;
329
+ }
330
+
331
+ return buildDeterministicMessagingFallback({ failedStepCount, stepIndex, toolExecutions });
332
+ }
333
+
334
+ function buildModelFailureLoopPrompt({ failedModel, nextModel, errorMessage }) {
335
+ return [
336
+ `The previous model call on "${failedModel}" failed with: ${summarizeForLog(errorMessage, 220)}.`,
337
+ `Continue on "${nextModel}" and recover autonomously.`,
338
+ 'If a previous plan depended on that failed call, adjust your approach and proceed end-to-end.',
339
+ 'Only ask the user for help if no safe path remains.'
340
+ ].join(' ');
307
341
  }
308
342
 
309
343
  const MAX_AUTONOMOUS_MESSAGING_RETRIES = 2;
@@ -1984,12 +2018,18 @@ class AgentEngine {
1984
2018
  if (!runMeta?.messagingSent) {
1985
2019
  const manager = this.messagingManager;
1986
2020
  if (manager) {
2021
+ const failureScenario = buildMessagingFailureScenario({
2022
+ err,
2023
+ failedStepCount,
2024
+ stepIndex,
2025
+ toolExecutions,
2026
+ });
1987
2027
  try {
1988
2028
  const failedMessage = sanitizeConversationMessages([
1989
2029
  ...messages,
1990
2030
  {
1991
2031
  role: 'system',
1992
- content: `The run encountered a runtime error and cannot continue reliably: ${summarizeForLog(err.message, 260)}. Do not call tools. Write exactly one short plain-text user message that explains the blocker naturally. Do not ask the user to resend or restate the same task. Only ask the user for something if a specific external input, permission, or configuration change is actually required.`
2032
+ content: `The run encountered a runtime error and cannot continue reliably. Use the actual run scenario below to explain the blocker naturally.\n\nScenario:\n${failureScenario || 'No additional scenario details were captured.'}\n\nDo not call tools. Write exactly one short plain-text user message. Do not ask the user to resend or restate the same task. Only ask the user for something if a specific external input, permission, or configuration change is actually required. Do not promise future work unless it will happen automatically before this reply is sent.`
1993
2033
  }
1994
2034
  ]);
1995
2035
  const modelReply = await provider.chat(failedMessage, [], {
@@ -2005,7 +2045,12 @@ class AgentEngine {
2005
2045
  }
2006
2046
 
2007
2047
  if (!messagingFailureContent) {
2008
- messagingFailureContent = buildMessagingErrorReply(err);
2048
+ messagingFailureContent = buildDeterministicMessagingErrorReply({
2049
+ err,
2050
+ failedStepCount,
2051
+ stepIndex,
2052
+ toolExecutions,
2053
+ });
2009
2054
  }
2010
2055
 
2011
2056
  try {
@@ -78,6 +78,7 @@ For long tasks, give brief progress only when the user is waiting or the operati
78
78
  REPORT ACTUAL RESULTS
79
79
  When a tool returns data, share the relevant parts — summarized if large, direct if short. Never paste raw JSON as the answer. Never narrate what you're about to do at length before doing it.
80
80
  Never promise an action in the final answer unless you already took that action in this run. Do not say "I'll check", "I'll fix it", or "I'll send it" and then stop. Either do it first or say you have not done it yet.
81
+ Do not promise future follow-up work unless that work will actually happen automatically before the current run ends.
81
82
  For scheduler or task-config changes, never claim that a cron job was created, updated, deleted, enabled, disabled, or “fixed” unless the corresponding scheduler tool call succeeded in this run. If you did not verify the actual task config, say that clearly instead of guessing.
82
83
  If the user asks you to debug scheduler timing or frequency, inspect the current scheduled-task list first and separate three things clearly: what you observed, what you infer, and what you actually changed.
83
84
 
@@ -1,102 +0,0 @@
1
- import { defineConfig } from 'vitepress';
2
-
3
- export default defineConfig({
4
- title: 'NeoAgent',
5
- description: 'Self-hosted proactive AI agent docs',
6
- base: '/NeoAgent/',
7
- cleanUrls: true,
8
- lastUpdated: true,
9
- themeConfig: {
10
- nav: [
11
- {
12
- text: 'Start',
13
- activeMatch: '^/(getting-started|why-neoagent)?$',
14
- items: [
15
- { text: 'Overview', link: '/' },
16
- { text: 'Getting Started', link: '/getting-started' },
17
- { text: 'Why NeoAgent', link: '/why-neoagent' },
18
- ],
19
- },
20
- {
21
- text: 'Product',
22
- activeMatch: '^/(capabilities|automation|integrations|skills)',
23
- items: [
24
- { text: 'Capabilities', link: '/capabilities' },
25
- { text: 'Android Control', link: '/capabilities#android-control' },
26
- { text: 'Recordings', link: '/capabilities#recordings' },
27
- { text: 'Integrations', link: '/integrations' },
28
- { text: 'Automation', link: '/automation' },
29
- ],
30
- },
31
- {
32
- text: 'Operate',
33
- activeMatch: '^/(configuration|operations)',
34
- items: [
35
- { text: 'Configuration', link: '/configuration' },
36
- { text: 'Skills', link: '/skills' },
37
- { text: 'Operations', link: '/operations' },
38
- ],
39
- },
40
- { text: 'Why NeoAgent', link: '/why-neoagent' },
41
- { text: 'GitHub', link: 'https://github.com/NeoLabs-Systems/NeoAgent' },
42
- ],
43
- sidebar: [
44
- {
45
- text: 'Start',
46
- items: [
47
- { text: 'Overview', link: '/' },
48
- { text: 'Getting Started', link: '/getting-started' },
49
- { text: 'Why NeoAgent', link: '/why-neoagent' },
50
- ],
51
- },
52
- {
53
- text: 'Product Surface',
54
- items: [
55
- {
56
- text: 'Capabilities',
57
- link: '/capabilities',
58
- items: [
59
- { text: 'Android Control', link: '/capabilities#android-control' },
60
- { text: 'Recordings', link: '/capabilities#recordings' },
61
- { text: 'Health Data', link: '/capabilities#health-data' },
62
- { text: 'Agent Tools', link: '/capabilities#agent-tools' },
63
- { text: 'Runtime Modes', link: '/capabilities#runtime-modes' },
64
- ],
65
- },
66
- { text: 'Automation', link: '/automation' },
67
- { text: 'Integrations', link: '/integrations' },
68
- { text: 'Skills', link: '/skills' },
69
- ],
70
- },
71
- {
72
- text: 'Operate',
73
- items: [
74
- { text: 'Configuration', link: '/configuration' },
75
- { text: 'Operations', link: '/operations' },
76
- ],
77
- },
78
- ],
79
- socialLinks: [
80
- { icon: 'github', link: 'https://github.com/NeoLabs-Systems/NeoAgent' },
81
- ],
82
- search: {
83
- provider: 'local',
84
- },
85
- outline: {
86
- level: [2, 3],
87
- label: 'On This Page',
88
- },
89
- editLink: {
90
- pattern: 'https://github.com/NeoLabs-Systems/NeoAgent/edit/main/docs/:path',
91
- text: 'Edit this page on GitHub',
92
- },
93
- docFooter: {
94
- prev: 'Previous',
95
- next: 'Next',
96
- },
97
- footer: {
98
- message: 'Released under the MIT License.',
99
- copyright: 'Copyright NeoLabs Systems',
100
- },
101
- },
102
- });