neoagent 2.5.2-beta.25 → 2.5.2-beta.27

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.5.2-beta.25",
4
- "description": "Proactive personal AI agent with no limits",
3
+ "version": "2.5.2-beta.27",
4
+ "description": "Self-hosted AI agent for long-running tasks, automation, messaging, device control, and local memory",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "server/index.js",
7
7
  "engines": {
@@ -1 +1 @@
1
- 7c286f044074b8e0fc8946771061244b
1
+ 7ff5faf6c30bf9859f1c1ee320f350fe
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"77e2e94772b6eb43759e34ed1ad7da4674e19c
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "2742195180" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "3324688363" /* 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("mqh0uyur-6df469c").length!==0&&r.b}if(r){r=s.d
134797
+ r=B.b.u("mqh4ytnn-de00e37").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("mqh0uyur-6df469c").length===0||s.a!=null)return
140509
+ if(B.b.u("mqh4ytnn-de00e37").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,"mqh0uyur-6df469c")){s=1
140527
+ if(J.bi(j)===0||J.d(j,"mqh4ytnn-de00e37")){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("mqh0uyur-6df469c").length===0||n.c){s=1
140544
+ s=p}for(;;)switch(s){case 0:if(B.b.u("mqh4ytnn-de00e37").length===0||n.c){s=1
140545
140545
  break}n.c=!0
140546
140546
  n.F()
140547
140547
  p=4
@@ -1513,9 +1513,16 @@ async function runConversation(engine, userId, userMessage, options = {}, _model
1513
1513
  }, {
1514
1514
  verified: true,
1515
1515
  });
1516
+ if (analysis.mode === 'execute' || analysis.mode === 'plan_execute') {
1517
+ const iterMeta = engine.getRunMeta(runId);
1518
+ if (iterMeta) {
1519
+ iterMeta.consecutiveReadOnlyIterations = (iterMeta.consecutiveReadOnlyIterations || 0) + 1;
1520
+ }
1521
+ }
1516
1522
  continue;
1517
1523
  }
1518
1524
 
1525
+ let iterationConcreteProgress = false;
1519
1526
  for (const toolCall of response.toolCalls) {
1520
1527
  if (engine.isRunStopped(runId)) break;
1521
1528
  stepIndex++;
@@ -1730,6 +1737,9 @@ async function runConversation(engine, userId, userMessage, options = {}, _model
1730
1737
 
1731
1738
  const execution = classifyToolExecution(toolName, toolArgs, toolResult, toolErrorMessage);
1732
1739
  execution.input = toolArgs;
1740
+ if (execution.stateChanged && isProgressToolCall(toolName, toolArgs)) {
1741
+ iterationConcreteProgress = true;
1742
+ }
1733
1743
  repetitionGuard?.observe(toolName, toolArgs, toolResult);
1734
1744
  execution.artifacts = await extractArtifactsFromResult(toolName, toolResult);
1735
1745
  toolExecutions.push(execution);
@@ -1899,12 +1909,7 @@ async function runConversation(engine, userId, userMessage, options = {}, _model
1899
1909
  && (analysis.mode === 'execute' || analysis.mode === 'plan_execute')) {
1900
1910
  const iterMeta = engine.getRunMeta(runId);
1901
1911
  if (iterMeta) {
1902
- const calledProgress = response.toolCalls.some((tc) => {
1903
- let parsedArgs = {};
1904
- try { parsedArgs = JSON.parse(tc.function?.arguments || '{}'); } catch {}
1905
- return isProgressToolCall(tc.function?.name || '', parsedArgs);
1906
- });
1907
- iterMeta.consecutiveReadOnlyIterations = calledProgress
1912
+ iterMeta.consecutiveReadOnlyIterations = iterationConcreteProgress
1908
1913
  ? 0
1909
1914
  : (iterMeta.consecutiveReadOnlyIterations || 0) + 1;
1910
1915
  }
@@ -163,7 +163,7 @@ function isProgressToolCall(toolName, toolArgs = {}) {
163
163
  if (/^(list_|search_|read_file|get_file|find_files?|github_list|github_get|github_search|browser_get|browser_read)/.test(name)) {
164
164
  return false;
165
165
  }
166
- if (name === 'http_request') {
166
+ if (name === 'http_request' || name === 'github_api_request') {
167
167
  return String(toolArgs?.method || 'GET').toUpperCase() !== 'GET';
168
168
  }
169
169
  if (name === 'execute_command') {
@@ -10,6 +10,7 @@ const { summarizeForLog } = require('./logFormat');
10
10
  const { normalizeOutgoingMessage, clampRunContext } = require('./messagingFallback');
11
11
  const {
12
12
  isClearlyReadOnlyShellCommand,
13
+ isProgressToolCall,
13
14
  } = require('./loop/progress_classification');
14
15
 
15
16
  // Ordered classification rules mapping a tool name to its evidence "source"
@@ -93,6 +94,8 @@ function classifyToolExecution(toolName, toolArgs = {}, result, errorMessage = '
93
94
  ? !isClearlyReadOnlyShellCommand(toolArgs?.command || '')
94
95
  : stateChangingExact.has(name)
95
96
  )
97
+ || (name.startsWith('github_') && isProgressToolCall(name, toolArgs))
98
+ || (name === 'http_request' && isProgressToolCall(name, toolArgs))
96
99
  || name.startsWith('android_')
97
100
  || ['browser_click', 'browser_type', 'browser_evaluate'].includes(name);
98
101
 
@@ -134,7 +137,7 @@ function classifyToolExecution(toolName, toolArgs = {}, result, errorMessage = '
134
137
  error: normalizedError,
135
138
  evidenceSource,
136
139
  evidenceRelevant,
137
- stateChanged,
140
+ stateChanged: stateChanged && !normalizedError,
138
141
  dependsOnOutput: true,
139
142
  summary: compactToolResult(name, toolArgs, result || { error: errorMessage || 'Tool failed' }, {
140
143
  softLimit: 500,
@@ -755,6 +755,23 @@ function resolveApiRequestPath(args = {}) {
755
755
  return '';
756
756
  }
757
757
 
758
+ function hasOwnerRepoArg(args = {}) {
759
+ if (typeof args.owner_repo === 'string' && args.owner_repo.trim()) return true;
760
+ return Boolean(String(args.owner || '').trim() && String(args.repo || '').trim());
761
+ }
762
+
763
+ function parseOwnerRepoArg(args = {}) {
764
+ if (typeof args.owner_repo === 'string' && args.owner_repo.trim()) {
765
+ return parseOwnerRepo(args.owner_repo);
766
+ }
767
+ const owner = String(args.owner || '').trim();
768
+ const repo = String(args.repo || '').trim();
769
+ if (owner && repo) {
770
+ return parseOwnerRepo(`${owner}/${repo}`);
771
+ }
772
+ return parseOwnerRepo(args.owner_repo);
773
+ }
774
+
758
775
  function encodeGithubFileContent(args = {}) {
759
776
  const content = String(args.content ?? '');
760
777
  const encoding = String(args.encoding || args.content_encoding || 'utf-8').toLowerCase();
@@ -770,6 +787,23 @@ function resolveApiRequestBody(args = {}) {
770
787
  return null;
771
788
  }
772
789
 
790
+ for (const definition of githubToolDefinitions) {
791
+ const parameters = definition.parameters;
792
+ const properties = parameters?.properties;
793
+ if (!properties?.owner_repo) continue;
794
+ properties.owner = {
795
+ type: 'string',
796
+ description: 'Repository owner alias. Use together with repo when owner_repo is not supplied.',
797
+ };
798
+ properties.repo = {
799
+ type: 'string',
800
+ description: 'Repository name alias. Use together with owner when owner_repo is not supplied.',
801
+ };
802
+ if (Array.isArray(parameters.required) && parameters.required.includes('owner_repo')) {
803
+ parameters.required = parameters.required.filter((item) => item !== 'owner_repo');
804
+ }
805
+ }
806
+
773
807
  async function executeGithubTool(toolName, args, auth) {
774
808
  switch (toolName) {
775
809
  case 'github_get_auth_user': {
@@ -789,14 +823,14 @@ async function executeGithubTool(toolName, args, auth) {
789
823
  }
790
824
 
791
825
  case 'github_get_repo': {
792
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
826
+ const { owner, repo } = parseOwnerRepoArg(args);
793
827
  return await githubApiRequest(auth, {
794
828
  path: `/repos/${owner}/${repo}`,
795
829
  });
796
830
  }
797
831
 
798
832
  case 'github_list_issues': {
799
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
833
+ const { owner, repo } = parseOwnerRepoArg(args);
800
834
  const query = { per_page: Math.min(Number(args.max_results) || 30, 100) };
801
835
  if (args.state) query.state = args.state;
802
836
  if (args.labels) query.labels = args.labels;
@@ -810,14 +844,14 @@ async function executeGithubTool(toolName, args, auth) {
810
844
  }
811
845
 
812
846
  case 'github_get_issue': {
813
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
847
+ const { owner, repo } = parseOwnerRepoArg(args);
814
848
  return await githubApiRequest(auth, {
815
849
  path: `/repos/${owner}/${repo}/issues/${Number(args.issue_number)}`,
816
850
  });
817
851
  }
818
852
 
819
853
  case 'github_create_issue': {
820
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
854
+ const { owner, repo } = parseOwnerRepoArg(args);
821
855
  return await githubApiRequest(auth, {
822
856
  method: 'POST',
823
857
  path: `/repos/${owner}/${repo}/issues`,
@@ -831,7 +865,7 @@ async function executeGithubTool(toolName, args, auth) {
831
865
  }
832
866
 
833
867
  case 'github_update_issue': {
834
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
868
+ const { owner, repo } = parseOwnerRepoArg(args);
835
869
  const body = {};
836
870
  if (args.title) body.title = String(args.title);
837
871
  if (args.body !== undefined) body.body = String(args.body);
@@ -846,7 +880,7 @@ async function executeGithubTool(toolName, args, auth) {
846
880
  }
847
881
 
848
882
  case 'github_add_issue_labels': {
849
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
883
+ const { owner, repo } = parseOwnerRepoArg(args);
850
884
  return await githubApiRequest(auth, {
851
885
  method: 'POST',
852
886
  path: `/repos/${owner}/${repo}/issues/${Number(args.issue_number)}/labels`,
@@ -857,7 +891,7 @@ async function executeGithubTool(toolName, args, auth) {
857
891
  }
858
892
 
859
893
  case 'github_add_issue_assignees': {
860
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
894
+ const { owner, repo } = parseOwnerRepoArg(args);
861
895
  return await githubApiRequest(auth, {
862
896
  method: 'POST',
863
897
  path: `/repos/${owner}/${repo}/issues/${Number(args.issue_number)}/assignees`,
@@ -868,7 +902,7 @@ async function executeGithubTool(toolName, args, auth) {
868
902
  }
869
903
 
870
904
  case 'github_list_prs': {
871
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
905
+ const { owner, repo } = parseOwnerRepoArg(args);
872
906
  const query = { per_page: Math.min(Number(args.max_results) || 30, 100) };
873
907
  if (args.state) query.state = args.state;
874
908
  if (args.sort) query.sort = args.sort;
@@ -880,14 +914,14 @@ async function executeGithubTool(toolName, args, auth) {
880
914
  }
881
915
 
882
916
  case 'github_get_pr': {
883
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
917
+ const { owner, repo } = parseOwnerRepoArg(args);
884
918
  return await githubApiRequest(auth, {
885
919
  path: `/repos/${owner}/${repo}/pulls/${Number(args.pr_number)}`,
886
920
  });
887
921
  }
888
922
 
889
923
  case 'github_create_pr': {
890
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
924
+ const { owner, repo } = parseOwnerRepoArg(args);
891
925
  return await githubApiRequest(auth, {
892
926
  method: 'POST',
893
927
  path: `/repos/${owner}/${repo}/pulls`,
@@ -903,7 +937,7 @@ async function executeGithubTool(toolName, args, auth) {
903
937
  }
904
938
 
905
939
  case 'github_update_pr': {
906
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
940
+ const { owner, repo } = parseOwnerRepoArg(args);
907
941
  const body = {};
908
942
  if (args.title) body.title = String(args.title);
909
943
  if (args.body !== undefined) body.body = String(args.body);
@@ -916,7 +950,7 @@ async function executeGithubTool(toolName, args, auth) {
916
950
  }
917
951
 
918
952
  case 'github_merge_pr': {
919
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
953
+ const { owner, repo } = parseOwnerRepoArg(args);
920
954
  return await githubApiRequest(auth, {
921
955
  method: 'PUT',
922
956
  path: `/repos/${owner}/${repo}/pulls/${Number(args.pr_number)}/merge`,
@@ -929,7 +963,7 @@ async function executeGithubTool(toolName, args, auth) {
929
963
  }
930
964
 
931
965
  case 'github_list_commits': {
932
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
966
+ const { owner, repo } = parseOwnerRepoArg(args);
933
967
  const query = { per_page: Math.min(Number(args.max_results) || 30, 100) };
934
968
  if (args.sha) query.sha = String(args.sha);
935
969
  if (args.path) query.path = String(args.path);
@@ -940,7 +974,7 @@ async function executeGithubTool(toolName, args, auth) {
940
974
  }
941
975
 
942
976
  case 'github_list_branches': {
943
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
977
+ const { owner, repo } = parseOwnerRepoArg(args);
944
978
  return await githubApiRequest(auth, {
945
979
  path: `/repos/${owner}/${repo}/branches`,
946
980
  query: buildPaginationParams({ per_page: args.max_results }),
@@ -948,7 +982,7 @@ async function executeGithubTool(toolName, args, auth) {
948
982
  }
949
983
 
950
984
  case 'github_get_branch': {
951
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
985
+ const { owner, repo } = parseOwnerRepoArg(args);
952
986
  const branch = encodeURIComponent(String(args.branch || ''));
953
987
  return await githubApiRequest(auth, {
954
988
  path: `/repos/${owner}/${repo}/branches/${branch}`,
@@ -956,7 +990,7 @@ async function executeGithubTool(toolName, args, auth) {
956
990
  }
957
991
 
958
992
  case 'github_list_collaborators': {
959
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
993
+ const { owner, repo } = parseOwnerRepoArg(args);
960
994
  const maxResults = parsePositiveInt(args.max_results, 30);
961
995
  const perPage = Math.min(100, maxResults);
962
996
  const query = {
@@ -979,7 +1013,7 @@ async function executeGithubTool(toolName, args, auth) {
979
1013
  }
980
1014
 
981
1015
  case 'github_get_content': {
982
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
1016
+ const { owner, repo } = parseOwnerRepoArg(args);
983
1017
  const query = {};
984
1018
  if (args.ref) query.ref = String(args.ref);
985
1019
  const result = await githubApiRequest(auth, {
@@ -994,7 +1028,7 @@ async function executeGithubTool(toolName, args, auth) {
994
1028
  }
995
1029
 
996
1030
  case 'github_create_or_update_file': {
997
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
1031
+ const { owner, repo } = parseOwnerRepoArg(args);
998
1032
  return await githubApiRequest(auth, {
999
1033
  method: 'PUT',
1000
1034
  path: `/repos/${owner}/${repo}/contents/${String(args.path || '')}`,
@@ -1008,7 +1042,7 @@ async function executeGithubTool(toolName, args, auth) {
1008
1042
  }
1009
1043
 
1010
1044
  case 'github_delete_file': {
1011
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
1045
+ const { owner, repo } = parseOwnerRepoArg(args);
1012
1046
  return await githubApiRequest(auth, {
1013
1047
  method: 'DELETE',
1014
1048
  path: `/repos/${owner}/${repo}/contents/${String(args.path || '')}`,
@@ -1021,7 +1055,7 @@ async function executeGithubTool(toolName, args, auth) {
1021
1055
  }
1022
1056
 
1023
1057
  case 'github_list_workflow_runs': {
1024
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
1058
+ const { owner, repo } = parseOwnerRepoArg(args);
1025
1059
  let path = `/repos/${owner}/${repo}/actions/runs`;
1026
1060
  if (args.workflow_id) {
1027
1061
  path = `/repos/${owner}/${repo}/actions/workflows/${String(args.workflow_id)}/runs`;
@@ -1050,14 +1084,14 @@ async function executeGithubTool(toolName, args, auth) {
1050
1084
  }
1051
1085
 
1052
1086
  case 'github_get_workflow_run': {
1053
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
1087
+ const { owner, repo } = parseOwnerRepoArg(args);
1054
1088
  return await githubApiRequest(auth, {
1055
1089
  path: `/repos/${owner}/${repo}/actions/runs/${Number(args.run_id)}`,
1056
1090
  });
1057
1091
  }
1058
1092
 
1059
1093
  case 'github_trigger_workflow': {
1060
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
1094
+ const { owner, repo } = parseOwnerRepoArg(args);
1061
1095
  let inputs = {};
1062
1096
  if (args.inputs) {
1063
1097
  try {
@@ -1077,7 +1111,7 @@ async function executeGithubTool(toolName, args, auth) {
1077
1111
  }
1078
1112
 
1079
1113
  case 'github_list_workflows': {
1080
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
1114
+ const { owner, repo } = parseOwnerRepoArg(args);
1081
1115
  return await githubApiRequest(auth, {
1082
1116
  path: `/repos/${owner}/${repo}/actions/workflows`,
1083
1117
  });
@@ -1132,9 +1166,9 @@ async function executeGithubTool(toolName, args, auth) {
1132
1166
  ...parsedQuery,
1133
1167
  ...(args.query && typeof args.query === 'object' ? args.query : {}),
1134
1168
  };
1135
- } else if (args.owner_repo && !path.startsWith('/repos/') && !path.startsWith('/user') && !path.startsWith('/orgs/') && !path.startsWith('/search/')) {
1169
+ } else if (hasOwnerRepoArg(args) && !path.startsWith('/repos/') && !path.startsWith('/user') && !path.startsWith('/orgs/') && !path.startsWith('/search/')) {
1136
1170
  // Convenience: prepend /repos/{owner}/{repo} for relative paths
1137
- const { owner, repo } = parseOwnerRepo(args.owner_repo);
1171
+ const { owner, repo } = parseOwnerRepoArg(args);
1138
1172
  const relativePath = path.startsWith('/') ? path : `/${path}`;
1139
1173
  path = `/repos/${owner}/${repo}${relativePath}`;
1140
1174
  }