natureco-cli 5.9.0 → 5.9.1
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 +1 -1
- package/src/commands/repl.js +20 -1
- package/src/utils/tool-guardrails.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.9.
|
|
3
|
+
"version": "5.9.1",
|
|
4
4
|
"description": "OpenClaw'dan daha güvenli, daha hızlı, daha ucuz AI agent CLI. Multi-agent, self-evolving skills, audit log, maliyet optimizasyonu ve NatureCo platform-native.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"natureco": "bin/natureco.js"
|
package/src/commands/repl.js
CHANGED
|
@@ -279,7 +279,7 @@ async function sendStreaming(providerUrl, providerApiKey, messages, model, onChu
|
|
|
279
279
|
let currentMessages = messages;
|
|
280
280
|
let fullText = '';
|
|
281
281
|
let iterations = 0;
|
|
282
|
-
const MAX_TOOL_ITERATIONS =
|
|
282
|
+
const MAX_TOOL_ITERATIONS = isMM ? 12 : 8;
|
|
283
283
|
const MAX_CONTEXT_TOKENS = 32000; // safety limit before compression
|
|
284
284
|
|
|
285
285
|
// v5.7.18: Preflight compression — if context too long, compress middle messages
|
|
@@ -497,6 +497,25 @@ async function processToolCalls(toolCalls, onToolCall) {
|
|
|
497
497
|
if (onToolCall) onToolCall({ name: '_no_progress', args: null, status: 'done', result: { error: 'All tools failed this iteration' } });
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
+
// Same-tool loop detection: if same tool called >3x this iteration (regardless of success)
|
|
501
|
+
const toolCallCounts = {};
|
|
502
|
+
for (const { name } of results) {
|
|
503
|
+
toolCallCounts[name] = (toolCallCounts[name] || 0) + 1;
|
|
504
|
+
}
|
|
505
|
+
for (const [name, count] of Object.entries(toolCallCounts)) {
|
|
506
|
+
if (count > 3) {
|
|
507
|
+
const loopResult = results.find(r => r.name === name);
|
|
508
|
+
if (loopResult && !loopResult.result?.error) {
|
|
509
|
+
const warnContent = JSON.stringify({
|
|
510
|
+
_loop_warning: true,
|
|
511
|
+
message: `${name} called ${count}x this turn. If you're not making progress, try a different approach or report the result.`,
|
|
512
|
+
tool: name, call_count: count,
|
|
513
|
+
});
|
|
514
|
+
results.push({ name: '_loop_warning', id: `loop_${Date.now()}`, result: { result: warnContent } });
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
500
519
|
// Notify UI done + build messages
|
|
501
520
|
const messages = [];
|
|
502
521
|
for (const { name, id, result } of results) {
|
|
@@ -14,6 +14,7 @@ const IDEMPOTENT_TOOLS = new Set([
|
|
|
14
14
|
'web_search', 'web_readability', 'duckduckgo_search',
|
|
15
15
|
'exa_search', 'searxng_search', 'firecrawl',
|
|
16
16
|
'memory_search', 'memory', 'list_dir',
|
|
17
|
+
'browser', // browser snapshots are idempotent
|
|
17
18
|
]);
|
|
18
19
|
|
|
19
20
|
const MUTATING_TOOLS = new Set([
|