@krmxd/onegpt 0.2.3-beta → 0.2.4-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 +36 -1
- package/src/render.js +12 -11
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -109,6 +109,9 @@ const TOOL_GUIDANCE = (
|
|
|
109
109
|
"'/home/user/...' or '/Users/...' - they do not exist on this machine.\n" +
|
|
110
110
|
"- Tool arguments are REAL values: 'path': 'my_folder/app.py'. Never send the " +
|
|
111
111
|
"parameter schema ({'type': 'string'}) as a value, and never leave arguments empty.\n" +
|
|
112
|
+
"- Call tools ONLY as exact JSON: {\"name\": \"write_file\", \"arguments\": {...}}. " +
|
|
113
|
+
"NEVER invent formats like 'name_file:path' or bare '<html>' dumps - those are NOT " +
|
|
114
|
+
"tool calls, they will be ignored, and you must redo them properly.\n" +
|
|
112
115
|
"- To act, output plain JSON tool calls (never shell commands in code fences):\n" +
|
|
113
116
|
'{"name": "write_file", "arguments": {"path": "widgets/gadget.py", ' +
|
|
114
117
|
'"content": "print(\'hi\')"}}\n' +
|
|
@@ -195,6 +198,21 @@ function repliedWithoutActing(reply) {
|
|
|
195
198
|
return SLOTH_RE.test(reply) || reply.includes("```");
|
|
196
199
|
}
|
|
197
200
|
|
|
201
|
+
// Tiny models degenerate into printing the same chunk over and over
|
|
202
|
+
// ("name_file:web <html>..." x20). Detect any meaningful line repeated
|
|
203
|
+
// too many times so the agent can cut the run instead of spamming chat.
|
|
204
|
+
function degenerateRepeat(text, minLen = 12, maxHits = 4) {
|
|
205
|
+
const counts = new Map();
|
|
206
|
+
for (const rawLine of String(text || "").split("\n")) {
|
|
207
|
+
const line = rawLine.trim();
|
|
208
|
+
if (line.length < minLen) continue;
|
|
209
|
+
const n = (counts.get(line) || 0) + 1;
|
|
210
|
+
counts.set(line, n);
|
|
211
|
+
if (n >= maxHits) return line;
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
198
216
|
// "Created the folder." style announcements. Harmless on their own, but a
|
|
199
217
|
// red flag when the request named files that were never actually created
|
|
200
218
|
// (e.g. 'a folder AND an index.html' - folder done, file skipped).
|
|
@@ -607,6 +625,7 @@ class Agent {
|
|
|
607
625
|
let nudges = 0;
|
|
608
626
|
this._autoChecks = 0;
|
|
609
627
|
let lastSig = null;
|
|
628
|
+
let collectedText = "";
|
|
610
629
|
let loopBreaks = 0;
|
|
611
630
|
const doneBits = [];
|
|
612
631
|
|
|
@@ -733,6 +752,7 @@ class Agent {
|
|
|
733
752
|
let nTokens = 0;
|
|
734
753
|
this.lastRun = {};
|
|
735
754
|
let lastSig = null;
|
|
755
|
+
let collectedText = "";
|
|
736
756
|
let loopBreaks = 0;
|
|
737
757
|
const doneBits = [];
|
|
738
758
|
let sawText = false;
|
|
@@ -781,6 +801,20 @@ class Agent {
|
|
|
781
801
|
}
|
|
782
802
|
|
|
783
803
|
const full = contentParts.join("");
|
|
804
|
+
// Degeneration breaker: same meaningful line 4+ times in ONE round
|
|
805
|
+
// (or across the whole reply) -> stop instead of spamming chat.
|
|
806
|
+
const rep = degenerateRepeat(full)
|
|
807
|
+
|| (full.trim().length < 40 && degenerateRepeat(collectedText, 8, 6));
|
|
808
|
+
if (rep) {
|
|
809
|
+
this.history.push({ role: "assistant", content: full, ts: Date.now() / 1000 });
|
|
810
|
+
yield "\n· repeated output detected - cutting it off\n";
|
|
811
|
+
if (wantsAction(userInput)) {
|
|
812
|
+
this.history.push({ role: "user", content: redirectMsg(userInput), ts: Date.now() / 1000 });
|
|
813
|
+
if (loopBreaks < 2) { loopBreaks++; continue; }
|
|
814
|
+
}
|
|
815
|
+
break;
|
|
816
|
+
}
|
|
817
|
+
collectedText = (collectedText ? collectedText + "\n" : "") + full;
|
|
784
818
|
this.usage.prompt += usage.prompt;
|
|
785
819
|
this.usage.completion += usage.completion;
|
|
786
820
|
this.usage.total += usage.total;
|
|
@@ -966,4 +1000,5 @@ class Agent {
|
|
|
966
1000
|
}
|
|
967
1001
|
|
|
968
1002
|
module.exports = { Agent, extractJsonTools, repairToolJson, wantsAction,
|
|
969
|
-
repliedWithoutActing, stalledHalfway, syntaxCheckError, autoCheckMsg
|
|
1003
|
+
repliedWithoutActing, stalledHalfway, syntaxCheckError, autoCheckMsg,
|
|
1004
|
+
degenerateRepeat };
|
package/src/render.js
CHANGED
|
@@ -257,18 +257,19 @@ class SmoothPrinter {
|
|
|
257
257
|
let preview = this.buf;
|
|
258
258
|
if (preview.length > MAX_PREVIEW_CHARS) preview = preview.slice(-MAX_PREVIEW_CHARS);
|
|
259
259
|
const rendered = renderMarkdown(preview, width);
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
const maxRows = (this.out.rows || 2000) -
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
260
|
+
let lines = rendered.split("\n");
|
|
261
|
+
const target = Math.max(0, lines.length - 1);
|
|
262
|
+
const maxRows = Math.max(3, (this.out.rows || 2000) - 2);
|
|
263
|
+
// Viewport with INCREMENTAL REVEAL: grow by one row per tick so the
|
|
264
|
+
// painted block never pushes past the screen edge (which would scroll
|
|
265
|
+
// ghosts in and desync the next erase). Once at maxRows it repaints a
|
|
266
|
+
// stable window; finish() prints the complete styled message.
|
|
267
|
+
let take = Math.min(target, maxRows, this.drawn + 1);
|
|
268
|
+
if (target < take) take = target;
|
|
269
|
+
lines = lines.slice(-(take + 1));
|
|
269
270
|
this._erase();
|
|
270
|
-
this.out.write(
|
|
271
|
-
this.drawn =
|
|
271
|
+
this.out.write(lines.join("\n"));
|
|
272
|
+
this.drawn = Math.max(0, lines.length - 1);
|
|
272
273
|
this.paintWidth = cols || width;
|
|
273
274
|
this.lastPaint = now;
|
|
274
275
|
}
|