kiosapi 0.1.9 → 0.1.11
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/dist/agent/run.js +35 -24
- package/dist/commands.js +5 -0
- package/package.json +1 -1
package/dist/agent/run.js
CHANGED
|
@@ -368,10 +368,13 @@ export async function runTurn(s, userText) {
|
|
|
368
368
|
console.log(dim(` ↳ ${idn(totalIn + totalOut)} token (${idn(totalIn)} in · ${idn(totalOut)} out)`));
|
|
369
369
|
}
|
|
370
370
|
};
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
const
|
|
371
|
+
// Loop detection: count total calls per signature (tool+args) across the whole runTurn.
|
|
372
|
+
// Consecutive-3 catches obvious tight loops; count-4 catches spread-out repetition where
|
|
373
|
+
// other calls (daftar src, baca ...) appear between the repeating call.
|
|
374
|
+
const callCounts = new Map();
|
|
375
|
+
const lastSigs = []; // last 3 sigs for consecutive detection
|
|
376
|
+
const COUNT_LIMIT = 4; // same tool+args called 4× total → loop
|
|
377
|
+
const CONSEC_LIMIT = 3; // same sig 3× in a row → loop
|
|
375
378
|
const stepLimit = s.maxSteps ?? MAX_STEPS;
|
|
376
379
|
for (let step = 0; step < stepLimit; step++) {
|
|
377
380
|
const stop = thinking();
|
|
@@ -410,29 +413,37 @@ export async function runTurn(s, userText) {
|
|
|
410
413
|
s.totalTokens += totalIn + totalOut;
|
|
411
414
|
return lastText;
|
|
412
415
|
}
|
|
413
|
-
// --- Loop detection
|
|
416
|
+
// --- Loop detection before running any tools this step ---
|
|
417
|
+
let loopSig = null;
|
|
414
418
|
for (const call of calls) {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
+
const sig = `${call.function.name}:${call.function.arguments}`;
|
|
420
|
+
const count = (callCounts.get(sig) ?? 0) + 1;
|
|
421
|
+
callCounts.set(sig, count);
|
|
422
|
+
lastSigs.push(sig);
|
|
423
|
+
if (lastSigs.length > CONSEC_LIMIT)
|
|
424
|
+
lastSigs.shift();
|
|
425
|
+
// Total count exceeded, or 3 in a row
|
|
426
|
+
const consecutive = lastSigs.length === CONSEC_LIMIT && lastSigs.every((s) => s === sig);
|
|
427
|
+
if (count >= COUNT_LIMIT || consecutive) {
|
|
428
|
+
loopSig = sig;
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
419
431
|
}
|
|
420
|
-
if (
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
saveCheckpoint(s);
|
|
432
|
-
showUsage();
|
|
433
|
-
s.totalTokens += totalIn + totalOut;
|
|
434
|
-
return lastText;
|
|
432
|
+
if (loopSig !== null) {
|
|
433
|
+
const loopName = loopSig.split(':')[0] ?? 'unknown';
|
|
434
|
+
const total = callCounts.get(loopSig) ?? 0;
|
|
435
|
+
console.log(red(`\n⚠ Loop terdeteksi: "${loopName}" dipanggil ${total}× — agen terjebak.`));
|
|
436
|
+
console.log(yellow('Berikan instruksi baru, atau ketik /bersih untuk mulai ulang.'));
|
|
437
|
+
const loopMsg = `⚠ LOOP: "${loopName}" sudah dipanggil ${total}× dengan argumen yang sama. ` +
|
|
438
|
+
`JANGAN panggil lagi. Gunakan tool "selesai" dan jelaskan kendalanya, ` +
|
|
439
|
+
`atau minta klarifikasi dari pengguna.`;
|
|
440
|
+
for (const call of calls) {
|
|
441
|
+
s.messages.push({ role: 'tool', content: loopMsg, tool_call_id: call.id });
|
|
435
442
|
}
|
|
443
|
+
saveCheckpoint(s);
|
|
444
|
+
showUsage();
|
|
445
|
+
s.totalTokens += totalIn + totalOut;
|
|
446
|
+
return lastText;
|
|
436
447
|
}
|
|
437
448
|
const stepModified = new Set();
|
|
438
449
|
for (const call of calls) {
|
package/dist/commands.js
CHANGED
|
@@ -705,10 +705,15 @@ export async function cmdInit() {
|
|
|
705
705
|
const otoRaw = (await prompt('Auto-approve semua tool secara default? (y/t, Enter = t): '))
|
|
706
706
|
.trim()
|
|
707
707
|
.toLowerCase();
|
|
708
|
+
const stepsRaw = (await prompt('Batas langkah agen per sesi? (angka, Enter = 50): ')).trim();
|
|
709
|
+
const maxSteps = stepsRaw ? Number.parseInt(stepsRaw, 10) || 50 : undefined;
|
|
710
|
+
const projectContext = (await prompt('Konteks proyek (Enter untuk kosongkan; dua baris kosong = selesai):\n')).trim() || undefined;
|
|
708
711
|
const config = {
|
|
709
712
|
...(chosenModel ? { model: chosenModel } : {}),
|
|
710
713
|
mode,
|
|
711
714
|
otomatis: otoRaw === 'y' || otoRaw === 'ya',
|
|
715
|
+
...(maxSteps && maxSteps !== 50 ? { maxSteps } : {}),
|
|
716
|
+
...(projectContext ? { projectContext } : {}),
|
|
712
717
|
};
|
|
713
718
|
const p = initProjectConfig(config);
|
|
714
719
|
console.log(green(`\n✓ ${p}`));
|