neoagent 2.5.2-beta.2 → 2.5.2-beta.20

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.
Files changed (30) hide show
  1. package/package.json +1 -1
  2. package/server/public/.last_build_id +1 -1
  3. package/server/public/flutter_bootstrap.js +1 -1
  4. package/server/public/main.dart.js +4 -4
  5. package/server/services/ai/deliverables/artifact_helpers.js +109 -16
  6. package/server/services/ai/deliverables/selector.js +17 -0
  7. package/server/services/ai/engine.js +2 -4312
  8. package/server/services/ai/loop/agent_engine_core.js +1590 -0
  9. package/server/services/ai/loop/blank_recovery.js +37 -0
  10. package/server/services/ai/loop/callbacks.js +151 -0
  11. package/server/services/ai/loop/completion_judge.js +252 -0
  12. package/server/services/ai/loop/conversation_loop.js +2322 -0
  13. package/server/services/ai/loop/delivery_state.js +27 -0
  14. package/server/services/ai/loop/error_recovery.js +38 -0
  15. package/server/services/ai/loop/iteration_budget.js +24 -0
  16. package/server/services/ai/loop/messaging_delivery.js +250 -0
  17. package/server/services/ai/loop/model_io.js +258 -0
  18. package/server/services/ai/loop/progress_classification.js +177 -0
  19. package/server/services/ai/loop/progress_monitor.js +81 -0
  20. package/server/services/ai/loop/run_state.js +356 -0
  21. package/server/services/ai/loop/tool_dispatch.js +230 -0
  22. package/server/services/ai/loopPolicy.js +3 -3
  23. package/server/services/ai/repetitionGuard.js +47 -2
  24. package/server/services/ai/systemPrompt.js +5 -0
  25. package/server/services/ai/taskAnalysis.js +5 -0
  26. package/server/services/ai/toolEvidence.js +8 -1
  27. package/server/services/ai/tools.js +82 -11
  28. package/server/services/integrations/github/repos.js +39 -29
  29. package/server/services/messaging/manager.js +7 -0
  30. package/server/services/runtime/backends/local-vm.js +7 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.5.2-beta.2",
3
+ "version": "2.5.2-beta.20",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "server/index.js",
@@ -1 +1 @@
1
- 902e2ce5136c6bece8b7729e2742c5c6
1
+ efe2ad6d1aff0358de22202a239e2829
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"77e2e94772b6eb43759e34ed1ad7da4674e19c
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "3064876241" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "2093031085" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });
@@ -134794,7 +134794,7 @@ r===$&&A.b()
134794
134794
  p.push(A.jP(q,A.j9(!1,new A.a_(B.uG,A.d8(new A.cA(B.jt,new A.a7N(r,q),q),q,q),q),!1,B.H,!0),q,q,0,0,0,q))}r=!1
134795
134795
  if(!s.ay)if(!s.ch){r=s.e
134796
134796
  r===$&&A.b()
134797
- r=B.b.u("mqedthn8-62da7d5").length!==0&&r.b}if(r){r=s.d
134797
+ r=B.b.u("mqgmwb41-5bb5db5").length!==0&&r.b}if(r){r=s.d
134798
134798
  r===$&&A.b()
134799
134799
  r=r.aP&&!r.ai?84:0
134800
134800
  s=s.e
@@ -140506,7 +140506,7 @@ $S:0}
140506
140506
  A.a_6.prototype={}
140507
140507
  A.SQ.prototype={
140508
140508
  nb(a){var s=this
140509
- if(B.b.u("mqedthn8-62da7d5").length===0||s.a!=null)return
140509
+ if(B.b.u("mqgmwb41-5bb5db5").length===0||s.a!=null)return
140510
140510
  s.AU()
140511
140511
  s.a=A.on(B.RH,new A.bc8(s))},
140512
140512
  AU(){var s=0,r=A.l(t.H),q,p=2,o=[],n=this,m,l,k,j,i,h,g,f
@@ -140524,7 +140524,7 @@ if(!t.f.b(k)){s=1
140524
140524
  break}i=J.a3(k,"buildId")
140525
140525
  h=i==null?null:B.b.u(J.p(i))
140526
140526
  j=h==null?"":h
140527
- if(J.bi(j)===0||J.d(j,"mqedthn8-62da7d5")){s=1
140527
+ if(J.bi(j)===0||J.d(j,"mqgmwb41-5bb5db5")){s=1
140528
140528
  break}n.b=!0
140529
140529
  n.F()
140530
140530
  p=2
@@ -140541,7 +140541,7 @@ case 2:return A.i(o.at(-1),r)}})
140541
140541
  return A.k($async$AU,r)},
