@freesyntax/notch-cli 0.5.16 → 0.5.17
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/index.js +83 -85
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2450,16 +2450,6 @@ async function updateIndex() {
|
|
|
2450
2450
|
}
|
|
2451
2451
|
|
|
2452
2452
|
// src/agent/loop.ts
|
|
2453
|
-
var MAX_RETRIES = 3;
|
|
2454
|
-
var RETRY_DELAYS = [1e3, 3e3, 8e3];
|
|
2455
|
-
function isRetryableError(err) {
|
|
2456
|
-
if (!(err instanceof Error)) return false;
|
|
2457
|
-
const msg = err.message.toLowerCase();
|
|
2458
|
-
return msg.includes("502") || msg.includes("503") || msg.includes("429") || msg.includes("rate limit") || msg.includes("timeout") || msg.includes("econnreset") || msg.includes("econnrefused") || msg.includes("fetch failed") || msg.includes("network") || msg.includes("aborted");
|
|
2459
|
-
}
|
|
2460
|
-
async function sleep(ms) {
|
|
2461
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2462
|
-
}
|
|
2463
2453
|
function getErrorSignature(toolName, result) {
|
|
2464
2454
|
return {
|
|
2465
2455
|
toolName,
|
|
@@ -2500,81 +2490,44 @@ async function runAgentLoop(messages, config) {
|
|
|
2500
2490
|
const toolCalls = [];
|
|
2501
2491
|
const toolResults = [];
|
|
2502
2492
|
let streamUsage = null;
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
maxSteps: 1
|
|
2493
|
+
const result = streamText({
|
|
2494
|
+
model: config.model,
|
|
2495
|
+
system: config.systemPrompt,
|
|
2496
|
+
messages: history,
|
|
2497
|
+
tools,
|
|
2498
|
+
maxSteps: 1
|
|
2499
|
+
});
|
|
2500
|
+
for await (const event of result.fullStream) {
|
|
2501
|
+
if (event.type === "text-delta") {
|
|
2502
|
+
fullText += event.textDelta;
|
|
2503
|
+
config.onTextChunk?.(event.textDelta);
|
|
2504
|
+
} else if (event.type === "tool-call") {
|
|
2505
|
+
toolCalls.push({
|
|
2506
|
+
toolCallId: event.toolCallId,
|
|
2507
|
+
toolName: event.toolName,
|
|
2508
|
+
args: event.args
|
|
2520
2509
|
});
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
args: event.args
|
|
2530
|
-
});
|
|
2531
|
-
config.onToolCall?.(event.toolName, event.args);
|
|
2532
|
-
}
|
|
2533
|
-
const evt = event;
|
|
2534
|
-
if (evt.type === "tool-result") {
|
|
2535
|
-
const res = evt.result;
|
|
2536
|
-
toolResults.push({
|
|
2537
|
-
toolCallId: evt.toolCallId,
|
|
2538
|
-
result: evt.result
|
|
2539
|
-
});
|
|
2540
|
-
config.onToolResult?.(
|
|
2541
|
-
toolCalls.find((tc) => tc.toolCallId === evt.toolCallId)?.toolName ?? "unknown",
|
|
2542
|
-
res?.content ?? String(evt.result),
|
|
2543
|
-
res?.isError ?? false
|
|
2544
|
-
);
|
|
2545
|
-
}
|
|
2546
|
-
}
|
|
2547
|
-
try {
|
|
2548
|
-
const u = await result.usage;
|
|
2549
|
-
if (u) streamUsage = u;
|
|
2550
|
-
} catch {
|
|
2551
|
-
}
|
|
2552
|
-
lastError = null;
|
|
2553
|
-
break;
|
|
2554
|
-
} catch (err) {
|
|
2555
|
-
lastError = err;
|
|
2556
|
-
if (attempt < MAX_RETRIES && isRetryableError(err)) {
|
|
2557
|
-
continue;
|
|
2558
|
-
}
|
|
2559
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2560
|
-
history.push({
|
|
2561
|
-
role: "assistant",
|
|
2562
|
-
content: `[Error: ${errMsg}. The model endpoint may be unavailable. Try again or switch models with /model.]`
|
|
2510
|
+
config.onToolCall?.(event.toolName, event.args);
|
|
2511
|
+
}
|
|
2512
|
+
const evt = event;
|
|
2513
|
+
if (evt.type === "tool-result") {
|
|
2514
|
+
const res = evt.result;
|
|
2515
|
+
toolResults.push({
|
|
2516
|
+
toolCallId: evt.toolCallId,
|
|
2517
|
+
result: evt.result
|
|
2563
2518
|
});
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
compressed: wasCompressed,
|
|
2570
|
-
usage: {
|
|
2571
|
-
promptTokens: totalPromptTokens,
|
|
2572
|
-
completionTokens: totalCompletionTokens,
|
|
2573
|
-
totalTokens: totalPromptTokens + totalCompletionTokens
|
|
2574
|
-
}
|
|
2575
|
-
};
|
|
2519
|
+
config.onToolResult?.(
|
|
2520
|
+
toolCalls.find((tc) => tc.toolCallId === evt.toolCallId)?.toolName ?? "unknown",
|
|
2521
|
+
res?.content ?? String(evt.result),
|
|
2522
|
+
res?.isError ?? false
|
|
2523
|
+
);
|
|
2576
2524
|
}
|
|
2577
2525
|
}
|
|
2526
|
+
try {
|
|
2527
|
+
const u = await result.usage;
|
|
2528
|
+
if (u) streamUsage = u;
|
|
2529
|
+
} catch {
|
|
2530
|
+
}
|
|
2578
2531
|
if (streamUsage) {
|
|
2579
2532
|
totalPromptTokens += streamUsage.promptTokens ?? 0;
|
|
2580
2533
|
totalCompletionTokens += streamUsage.completionTokens ?? 0;
|
|
@@ -2881,12 +2834,12 @@ async function withRetry(fn, options = {}) {
|
|
|
2881
2834
|
delay += Math.random() * delay * 0.5;
|
|
2882
2835
|
}
|
|
2883
2836
|
options.onRetry?.(attempt, err, delay);
|
|
2884
|
-
await
|
|
2837
|
+
await sleep(delay);
|
|
2885
2838
|
}
|
|
2886
2839
|
}
|
|
2887
2840
|
throw lastError;
|
|
2888
2841
|
}
|
|
2889
|
-
function
|
|
2842
|
+
function sleep(ms) {
|
|
2890
2843
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2891
2844
|
}
|
|
2892
2845
|
|
|
@@ -3340,16 +3293,45 @@ async function buildRepoMap(root) {
|
|
|
3340
3293
|
"**/.git/**",
|
|
3341
3294
|
"**/dist/**",
|
|
3342
3295
|
"**/build/**",
|
|
3296
|
+
"**/out/**",
|
|
3297
|
+
"**/.next/**",
|
|
3298
|
+
"**/.nuxt/**",
|
|
3299
|
+
"**/.output/**",
|
|
3343
3300
|
"**/__pycache__/**",
|
|
3344
3301
|
"**/target/**",
|
|
3302
|
+
"**/.venv/**",
|
|
3303
|
+
"**/venv/**",
|
|
3345
3304
|
"**/*.test.*",
|
|
3346
3305
|
"**/*.spec.*",
|
|
3347
|
-
"**/*.d.ts"
|
|
3306
|
+
"**/*.d.ts",
|
|
3307
|
+
"**/*.config.*",
|
|
3308
|
+
// vite.config, tailwind.config, etc.
|
|
3309
|
+
"**/*.setup.*",
|
|
3310
|
+
// vitest.setup, jest.setup
|
|
3311
|
+
"**/postcss.config.*",
|
|
3312
|
+
"**/tsconfig.*",
|
|
3313
|
+
"**/.eslintrc.*",
|
|
3314
|
+
"**/.prettierrc.*",
|
|
3315
|
+
"**/env.d.ts",
|
|
3316
|
+
"**/vite-env.d.ts",
|
|
3317
|
+
"**/global.d.ts",
|
|
3318
|
+
"**/globals.d.ts",
|
|
3319
|
+
"**/next-env.d.ts",
|
|
3320
|
+
"**/migrations/**",
|
|
3321
|
+
"**/generated/**",
|
|
3322
|
+
"**/*.min.*",
|
|
3323
|
+
"**/vendor/**",
|
|
3324
|
+
"**/public/**",
|
|
3325
|
+
"**/coverage/**",
|
|
3326
|
+
"**/.cache/**",
|
|
3327
|
+
"**/lock.*",
|
|
3328
|
+
"**/*-lock.*"
|
|
3348
3329
|
],
|
|
3349
3330
|
nodir: true
|
|
3350
3331
|
});
|
|
3351
3332
|
const entries = [];
|
|
3352
|
-
|
|
3333
|
+
files.sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b));
|
|
3334
|
+
for (const file of files.slice(0, 300)) {
|
|
3353
3335
|
const fullPath = path15.resolve(root, file);
|
|
3354
3336
|
try {
|
|
3355
3337
|
const content = await fs12.readFile(fullPath, "utf-8");
|
|
@@ -7698,6 +7680,19 @@ Analyze the above input.`;
|
|
|
7698
7680
|
}
|
|
7699
7681
|
messages.push({ role: "user", content: finalPrompt });
|
|
7700
7682
|
const spinner = ora4("Thinking...").start();
|
|
7683
|
+
const spinnerStart = Date.now();
|
|
7684
|
+
const spinnerTimer = setInterval(() => {
|
|
7685
|
+
if (!spinner.isSpinning) {
|
|
7686
|
+
clearInterval(spinnerTimer);
|
|
7687
|
+
return;
|
|
7688
|
+
}
|
|
7689
|
+
const elapsed = Math.floor((Date.now() - spinnerStart) / 1e3);
|
|
7690
|
+
if (elapsed >= 30) {
|
|
7691
|
+
spinner.text = `Waiting for model... (${elapsed}s \u2014 endpoint may be cold-starting)`;
|
|
7692
|
+
} else if (elapsed >= 10) {
|
|
7693
|
+
spinner.text = `Thinking... (${elapsed}s)`;
|
|
7694
|
+
}
|
|
7695
|
+
}, 2e3);
|
|
7701
7696
|
try {
|
|
7702
7697
|
const response = await withRetry(
|
|
7703
7698
|
() => runAgentLoop(messages, {
|
|
@@ -7707,10 +7702,12 @@ Analyze the above input.`;
|
|
|
7707
7702
|
maxIterations: config.maxIterations,
|
|
7708
7703
|
contextWindow: MODEL_CATALOG[activeModelId].contextWindow,
|
|
7709
7704
|
onTextChunk: (chunk) => {
|
|
7705
|
+
clearInterval(spinnerTimer);
|
|
7710
7706
|
if (spinner.isSpinning) spinner.stop();
|
|
7711
7707
|
process.stdout.write(chunk);
|
|
7712
7708
|
},
|
|
7713
7709
|
onToolCall: (name, args) => {
|
|
7710
|
+
clearInterval(spinnerTimer);
|
|
7714
7711
|
if (spinner.isSpinning) spinner.stop();
|
|
7715
7712
|
if ((name === "write" || name === "edit") && typeof args.path === "string") {
|
|
7716
7713
|
const filePath = nodePath.isAbsolute(args.path) ? args.path : nodePath.resolve(toolCtx.cwd, args.path);
|
|
@@ -7772,6 +7769,7 @@ Analyze the above input.`;
|
|
|
7772
7769
|
}
|
|
7773
7770
|
}
|
|
7774
7771
|
} catch (err) {
|
|
7772
|
+
clearInterval(spinnerTimer);
|
|
7775
7773
|
spinner.fail(`Error: ${err.message}`);
|
|
7776
7774
|
checkpoints.discard();
|
|
7777
7775
|
const msg = err.message?.toLowerCase() ?? "";
|