kiosapi 0.1.21 → 0.1.23
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 +29 -17
- package/dist/agent/schemas.js +8 -4
- package/dist/agent/tools.js +18 -5
- package/package.json +1 -1
package/dist/agent/run.js
CHANGED
|
@@ -251,11 +251,15 @@ async function runTool(call, otomatis, model) {
|
|
|
251
251
|
const str = (k) => (typeof args[k] === 'string' ? args[k] : '');
|
|
252
252
|
try {
|
|
253
253
|
switch (call.function.name) {
|
|
254
|
-
case 'baca_file':
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
case 'baca_file': {
|
|
255
|
+
const mulai = typeof args.mulai === 'number' ? Math.floor(args.mulai) : undefined;
|
|
256
|
+
const sampai = typeof args.sampai === 'number' ? Math.floor(args.sampai) : undefined;
|
|
257
|
+
const rangeStr = mulai != null ? ` baris ${mulai}${sampai != null ? `–${sampai}` : '+'}` : '';
|
|
258
|
+
console.log(dim(` baca ${str('path')}${rangeStr}`));
|
|
259
|
+
return { output: bacaFile(str('path'), mulai, sampai) };
|
|
260
|
+
}
|
|
257
261
|
case 'daftar_file': {
|
|
258
|
-
const ked = typeof args
|
|
262
|
+
const ked = typeof args.kedalaman === 'number' ? args.kedalaman : undefined;
|
|
259
263
|
const dPath = str('path') || '.';
|
|
260
264
|
console.log(dim(` daftar ${dPath}${ked != null ? ` (kedalaman ${ked})` : ''}`));
|
|
261
265
|
return { output: daftarFile(dPath, ked) };
|
|
@@ -406,7 +410,9 @@ export async function runTurn(s, userText) {
|
|
|
406
410
|
try {
|
|
407
411
|
snippets.push(`<root-directory>\n${daftarFile('.', 2)}\n</root-directory>`);
|
|
408
412
|
}
|
|
409
|
-
catch {
|
|
413
|
+
catch {
|
|
414
|
+
/* ignore */
|
|
415
|
+
}
|
|
410
416
|
for (const f of ['package.json', 'pyproject.toml', 'Cargo.toml', 'go.mod']) {
|
|
411
417
|
const abs = join(process.cwd(), f);
|
|
412
418
|
if (existsSync(abs)) {
|
|
@@ -415,7 +421,9 @@ export async function runTurn(s, userText) {
|
|
|
415
421
|
// 1500 chars: enough for name/scripts/deps, not the full lockfile prose
|
|
416
422
|
snippets.push(`<file path="${f}">\n${content.slice(0, 1_500)}\n</file>`);
|
|
417
423
|
}
|
|
418
|
-
catch {
|
|
424
|
+
catch {
|
|
425
|
+
/* unreadable — skip */
|
|
426
|
+
}
|
|
419
427
|
}
|
|
420
428
|
}
|
|
421
429
|
if (snippets.length > 0) {
|
|
@@ -523,9 +531,7 @@ export async function runTurn(s, userText) {
|
|
|
523
531
|
const total = callCounts.get(loopSig) ?? 0;
|
|
524
532
|
console.log(red(`\n⚠ Loop terdeteksi: "${loopName}" dipanggil ${total}× — agen terjebak.`));
|
|
525
533
|
console.log(yellow('Berikan instruksi baru, atau ketik /bersih untuk mulai ulang.'));
|
|
526
|
-
const loopMsg = `⚠ LOOP: "${loopName}" sudah dipanggil ${total}× dengan argumen yang sama.
|
|
527
|
-
`JANGAN panggil lagi. Gunakan tool "selesai" dan jelaskan kendalanya, ` +
|
|
528
|
-
`atau minta klarifikasi dari pengguna.`;
|
|
534
|
+
const loopMsg = `⚠ LOOP: "${loopName}" sudah dipanggil ${total}× dengan argumen yang sama. JANGAN panggil lagi. Gunakan tool "selesai" dan jelaskan kendalanya, atau minta klarifikasi dari pengguna.`;
|
|
529
535
|
for (const call of calls) {
|
|
530
536
|
s.messages.push({ role: 'tool', content: loopMsg, tool_call_id: call.id });
|
|
531
537
|
}
|
|
@@ -545,11 +551,8 @@ export async function runTurn(s, userText) {
|
|
|
545
551
|
const toolName = call.function.name;
|
|
546
552
|
const cachedOut = toolCache.get(sig) ?? '';
|
|
547
553
|
const warn = count >= COUNT_LIMIT - 1
|
|
548
|
-
? `⚠ STOP: "${toolName}" sudah dipanggil ${count}× dengan argumen yang sama —
|
|
549
|
-
|
|
550
|
-
: `[Cache — identik dengan panggilan sebelumnya]\n${cachedOut}\n\n` +
|
|
551
|
-
`⚠ Kamu sudah memanggil "${toolName}" dengan argumen yang sama ${count}×. ` +
|
|
552
|
-
`Jangan ulangi — masuk ke subfolder spesifik atau gunakan "selesai".`;
|
|
554
|
+
? `⚠ STOP: "${toolName}" sudah dipanggil ${count}× dengan argumen yang sama — hasilnya tidak berubah. WAJIB gunakan tool "selesai" atau eksplorasi path BERBEDA.`
|
|
555
|
+
: `[Cache — identik dengan panggilan sebelumnya]\n${cachedOut}\n\n⚠ Kamu sudah memanggil "${toolName}" dengan argumen yang sama ${count}×. Jangan ulangi — masuk ke subfolder spesifik atau gunakan "selesai".`;
|
|
553
556
|
console.log(dim(` ↩ ${toolName} (cache ke-${count})`));
|
|
554
557
|
s.messages.push({ role: 'tool', content: warn, tool_call_id: call.id });
|
|
555
558
|
continue;
|
|
@@ -559,13 +562,22 @@ export async function runTurn(s, userText) {
|
|
|
559
562
|
// listing or 100 KB of file content, which quickly overflows small-context-window models
|
|
560
563
|
// (Workers AI llama has ~8K token limit). The full result is already returned by runTool;
|
|
561
564
|
// truncating only the *stored* copy keeps the API payload manageable without losing info.
|
|
562
|
-
const MAX_STORED_RESULT =
|
|
565
|
+
const MAX_STORED_RESULT = 10_000;
|
|
563
566
|
const stored = result.output.length > MAX_STORED_RESULT
|
|
564
|
-
? `${result.output.slice(0, MAX_STORED_RESULT)}\n…[dipotong — gunakan path
|
|
567
|
+
? `${result.output.slice(0, MAX_STORED_RESULT)}\n…[dipotong — gunakan baca_file(path, baris_lanjutan) untuk membaca sisa file]`
|
|
565
568
|
: result.output;
|
|
566
569
|
s.messages.push({ role: 'tool', content: stored, tool_call_id: call.id });
|
|
567
|
-
if (result.modifiedPath)
|
|
570
|
+
if (result.modifiedPath) {
|
|
568
571
|
stepModified.add(result.modifiedPath);
|
|
572
|
+
// Invalidate cached reads for the modified file so the model can verify
|
|
573
|
+
// its own edits without getting stale content or spurious loop warnings.
|
|
574
|
+
for (const cacheSig of [...toolCache.keys()]) {
|
|
575
|
+
if (cacheSig.includes(result.modifiedPath)) {
|
|
576
|
+
toolCache.delete(cacheSig);
|
|
577
|
+
callCounts.delete(cacheSig);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
569
581
|
if (READ_ONLY_TOOLS.has(call.function.name))
|
|
570
582
|
toolCache.set(sig, stored);
|
|
571
583
|
if (result.done) {
|
package/dist/agent/schemas.js
CHANGED
|
@@ -4,10 +4,14 @@ const TOOLS = {
|
|
|
4
4
|
type: 'function',
|
|
5
5
|
function: {
|
|
6
6
|
name: 'baca_file',
|
|
7
|
-
description: 'Baca isi
|
|
7
|
+
description: 'Baca isi file. Untuk file besar yang terpotong, gunakan mulai (nomor baris 1-based) untuk membaca bagian selanjutnya.',
|
|
8
8
|
parameters: {
|
|
9
9
|
type: 'object',
|
|
10
|
-
properties: {
|
|
10
|
+
properties: {
|
|
11
|
+
path: { type: 'string', description: 'Path file' },
|
|
12
|
+
mulai: { type: 'number', description: 'Baris awal, 1-based (default: 1)' },
|
|
13
|
+
sampai: { type: 'number', description: 'Baris akhir (default: akhir file)' },
|
|
14
|
+
},
|
|
11
15
|
required: ['path'],
|
|
12
16
|
},
|
|
13
17
|
},
|
|
@@ -211,9 +215,9 @@ OS: ${osName} · ${shellNote}
|
|
|
211
215
|
Aturan:
|
|
212
216
|
- Bekerja langkah demi langkah: pakai tool untuk membaca sebelum mengubah.
|
|
213
217
|
- Strategi eksplorasi: struktur root tersedia di konteks awal — identifikasi subfolder relevan LANGSUNG, lalu baca dengan baca_file. Jangan ulangi daftar_file pada path yang sama.
|
|
214
|
-
- baca_file menampilkan "[path · N baris · M char]"
|
|
218
|
+
- baca_file menampilkan "[path · N baris · M char]" — jika ada "TERPOTONG", panggil baca_file(path, baris_lanjutan) BUKAN dengan argumen identik. Gunakan mulai/sampai untuk baca bagian tertentu.
|
|
215
219
|
- Kedalaman daftar_file: gunakan kedalaman=2 (default) untuk subfolder besar. Kedalaman=3 hanya jika kamu sudah tahu folder itu kecil. JANGAN gunakan kedalaman=4+ kecuali diminta eksplisit.
|
|
216
|
-
- JANGAN memanggil tool APAPUN dengan argumen identik lebih dari 1× dalam satu sesi. Jika tool mengembalikan peringatan cache "⚠", langsung ganti ke path atau argumen BERBEDA —
|
|
220
|
+
- JANGAN memanggil tool APAPUN dengan argumen identik lebih dari 1× dalam satu sesi. Jika tool mengembalikan peringatan cache "⚠", langsung ganti ke path atau argumen BERBEDA — untuk baca_file: gunakan mulai= berbeda atau gunakan cari.
|
|
217
221
|
- Path selalu relatif ke direktori kerja; akses ke luar ditolak.
|
|
218
222
|
- Gunakan hapus_file/pindah_file untuk menghapus/memindahkan file (lebih aman dari jalankan del/rm).
|
|
219
223
|
- Buat perubahan kecil dan jelas. Setelah tugas beres, panggil tool "selesai" dengan ringkasan.
|
package/dist/agent/tools.js
CHANGED
|
@@ -42,17 +42,30 @@ export function safePath(p) {
|
|
|
42
42
|
}
|
|
43
43
|
return { abs, rel: rel || '.' };
|
|
44
44
|
}
|
|
45
|
-
/** baca_file — read a text file. */
|
|
46
|
-
export function bacaFile(path) {
|
|
45
|
+
/** baca_file — read a text file, optionally a specific line range (1-based). */
|
|
46
|
+
export function bacaFile(path, mulai, sampai) {
|
|
47
47
|
const { abs } = safePath(path);
|
|
48
48
|
if (!existsSync(abs))
|
|
49
49
|
return `Error: file tidak ada: ${path}`;
|
|
50
50
|
const text = readFileSync(abs, 'utf8');
|
|
51
|
-
const
|
|
51
|
+
const allLines = text.split('\n');
|
|
52
|
+
const total = allLines.length;
|
|
53
|
+
if (mulai != null || sampai != null) {
|
|
54
|
+
const from = Math.max(1, Math.floor(mulai ?? 1));
|
|
55
|
+
const to = Math.min(total, Math.floor(sampai ?? total));
|
|
56
|
+
const content = allLines.slice(from - 1, to).join('\n');
|
|
57
|
+
const hint = to < total
|
|
58
|
+
? `\n\n…[baris ${to + 1}–${total} belum dibaca — panggil baca_file("${path}", ${to + 1}) untuk lanjut]`
|
|
59
|
+
: '';
|
|
60
|
+
return `[${path} · baris ${from}–${to} dari ${total}]\n${content}${hint}`;
|
|
61
|
+
}
|
|
52
62
|
if (text.length > MAX_READ) {
|
|
53
|
-
|
|
63
|
+
const sliced = text.slice(0, MAX_READ);
|
|
64
|
+
const linesShown = sliced.split('\n').length;
|
|
65
|
+
return (`[${path} · ${total} baris · ${text.length} char — menampilkan baris 1–${linesShown}]\n` +
|
|
66
|
+
`${sliced}\n\n…[TERPOTONG — panggil baca_file("${path}", ${linesShown + 1}) untuk melanjutkan]`);
|
|
54
67
|
}
|
|
55
|
-
return `[${path} · ${
|
|
68
|
+
return `[${path} · ${total} baris · ${text.length} char]\n${text}`;
|
|
56
69
|
}
|
|
57
70
|
/** daftar_file — list a directory (ignored entries hidden).
|
|
58
71
|
* kedalaman controls tree depth (1–5). Defaults: 3 for root ".", 1 for subdirs.
|