140542
140542
  vE(){var s=0,r=A.l(t.H),q,p=2,o=[],n=this,m,l,k,j,i,h,g,f,e,d,c,b,a,a0,a1
140543
140543
  var $async$vE=A.h(function(a2,a3){if(a2===1){o.push(a3)
140544
- s=p}for(;;)switch(s){case 0:if(B.b.u("mqedthn8-62da7d5").length===0||n.c){s=1
140544
+ s=p}for(;;)switch(s){case 0:if(B.b.u("mqgmwb41-5bb5db5").length===0||n.c){s=1
140545
140545
  break}n.c=!0
140546
140546
  n.F()
140547
140547
  p=4
@@ -72,10 +72,78 @@ const CANDIDATE_KEYS = [
72
72
  'mediaPaths',
73
73
  'screenshotPath',
74
74
  'uiDumpPath',
75
- 'url',
76
- 'urls',
75
+ 'artifact',
76
+ 'artifacts',
77
+ 'artifactPath',
78
+ 'artifactPaths',
79
+ 'artifactUrl',
80
+ 'artifactUrls',
81
+ 'artifactUri',
82
+ 'artifactUris',
83
+ 'downloadUrl',
84
+ 'downloadUrls',
85
+ 'downloadUri',
86
+ 'downloadUris',
77
87
  ];
78
88
 
89
+ const GENERIC_CANDIDATE_KEYS = new Set([
90
+ 'path',
91
+ 'paths',
92
+ 'file',
93
+ 'files',
94
+ 'filePath',
95
+ 'filePaths',
96
+ 'fullPath',
97
+ 'fullPaths',
98
+ 'downloadUrl',
99
+ 'downloadUrls',
100
+ 'downloadUri',
101
+ 'downloadUris',
102
+ ]);
103
+
104
+ const EXPLICIT_CANDIDATE_KEYS = new Set(
105
+ CANDIDATE_KEYS.filter((key) => !GENERIC_CANDIDATE_KEYS.has(key))
106
+ );
107
+
108
+ const ARTIFACT_CONTAINER_KEYS = new Set([
109
+ 'artifact',
110
+ 'artifacts',
111
+ 'attachment',
112
+ 'attachments',
113
+ 'deliverable',
114
+ 'deliverables',
115
+ 'download',
116
+ 'downloads',
117
+ 'file',
118
+ 'files',
119
+ 'media',
120
+ 'preview',
121
+ 'screenshot',
122
+ 'screenshots',
123
+ ]);
124
+
125
+ const CONTAINER_URL_KEYS = new Set(['url', 'urls', 'uri', 'uris', 'href', 'hrefs']);
126
+
127
+ const EVIDENCE_RESULT_TOOLS = /^(execute_command|github_|list_|search_|read_|get_|find_|http_request|web_search|browser_get|browser_read|code_navigate|query_structured_data|memory_|session_search|recordings_|read_health_data)/;
128
+
129
+ function allowsGenericCandidateKeys(toolName = '') {
130
+ return !EVIDENCE_RESULT_TOOLS.test(String(toolName || ''));
131
+ }
132
+
133
+ function isExplicitCandidateKey(keyHint = '', parentKeyHint = '', options = {}) {
134
+ if (EXPLICIT_CANDIDATE_KEYS.has(keyHint)) return true;
135
+ if (
136
+ ARTIFACT_CONTAINER_KEYS.has(parentKeyHint)
137
+ && CANDIDATE_KEYS.includes(keyHint)
138
+ && (!GENERIC_CANDIDATE_KEYS.has(parentKeyHint) || options.allowGenericKeys === true)
139
+ ) {
140
+ return true;
141
+ }
142
+ if (GENERIC_CANDIDATE_KEYS.has(keyHint)) return options.allowGenericKeys === true;
143
+ if (!CONTAINER_URL_KEYS.has(keyHint)) return false;
144
+ return ARTIFACT_CONTAINER_KEYS.has(parentKeyHint);
145
+ }
146
+
79
147
  function inferExtension(candidate = '') {
80
148
  return path.extname(String(candidate || '').split('?')[0]).toLowerCase();
81
149
  }
@@ -102,8 +170,17 @@ function normalizePathOrUri(value) {
102
170
  if (!text) return null;
103
171
  if (text.startsWith('/api/artifacts/')) return { uri: text, path: null };
104
172
  if (/^https?:\/\//i.test(text)) return { uri: text, path: null };
105
- if (/^[A-Za-z]:\\/.test(text)) return { path: text, uri: null };
106
- if (path.isAbsolute(text)) return { path: text, uri: null };
173
+ if (text.startsWith('//')) return null;
174
+ if (/^[A-Za-z]:\\/.test(text)) {
175
+ const ext = path.extname(text.split('?')[0]).toLowerCase();
176
+ if (!FILE_EXTENSION_TO_KIND[ext]) return null;
177
+ return { path: text, uri: null };
178
+ }
179
+ if (path.isAbsolute(text)) {
180
+ const ext = path.extname(text.split('?')[0]).toLowerCase();
181
+ if (!FILE_EXTENSION_TO_KIND[ext]) return null;
182
+ return { path: text, uri: null };
183
+ }
107
184
  return null;
108
185
  }
109
186
 
@@ -123,20 +200,25 @@ async function buildArtifactFromCandidate(candidate, fallbackKind = 'artifact')
123
200
  artifact.size = (await fs.promises.stat(artifact.path)).size;
124
201
  } catch (error) {
125
202
  console.warn('[deliverables] Failed to stat artifact candidate:', artifact.path, error?.message || error);
203
+ return null;
126
204
  }
127
205
  }
128
206
  return artifact.path || artifact.uri ? artifact : null;
129
207
  }
130
208
 
131
- function scanStringForCandidates(text) {
209
+ function scanStringForCandidates(text, { explicit = false } = {}) {
132
210
  const input = String(text || '');
133
211
  const matches = [];
134
- const regexes = [
135
- /\/api\/artifacts\/[A-Za-z0-9%_-]+\/content/g,
136
- /\/[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
137
- /[A-Za-z]:\\[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
138
- /https?:\/\/[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
139
- ];
212
+ const regexes = explicit
213
+ ? [
214
+ /\/api\/artifacts\/[A-Za-z0-9%_-]+\/content/g,
215
+ /\/[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
216
+ /[A-Za-z]:\\[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
217
+ /https?:\/\/[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
218
+ ]
219
+ : [
220
+ /\/api\/artifacts\/[A-Za-z0-9%_-]+\/content/g,
221
+ ];
140
222
  for (const regex of regexes) {
141
223
  const found = input.match(regex);
142
224
  if (found) matches.push(...found);
@@ -147,9 +229,14 @@ function scanStringForCandidates(text) {
147
229
  async function extractArtifactsFromResult(toolName, result) {
148
230
  const artifacts = [];
149
231
  const seen = new Set();
232
+ const seenCandidates = new Set();
150
233
  const fallbackKind = inferArtifactKind(toolName, 'artifact');
234
+ const allowGenericKeys = allowsGenericCandidateKeys(toolName);
151
235
 
152
236
  async function pushCandidate(candidate) {
237
+ const candidateKey = String(candidate || '').trim();
238
+ if (!candidateKey || seenCandidates.has(candidateKey)) return;
239
+ seenCandidates.add(candidateKey);
153
240
  const artifact = await buildArtifactFromCandidate(candidate, fallbackKind);
154
241
  if (!artifact) return;
155
242
  const key = `${artifact.kind}:${artifact.path || artifact.uri}`;
@@ -158,22 +245,26 @@ async function extractArtifactsFromResult(toolName, result) {
158
245
  artifacts.push(artifact);
159
246
  }
160
247
 
161
- async function visit(value, keyHint = '') {
248
+ async function visit(value, keyHint = '', parentKeyHint = '') {
162
249
  if (value == null) return;
163
250
  if (typeof value === 'string') {
164
- if (CANDIDATE_KEYS.includes(keyHint)) await pushCandidate(value);
165
- for (const candidate of scanStringForCandidates(value)) {
251
+ const explicit = isExplicitCandidateKey(keyHint, parentKeyHint, { allowGenericKeys });
252
+ if (explicit) {
253
+ if (normalizePathOrUri(value)) await pushCandidate(value);
254
+ return;
255
+ }
256
+ for (const candidate of scanStringForCandidates(value, { explicit })) {
166
257
  await pushCandidate(candidate);
167
258
  }
168
259
  return;
169
260
  }
170
261
  if (Array.isArray(value)) {
171
- for (const item of value) await visit(item, keyHint);
262
+ for (const item of value) await visit(item, keyHint, parentKeyHint);
172
263
  return;
173
264
  }
174
265
  if (typeof value === 'object') {
175
266
  for (const [key, nested] of Object.entries(value)) {
176
- await visit(nested, key);
267
+ await visit(nested, key, keyHint);
177
268
  }
178
269
  }
179
270
  }
@@ -183,8 +274,10 @@ async function extractArtifactsFromResult(toolName, result) {
183
274
  }
184
275
 
185
276
  module.exports = {
277
+ allowsGenericCandidateKeys,
186
278
  extractArtifactsFromResult,
187
279
  inferArtifactKind,
188
280
  inferMimeType,
281
+ isExplicitCandidateKey,
189
282
  normalizePathOrUri,
190
283
  };
@@ -47,6 +47,23 @@ async function selectDeliverableWorkflow({
47
47
  tools = [],
48
48
  options = {},
49
49
  }) {
50
+ if (!engine || typeof engine.requestStructuredJson !== 'function') {
51
+ return {
52
+ selection: {
53
+ status: 'standard',
54
+ type: null,
55
+ confidence: 0,
56
+ goal: '',
57
+ requestedOutputs: [],
58
+ supportingCapabilities: [],
59
+ },
60
+ usage: 0,
61
+ raw: '',
62
+ skipped: true,
63
+ reason: 'structured selector unavailable',
64
+ };
65
+ }
66
+
50
67
  const response = await engine.requestStructuredJson({
51
68
  provider,
52
69
  providerName,