@noobdemon/noob-cli 1.5.3 → 1.5.4
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 -12
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -175,24 +175,48 @@ function buildPrompt(history) {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
// Extract a single tool call from an assistant message, if present.
|
|
178
|
+
// NOTE: we do NOT match up to a closing ``` fence — write_file content routinely
|
|
179
|
+
// contains its own ```code``` fences (e.g. a README), and the first inner fence
|
|
180
|
+
// would close the block early and break the JSON. Instead, find the ```tool (or
|
|
181
|
+
// ```json) opener and brace-match the first balanced JSON object after it.
|
|
178
182
|
export function parseToolCall(text) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const j = text.match(/```json\s*\n([\s\S]*?)```/);
|
|
184
|
-
if (j && /"name"\s*:/.test(j[1])) m = j;
|
|
185
|
-
}
|
|
186
|
-
if (!m) return null;
|
|
187
|
-
try {
|
|
188
|
-
const obj = JSON.parse(m[1].trim());
|
|
183
|
+
for (const fence of ["tool", "json"]) {
|
|
184
|
+
const open = text.match(new RegExp("```" + fence + "[ \\t]*\\n"));
|
|
185
|
+
if (!open) continue;
|
|
186
|
+
const obj = extractJsonObject(text, open.index + open[0].length);
|
|
189
187
|
if (obj && typeof obj.name === "string") return { name: obj.name, input: obj.input || {} };
|
|
190
|
-
} catch {
|
|
191
|
-
/* malformed — treat as prose */
|
|
192
188
|
}
|
|
193
189
|
return null;
|
|
194
190
|
}
|
|
195
191
|
|
|
192
|
+
// Parse the first balanced {…} at/after `from`, tracking string literals and
|
|
193
|
+
// escapes so braces or backticks INSIDE string values don't throw off the depth
|
|
194
|
+
// count. Returns the parsed object, or null if malformed/truncated (unbalanced).
|
|
195
|
+
function extractJsonObject(s, from) {
|
|
196
|
+
const start = s.indexOf("{", from);
|
|
197
|
+
if (start === -1) return null;
|
|
198
|
+
let depth = 0, inStr = false, esc = false;
|
|
199
|
+
for (let i = start; i < s.length; i++) {
|
|
200
|
+
const ch = s[i];
|
|
201
|
+
if (inStr) {
|
|
202
|
+
if (esc) esc = false;
|
|
203
|
+
else if (ch === "\\") esc = true;
|
|
204
|
+
else if (ch === '"') inStr = false;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (ch === '"') inStr = true;
|
|
208
|
+
else if (ch === "{") depth++;
|
|
209
|
+
else if (ch === "}" && --depth === 0) {
|
|
210
|
+
try {
|
|
211
|
+
return JSON.parse(s.slice(start, i + 1));
|
|
212
|
+
} catch {
|
|
213
|
+
return null; // malformed JSON — treat as prose
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return null; // unbalanced (e.g. stream cut mid-block) — auto-continue finishes it
|
|
218
|
+
}
|
|
219
|
+
|
|
196
220
|
/**
|
|
197
221
|
* Run one agent turn (which may span several tool steps).
|
|
198
222
|
*
|