@krmxd/onegpt 0.2.2-beta → 0.2.3-beta
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/agent.js +58 -1
- package/src/render.js +7 -7
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -10,6 +10,41 @@ const path = require("path");
|
|
|
10
10
|
const { getConfig } = require("./config");
|
|
11
11
|
const { getSharedProvider } = require("./ollama");
|
|
12
12
|
const { ToolRegistry } = require("./tools");
|
|
13
|
+
const { spawnSync } = require("child_process");
|
|
14
|
+
|
|
15
|
+
// --- auto syntax check for AI-written code -------------------------------
|
|
16
|
+
const CHECKABLE_EXT = new Set([".py", ".js", ".mjs", ".cjs"]);
|
|
17
|
+
|
|
18
|
+
function _pick(binaries, args, timeoutMs) {
|
|
19
|
+
for (const bin of binaries) {
|
|
20
|
+
try {
|
|
21
|
+
const r = spawnSync(bin, args, { timeout: timeoutMs });
|
|
22
|
+
if (r.status === 0) return null;
|
|
23
|
+
if (r.error && r.error.code === "ENOENT") continue;
|
|
24
|
+
const err = (r.stderr ? r.stderr.toString() : "")
|
|
25
|
+
|| (r.stdout ? r.stdout.toString() : "") || `exit ${r.status}`;
|
|
26
|
+
return err.split("\n").filter((l) => l.trim()).slice(0, 4).join("\n").slice(0, 500);
|
|
27
|
+
} catch { /* try next */ }
|
|
28
|
+
}
|
|
29
|
+
return null; // no interpreter available - skip silently
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function syntaxCheckError(filePath) {
|
|
33
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
34
|
+
if (!CHECKABLE_EXT.has(ext)) return null;
|
|
35
|
+
if (!fs.existsSync(filePath)) return null;
|
|
36
|
+
if (ext === ".py") {
|
|
37
|
+
return _pick(["python3", "python"], ["-m", "py_compile", filePath], 15000);
|
|
38
|
+
}
|
|
39
|
+
return _pick([process.execPath || "node", "node"], ["--check", filePath], 15000);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function autoCheckMsg(p, err) {
|
|
43
|
+
// Loop-break redirect style: tiny models need the exact shape again.
|
|
44
|
+
return "[auto-check] The file you just wrote FAILED its syntax check:\n" +
|
|
45
|
+
`${p}\n${err}\n` +
|
|
46
|
+
"Rewrite the ENTIRE file correctly NOW with write_file (bare JSON tool call), fixing every reported error. Do not explain.";
|
|
47
|
+
}
|
|
13
48
|
|
|
14
49
|
const TOOL_RE = /\x00TOOL:([^:]*):([^:]*):(.*?)\x00/g;
|
|
15
50
|
const USAGE_RE = /\x00USAGE:(.*?)\x00/;
|
|
@@ -570,6 +605,7 @@ class Agent {
|
|
|
570
605
|
let full = "";
|
|
571
606
|
let rounds = 0;
|
|
572
607
|
let nudges = 0;
|
|
608
|
+
this._autoChecks = 0;
|
|
573
609
|
let lastSig = null;
|
|
574
610
|
let loopBreaks = 0;
|
|
575
611
|
const doneBits = [];
|
|
@@ -633,6 +669,15 @@ class Agent {
|
|
|
633
669
|
doneBits.push(result.output.split("\n")[0].slice(0, 90));
|
|
634
670
|
const ev = codeEvent(tc, pre);
|
|
635
671
|
if (ev) full += (full.trim() ? "\n\n" : "") + codeMarkdown(ev);
|
|
672
|
+
// Auto syntax check: broken AI-written code gets one bounce-back.
|
|
673
|
+
if (ev && (tc.name === "write_file" || tc.name === "edit_file")
|
|
674
|
+
&& this._autoChecks < 2) {
|
|
675
|
+
const err = syntaxCheckError(ev.path);
|
|
676
|
+
if (err) {
|
|
677
|
+
this._autoChecks++;
|
|
678
|
+
this.history.push({ role: "user", content: autoCheckMsg(ev.path, err), ts: Date.now() / 1000 });
|
|
679
|
+
}
|
|
680
|
+
}
|
|
636
681
|
}
|
|
637
682
|
}
|
|
638
683
|
} else {
|
|
@@ -682,6 +727,7 @@ class Agent {
|
|
|
682
727
|
this.history.push({ role: "user", content: userInput, ts: Date.now() / 1000 });
|
|
683
728
|
let rounds = 0;
|
|
684
729
|
let nudges = 0;
|
|
730
|
+
this._autoChecks = 0;
|
|
685
731
|
const tStart = Date.now();
|
|
686
732
|
let ttft = 0;
|
|
687
733
|
let nTokens = 0;
|
|
@@ -790,6 +836,16 @@ class Agent {
|
|
|
790
836
|
}
|
|
791
837
|
const ev = codeEvent(tc, pre);
|
|
792
838
|
if (ev) yield "\n" + codeMarkdown(ev) + "\n";
|
|
839
|
+
// Auto syntax check: broken AI-written code gets one bounce-back.
|
|
840
|
+
if (ev && (tc.name === "write_file" || tc.name === "edit_file")
|
|
841
|
+
&& this._autoChecks < 2) {
|
|
842
|
+
const err = syntaxCheckError(ev.path);
|
|
843
|
+
if (err) {
|
|
844
|
+
this._autoChecks++;
|
|
845
|
+
yield `\n[auto-check] ${path.basename(ev.path)} has a syntax error - fixing...\n`;
|
|
846
|
+
this.history.push({ role: "user", content: autoCheckMsg(ev.path, err), ts: Date.now() / 1000 });
|
|
847
|
+
}
|
|
848
|
+
}
|
|
793
849
|
}
|
|
794
850
|
}
|
|
795
851
|
} else {
|
|
@@ -909,4 +965,5 @@ class Agent {
|
|
|
909
965
|
}
|
|
910
966
|
}
|
|
911
967
|
|
|
912
|
-
module.exports = { Agent, extractJsonTools, repairToolJson, wantsAction,
|
|
968
|
+
module.exports = { Agent, extractJsonTools, repairToolJson, wantsAction,
|
|
969
|
+
repliedWithoutActing, stalledHalfway, syntaxCheckError, autoCheckMsg };
|
package/src/render.js
CHANGED
|
@@ -275,12 +275,10 @@ class SmoothPrinter {
|
|
|
275
275
|
|
|
276
276
|
_degrade(skipFlush) {
|
|
277
277
|
this.degraded = true;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
this.out.write("\n");
|
|
283
|
-
}
|
|
278
|
+
// Do NOT reprint the buffer here - part of it is already on screen
|
|
279
|
+
// and repainting would duplicate it. Just mark the seam and let the
|
|
280
|
+
// remaining chunks stream raw.
|
|
281
|
+
this.out.write("\n");
|
|
284
282
|
this.buf = "";
|
|
285
283
|
}
|
|
286
284
|
|
|
@@ -288,7 +286,9 @@ class SmoothPrinter {
|
|
|
288
286
|
if (this.closed) return;
|
|
289
287
|
this.closed = true;
|
|
290
288
|
if (this.timer) { clearTimeout(this.timer); this.timer = null; }
|
|
291
|
-
if (!this.tty
|
|
289
|
+
if (!this.tty) return;
|
|
290
|
+
// Always un-hide the cursor, degraded or not.
|
|
291
|
+
if (this.degraded) { this.out.write(`${ESC}[?25h`); return; }
|
|
292
292
|
this._erase();
|
|
293
293
|
const width = this.widthOf();
|
|
294
294
|
this.out.write(renderMarkdown(this.buf, width) + "\n");
|