kiosapi 0.1.8 → 0.1.9

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 CHANGED
@@ -368,6 +368,10 @@ 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
+ // Sliding window of recent tool-call signatures (name + serialised args) across all steps.
372
+ // Used to detect the model repeating the same call in a stuck loop (e.g. daftar . × 20).
373
+ const recentSigs = [];
374
+ const LOOP_THRESHOLD = 3;
371
375
  const stepLimit = s.maxSteps ?? MAX_STEPS;
372
376
  for (let step = 0; step < stepLimit; step++) {
373
377
  const stop = thinking();
@@ -406,6 +410,30 @@ export async function runTurn(s, userText) {
406
410
  s.totalTokens += totalIn + totalOut;
407
411
  return lastText;
408
412
  }
413
+ // --- Loop detection: push new signatures, then check if last N are identical ---
414
+ for (const call of calls) {
415
+ recentSigs.push(`${call.function.name}:${call.function.arguments}`);
416
+ }
417
+ if (recentSigs.length > LOOP_THRESHOLD * 3) {
418
+ recentSigs.splice(0, recentSigs.length - LOOP_THRESHOLD * 3);
419
+ }
420
+ if (recentSigs.length >= LOOP_THRESHOLD) {
421
+ const tail = recentSigs.slice(-LOOP_THRESHOLD);
422
+ if (tail.every((sig) => sig === tail[0])) {
423
+ const loopName = calls[0]?.function.name ?? 'unknown';
424
+ console.log(red(`\n⚠ Loop terdeteksi: "${loopName}" dipanggil ${LOOP_THRESHOLD}× berturut-turut dengan argumen sama.`));
425
+ console.log(yellow('Berikan instruksi baru, atau ketik /bersih untuk mulai ulang.'));
426
+ // Push error tool results for all calls in this step so history stays balanced.
427
+ const loopMsg = `⚠ LOOP TERDETEKSI: "${loopName}" sudah dipanggil ${LOOP_THRESHOLD}× dengan argumen yang sama. BERHENTI memanggil tool ini. Gunakan tool "selesai" dengan penjelasan bahwa tugas tidak dapat diselesaikan, atau tunggu instruksi baru dari pengguna.`;
428
+ for (const call of calls) {
429
+ s.messages.push({ role: 'tool', content: loopMsg, tool_call_id: call.id });
430
+ }
431
+ saveCheckpoint(s);
432
+ showUsage();
433
+ s.totalTokens += totalIn + totalOut;
434
+ return lastText;
435
+ }
436
+ }
409
437
  const stepModified = new Set();
410
438
  for (const call of calls) {
411
439
  const result = await runTool(call, s.otomatis, s.model);
@@ -195,5 +195,7 @@ Aturan:
195
195
  - Path selalu relatif ke direktori kerja; akses ke luar ditolak.
196
196
  - Gunakan hapus_file/pindah_file untuk menghapus/memindahkan file (lebih aman dari jalankan del/rm).
197
197
  - Buat perubahan kecil dan jelas. Setelah tugas beres, panggil tool "selesai" dengan ringkasan.
198
+ - JANGAN memanggil tool yang sama dengan argumen yang sama lebih dari 1× berturut-turut. Jika sudah mendapat hasil daftar_file atau baca_file, langsung lanjutkan — JANGAN ulangi panggilan yang sama.
199
+ - Jika tidak tahu harus berbuat apa selanjutnya, gunakan tool "selesai" dan jelaskan apa yang sudah ditemukan.
198
200
  - Jawab dan jelaskan dalam Bahasa Indonesia.`;
199
201
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kiosapi",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "description": "CLI Kiosapi.id berbahasa Indonesia — bangun aplikasimu pakai API key Kiosapi (agen + multimodal).",
6
6
  "keywords": [
@@ -28,7 +28,10 @@
28
28
  "bin": {
29
29
  "kiosapi": "./dist/index.js"
30
30
  },
31
- "files": ["dist", "README.md"],
31
+ "files": [
32
+ "dist",
33
+ "README.md"
34
+ ],
32
35
  "engines": {
33
36
  "node": ">=20"
34
37
  },