@rama_nigg/open-cursor 2.3.18 → 2.3.19
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/cli/mcptool.js +5586 -130
- package/dist/index.js +5662 -134
- package/dist/plugin-entry.js +5662 -134
- package/package.json +1 -1
- package/src/provider/runtime-interception.ts +89 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rama_nigg/open-cursor",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.19",
|
|
4
4
|
"description": "No prompt limits. No broken streams. Full thinking + tool support. Your Cursor subscription, properly integrated.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin-entry.js",
|
|
@@ -59,6 +59,7 @@ export interface ToolLoopGuardTermination {
|
|
|
59
59
|
maxRepeat: number;
|
|
60
60
|
errorClass: string;
|
|
61
61
|
silent?: boolean;
|
|
62
|
+
soft?: boolean;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
export interface ToolSchemaValidationTermination {
|
|
@@ -177,6 +178,15 @@ export async function handleToolLoopEventLegacy(
|
|
|
177
178
|
compat.validation,
|
|
178
179
|
);
|
|
179
180
|
if (validationTermination) {
|
|
181
|
+
if (validationTermination.soft) {
|
|
182
|
+
const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, validationTermination);
|
|
183
|
+
log.debug("Soft-blocking schema validation loop guard in legacy (emitting hint)", {
|
|
184
|
+
tool: normalizedToolCall.function.name,
|
|
185
|
+
fingerprint: validationTermination.fingerprint,
|
|
186
|
+
});
|
|
187
|
+
await onToolResult(hintChunk);
|
|
188
|
+
return { intercepted: false, skipConverter: true };
|
|
189
|
+
}
|
|
180
190
|
return { intercepted: false, skipConverter: true, terminate: validationTermination };
|
|
181
191
|
}
|
|
182
192
|
|
|
@@ -211,6 +221,15 @@ export async function handleToolLoopEventLegacy(
|
|
|
211
221
|
|
|
212
222
|
const termination = evaluateToolLoopGuard(toolLoopGuard, normalizedToolCall);
|
|
213
223
|
if (termination) {
|
|
224
|
+
if (termination.soft) {
|
|
225
|
+
const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination);
|
|
226
|
+
log.debug("Soft-blocking tool loop guard in legacy (emitting hint)", {
|
|
227
|
+
tool: normalizedToolCall.function.name,
|
|
228
|
+
fingerprint: termination.fingerprint,
|
|
229
|
+
});
|
|
230
|
+
await onToolResult(hintChunk);
|
|
231
|
+
return { intercepted: false, skipConverter: true };
|
|
232
|
+
}
|
|
214
233
|
return { intercepted: false, skipConverter: true, terminate: termination };
|
|
215
234
|
}
|
|
216
235
|
await onInterceptedToolCall(normalizedToolCall);
|
|
@@ -341,10 +360,30 @@ export async function handleToolLoopEventV1(
|
|
|
341
360
|
compat.validation,
|
|
342
361
|
);
|
|
343
362
|
if (validationTermination) {
|
|
363
|
+
if (validationTermination.soft) {
|
|
364
|
+
const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, validationTermination);
|
|
365
|
+
log.debug("Soft-blocking schema validation loop guard (emitting hint)", {
|
|
366
|
+
tool: normalizedToolCall.function.name,
|
|
367
|
+
fingerprint: validationTermination.fingerprint,
|
|
368
|
+
repeatCount: validationTermination.repeatCount,
|
|
369
|
+
});
|
|
370
|
+
await onToolResult(hintChunk);
|
|
371
|
+
return { intercepted: false, skipConverter: true };
|
|
372
|
+
}
|
|
344
373
|
return { intercepted: false, skipConverter: true, terminate: validationTermination };
|
|
345
374
|
}
|
|
346
375
|
const termination = evaluateToolLoopGuard(toolLoopGuard, normalizedToolCall);
|
|
347
376
|
if (termination) {
|
|
377
|
+
if (termination.soft) {
|
|
378
|
+
const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination);
|
|
379
|
+
log.debug("Soft-blocking tool loop guard in validation path (emitting hint)", {
|
|
380
|
+
tool: normalizedToolCall.function.name,
|
|
381
|
+
fingerprint: termination.fingerprint,
|
|
382
|
+
repeatCount: termination.repeatCount,
|
|
383
|
+
});
|
|
384
|
+
await onToolResult(hintChunk);
|
|
385
|
+
return { intercepted: false, skipConverter: true };
|
|
386
|
+
}
|
|
348
387
|
return { intercepted: false, skipConverter: true, terminate: termination };
|
|
349
388
|
}
|
|
350
389
|
const reroutedWrite = tryRerouteEditToWrite(
|
|
@@ -415,6 +454,16 @@ export async function handleToolLoopEventV1(
|
|
|
415
454
|
|
|
416
455
|
const termination = evaluateToolLoopGuard(toolLoopGuard, normalizedToolCall);
|
|
417
456
|
if (termination) {
|
|
457
|
+
if (termination.soft) {
|
|
458
|
+
const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination);
|
|
459
|
+
log.debug("Soft-blocking tool loop guard (emitting hint)", {
|
|
460
|
+
tool: normalizedToolCall.function.name,
|
|
461
|
+
fingerprint: termination.fingerprint,
|
|
462
|
+
repeatCount: termination.repeatCount,
|
|
463
|
+
});
|
|
464
|
+
await onToolResult(hintChunk);
|
|
465
|
+
return { intercepted: false, skipConverter: true };
|
|
466
|
+
}
|
|
418
467
|
return { intercepted: false, skipConverter: true, terminate: termination };
|
|
419
468
|
}
|
|
420
469
|
await onInterceptedToolCall(normalizedToolCall);
|
|
@@ -515,6 +564,11 @@ function evaluateToolLoopGuard(
|
|
|
515
564
|
};
|
|
516
565
|
}
|
|
517
566
|
|
|
567
|
+
// First trigger (repeatCount exactly one over threshold): soft block.
|
|
568
|
+
// Emit a hint to the model instead of killing the stream.
|
|
569
|
+
// If the model ignores the hint and retries, subsequent triggers are hard kills.
|
|
570
|
+
const isFirstTrigger = decision.repeatCount === decision.maxRepeat + 1;
|
|
571
|
+
|
|
518
572
|
return {
|
|
519
573
|
reason: "loop_guard",
|
|
520
574
|
message: `Tool loop guard stopped repeated failing calls to "${toolCall.function.name}" `
|
|
@@ -525,6 +579,7 @@ function evaluateToolLoopGuard(
|
|
|
525
579
|
repeatCount: decision.repeatCount,
|
|
526
580
|
maxRepeat: decision.maxRepeat,
|
|
527
581
|
errorClass: decision.errorClass,
|
|
582
|
+
soft: isFirstTrigger,
|
|
528
583
|
};
|
|
529
584
|
}
|
|
530
585
|
|
|
@@ -570,12 +625,15 @@ function evaluateSchemaValidationLoopGuard(
|
|
|
570
625
|
return null;
|
|
571
626
|
}
|
|
572
627
|
|
|
573
|
-
|
|
628
|
+
const isFirstTrigger = decision.repeatCount === decision.maxRepeat + 1;
|
|
629
|
+
|
|
630
|
+
log.debug("Tool loop guard triggered on schema validation", {
|
|
574
631
|
tool: toolCall.function.name,
|
|
575
632
|
fingerprint: decision.fingerprint,
|
|
576
633
|
repeatCount: decision.repeatCount,
|
|
577
634
|
maxRepeat: decision.maxRepeat,
|
|
578
635
|
validationSignature,
|
|
636
|
+
soft: isFirstTrigger,
|
|
579
637
|
});
|
|
580
638
|
return {
|
|
581
639
|
reason: "loop_guard",
|
|
@@ -588,6 +646,7 @@ function evaluateSchemaValidationLoopGuard(
|
|
|
588
646
|
repeatCount: decision.repeatCount,
|
|
589
647
|
maxRepeat: decision.maxRepeat,
|
|
590
648
|
errorClass: decision.errorClass,
|
|
649
|
+
soft: isFirstTrigger,
|
|
591
650
|
};
|
|
592
651
|
}
|
|
593
652
|
|
|
@@ -663,6 +722,35 @@ function createNonFatalSchemaValidationHintChunk(
|
|
|
663
722
|
};
|
|
664
723
|
}
|
|
665
724
|
|
|
725
|
+
type LoopGuardHintChunk = NonFatalSchemaValidationResultChunk;
|
|
726
|
+
|
|
727
|
+
function createLoopGuardHintChunk(
|
|
728
|
+
meta: { id: string; created: number; model: string },
|
|
729
|
+
toolCall: OpenAiToolCall,
|
|
730
|
+
termination: ToolLoopGuardTermination,
|
|
731
|
+
): LoopGuardHintChunk {
|
|
732
|
+
const content =
|
|
733
|
+
`Tool "${toolCall.function.name}" has been temporarily blocked after `
|
|
734
|
+
+ `${termination.repeatCount} repeated ${termination.errorClass} failures. `
|
|
735
|
+
+ "Do not retry this tool. Use a different approach to complete the task.";
|
|
736
|
+
return {
|
|
737
|
+
id: meta.id,
|
|
738
|
+
object: "chat.completion.chunk",
|
|
739
|
+
created: meta.created,
|
|
740
|
+
model: meta.model,
|
|
741
|
+
choices: [
|
|
742
|
+
{
|
|
743
|
+
index: 0,
|
|
744
|
+
delta: {
|
|
745
|
+
role: "assistant",
|
|
746
|
+
content,
|
|
747
|
+
},
|
|
748
|
+
finish_reason: null,
|
|
749
|
+
},
|
|
750
|
+
],
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
|
|
666
754
|
function safeArgTypeSummary(event: StreamJsonToolCallEvent): Record<string, string> {
|
|
667
755
|
try {
|
|
668
756
|
let raw: unknown;
|