neoagent 2.5.2-beta.5 → 2.5.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/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
c71ef84ad1471500295da6f6c6f13299
|
|
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"77e2e94772b6eb43759e34ed1ad7da4674e19c
|
|
|
37
37
|
|
|
38
38
|
_flutter.loader.load({
|
|
39
39
|
serviceWorkerSettings: {
|
|
40
|
-
serviceWorkerVersion: "
|
|
40
|
+
serviceWorkerVersion: "2830694115" /* 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("
|
|
134797
|
+
r=B.b.u("mqfoxi8l-ab0f828").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("
|
|
140509
|
+
if(B.b.u("mqfoxi8l-ab0f828").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,"
|
|
140527
|
+
if(J.bi(j)===0||J.d(j,"mqfoxi8l-ab0f828")){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("
|
|
140544
|
+
s=p}for(;;)switch(s){case 0:if(B.b.u("mqfoxi8l-ab0f828").length===0||n.c){s=1
|
|
140545
140545
|
break}n.c=!0
|
|
140546
140546
|
n.F()
|
|
140547
140547
|
p=4
|
|
@@ -144,6 +144,7 @@ function normalizeErrorKey(errorMsg) {
|
|
|
144
144
|
if (/enoent|no such file/i.test(msg)) return 'enoent';
|
|
145
145
|
if (/can.?t cd to|no such directory/i.test(msg)) return 'bad_cwd';
|
|
146
146
|
if (/not found/i.test(msg)) return 'not_found';
|
|
147
|
+
if (/owner_repo.*format|must be.*owner.*repo|owner.*repo.*string|owner.*repo.*combined/i.test(msg)) return 'owner_repo_format';
|
|
147
148
|
return msg.slice(0, 60);
|
|
148
149
|
}
|
|
149
150
|
|
|
@@ -155,10 +156,20 @@ function trackErrorPattern(errorMsg, runMeta) {
|
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
function buildErrorPatternGuidance(key, count) {
|
|
159
|
+
// Immediate guidance on first occurrence for high-signal patterns that waste
|
|
160
|
+
// multiple iterations before self-correcting.
|
|
161
|
+
const immediateGuides = {
|
|
162
|
+
eisdir: 'That path is a directory (or a VM-only path like /tmp that read_file cannot reach). Use execute_command with `cat <path>` to read files inside VMs, or list_directory to inspect a directory.',
|
|
163
|
+
owner_repo_format: 'The parameter "owner_repo" expects a single combined string like "NeoLabs-Systems/NeoAgent" — not separate owner/repo fields. Pass the full "owner/repo" as one value.',
|
|
164
|
+
};
|
|
165
|
+
if (immediateGuides[key]) {
|
|
166
|
+
const prefix = count > 1 ? `REPEATED ERROR (${count}×): ` : 'ERROR GUIDANCE: ';
|
|
167
|
+
return `${prefix}${immediateGuides[key]}`;
|
|
168
|
+
}
|
|
169
|
+
|
|
158
170
|
if (count < 3) return null;
|
|
159
171
|
const guides = {
|
|
160
172
|
outside_workspace: 'read_file cannot access /tmp paths. Use execute_command with `cat <path>` instead.',
|
|
161
|
-
eisdir: 'That path is a directory, not a file. Use list_directory or execute_command with `ls` to inspect it.',
|
|
162
173
|
enoent: 'That path does not exist. Use execute_command with `find . -name "..."` to locate the correct path first.',
|
|
163
174
|
bad_cwd: 'The VM home directory is not ~/. Use absolute paths starting from /tmp or discover the workspace root first.',
|
|
164
175
|
not_found: 'This path or resource was not found. Try listing the parent directory or checking with a broader search first.',
|
|
@@ -168,6 +179,19 @@ function buildErrorPatternGuidance(key, count) {
|
|
|
168
179
|
return `REPEATED ERROR (${count}×): ${guide}`;
|
|
169
180
|
}
|
|
170
181
|
|
|
182
|
+
const OUTPUT_FINGERPRINT_TOOLS = /^(list_|search_|read_|get_|find_|github_list|github_get|github_search)/;
|
|
183
|
+
|
|
184
|
+
function fingerprintOutput(toolName, result) {
|
|
185
|
+
if (!toolName || !OUTPUT_FINGERPRINT_TOOLS.test(toolName)) return null;
|
|
186
|
+
const raw = typeof result === 'string' ? result : JSON.stringify(result ?? '');
|
|
187
|
+
if (raw.length < 200) return null;
|
|
188
|
+
// djb2 hash over first 3000 chars — fast, collision-unlikely for our sizes
|
|
189
|
+
let h = 5381;
|
|
190
|
+
const limit = Math.min(raw.length, 3000);
|
|
191
|
+
for (let i = 0; i < limit; i++) h = ((h << 5) + h) ^ raw.charCodeAt(i);
|
|
192
|
+
return h >>> 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
171
195
|
function resolveModelCallTimeoutMs(options = {}) {
|
|
172
196
|
const requested = Number(options?.modelCallTimeoutMs);
|
|
173
197
|
if (Number.isFinite(requested) && requested > 0) {
|
|
@@ -2228,7 +2252,7 @@ class AgentEngine {
|
|
|
2228
2252
|
if (!runMeta || runMeta.aborted || runMeta.triggerSource !== 'messaging') {
|
|
2229
2253
|
return { sent: false, skipped: true };
|
|
2230
2254
|
}
|
|
2231
|
-
if (runMeta.
|
|
2255
|
+
if (runMeta.terminalInterim) {
|
|
2232
2256
|
return { sent: false, skipped: true };
|
|
2233
2257
|
}
|
|
2234
2258
|
|
|
@@ -2596,6 +2620,7 @@ class AgentEngine {
|
|
|
2596
2620
|
this.activeRuns.set(runId, {
|
|
2597
2621
|
userId,
|
|
2598
2622
|
agentId,
|
|
2623
|
+
title: runTitle,
|
|
2599
2624
|
status: 'running',
|
|
2600
2625
|
aborted: false,
|
|
2601
2626
|
messagingSent: false,
|
|
@@ -2622,6 +2647,7 @@ class AgentEngine {
|
|
|
2622
2647
|
systemSteeringQueue: [],
|
|
2623
2648
|
toolPids: new Set(),
|
|
2624
2649
|
repetitionGuard: new ToolRepetitionGuard(),
|
|
2650
|
+
seenOutputHashes: new Map(),
|
|
2625
2651
|
messagingContext: triggerSource === 'messaging'
|
|
2626
2652
|
? {
|
|
2627
2653
|
platform: options.source || null,
|
|
@@ -3010,6 +3036,13 @@ class AgentEngine {
|
|
|
3010
3036
|
}
|
|
3011
3037
|
messages = sanitizeConversationMessages(messages);
|
|
3012
3038
|
|
|
3039
|
+
if (analysis.mode === 'execute' || analysis.mode === 'plan_execute') {
|
|
3040
|
+
messages.push({
|
|
3041
|
+
role: 'system',
|
|
3042
|
+
content: 'Research budget: after 3 read/list/search tool calls, you must take a concrete action (write, create, send, update) or explain clearly why you cannot. Work on one item at a time — do not queue up more reads.',
|
|
3043
|
+
});
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3013
3046
|
directAnswerEligible = isDirectAnswerEligibleAnalysis(analysis)
|
|
3014
3047
|
&& Boolean(normalizeOutgoingMessage(analysis.draft_reply));
|
|
3015
3048
|
|
|
@@ -3594,6 +3627,22 @@ class AgentEngine {
|
|
|
3594
3627
|
}
|
|
3595
3628
|
} else {
|
|
3596
3629
|
consecutiveToolFailures = 0;
|
|
3630
|
+
// Output fingerprint guard: steer away from re-fetching data already seen.
|
|
3631
|
+
if (!toolErrorMessage) {
|
|
3632
|
+
const currentRunMeta = this.getRunMeta(runId);
|
|
3633
|
+
const fp = fingerprintOutput(toolName, toolResult);
|
|
3634
|
+
if (fp !== null && currentRunMeta?.seenOutputHashes) {
|
|
3635
|
+
const prior = currentRunMeta.seenOutputHashes.get(fp);
|
|
3636
|
+
if (prior) {
|
|
3637
|
+
messages.push({
|
|
3638
|
+
role: 'system',
|
|
3639
|
+
content: `DUPLICATE DATA: This response is identical to what "${prior.toolName}" returned in iteration ${prior.iteration}. You already have this information. Stop fetching and use what you have — proceed to the next concrete action.`,
|
|
3640
|
+
});
|
|
3641
|
+
} else {
|
|
3642
|
+
currentRunMeta.seenOutputHashes.set(fp, { toolName, iteration });
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3597
3646
|
}
|
|
3598
3647
|
|
|
3599
3648
|
if (toolName === 'send_interim_update') {
|
|
@@ -3748,9 +3797,43 @@ class AgentEngine {
|
|
|
3748
3797
|
);
|
|
3749
3798
|
}
|
|
3750
3799
|
if (iteration >= maxIterations) {
|
|
3751
|
-
|
|
3800
|
+
// Grace call: budget exhausted but no content yet.
|
|
3801
|
+
// Strip tools and ask the model to summarise what it accomplished.
|
|
3802
|
+
// Mirrors the Hermes handle_max_iterations() pattern.
|
|
3803
|
+
console.warn(`[Run ${shortenRunId(runId)}] iteration_limit runId=${shortenRunId(runId)} — making grace call`);
|
|
3804
|
+
try {
|
|
3805
|
+
const graceMessages = sanitizeConversationMessages([
|
|
3806
|
+
...messages,
|
|
3807
|
+
{
|
|
3808
|
+
role: 'user',
|
|
3809
|
+
content: 'You have reached the maximum number of tool-calling iterations allowed. Please provide a final response summarising what you found and accomplished so far, without calling any more tools.',
|
|
3810
|
+
},
|
|
3811
|
+
]);
|
|
3812
|
+
const graceResponse = await withModelCallTimeout(
|
|
3813
|
+
provider.chat(graceMessages, [], {
|
|
3814
|
+
model,
|
|
3815
|
+
reasoningEffort: this.getReasoningEffort(providerName, options),
|
|
3816
|
+
}),
|
|
3817
|
+
options,
|
|
3818
|
+
`Grace call after ${maxIterations} iterations`,
|
|
3819
|
+
);
|
|
3820
|
+
totalTokens += graceResponse.usage?.totalTokens || 0;
|
|
3821
|
+
lastContent = sanitizeModelOutput(graceResponse.content || '', { model });
|
|
3822
|
+
if (lastContent) {
|
|
3823
|
+
messages.push({ role: 'assistant', content: lastContent });
|
|
3824
|
+
if (conversationId) {
|
|
3825
|
+
db.prepare('INSERT INTO conversation_messages (conversation_id, role, content, tokens) VALUES (?, ?, ?, ?)')
|
|
3826
|
+
.run(conversationId, 'assistant', lastContent, graceResponse.usage?.totalTokens || 0);
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
} catch (graceErr) {
|
|
3830
|
+
console.warn(`[Run ${shortenRunId(runId)}] grace call failed: ${graceErr?.message}`);
|
|
3831
|
+
}
|
|
3832
|
+
if (!normalizeOutgoingMessage(lastContent, options?.source || null)) {
|
|
3833
|
+
throw new Error(`Iteration limit reached before explicit completion after ${maxIterations} iterations.`);
|
|
3834
|
+
}
|
|
3752
3835
|
}
|
|
3753
|
-
if (stepIndex > 0 && !lastToolWasMessaging) {
|
|
3836
|
+
if (stepIndex > 0 && !lastToolWasMessaging && iteration < maxIterations) {
|
|
3754
3837
|
throw new Error('Run ended without an explicit completion or blocker reply.');
|
|
3755
3838
|
}
|
|
3756
3839
|
}
|