@probelabs/probe 0.6.0-rc159 → 0.6.0-rc162
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/README.md +169 -1
- package/build/agent/FallbackManager.d.ts +176 -0
- package/build/agent/FallbackManager.js +545 -0
- package/build/agent/ProbeAgent.d.ts +7 -1
- package/build/agent/ProbeAgent.js +545 -89
- package/build/agent/RetryManager.d.ts +157 -0
- package/build/agent/RetryManager.js +334 -0
- package/build/agent/acp/tools.js +6 -2
- package/build/agent/contextCompactor.js +271 -0
- package/build/agent/index.js +2165 -250
- package/build/agent/probeTool.js +20 -2
- package/build/agent/schemaUtils.js +7 -0
- package/build/agent/tools.js +16 -0
- package/build/agent/xmlParsingUtils.js +24 -4
- package/build/index.js +13 -0
- package/build/tools/common.js +21 -4
- package/build/tools/edit.js +409 -0
- package/build/tools/index.js +11 -0
- package/cjs/agent/ProbeAgent.cjs +2620 -606
- package/cjs/index.cjs +2582 -563
- package/package.json +2 -2
- package/src/agent/FallbackManager.d.ts +176 -0
- package/src/agent/FallbackManager.js +545 -0
- package/src/agent/ProbeAgent.d.ts +7 -1
- package/src/agent/ProbeAgent.js +545 -89
- package/src/agent/RetryManager.d.ts +157 -0
- package/src/agent/RetryManager.js +334 -0
- package/src/agent/acp/tools.js +6 -2
- package/src/agent/contextCompactor.js +271 -0
- package/src/agent/index.js +30 -1
- package/src/agent/probeTool.js +20 -2
- package/src/agent/schemaUtils.js +7 -0
- package/src/agent/tools.js +16 -0
- package/src/agent/xmlParsingUtils.js +24 -4
- package/src/index.js +13 -0
- package/src/tools/common.js +21 -4
- package/src/tools/edit.js +409 -0
- package/src/tools/index.js +11 -0
- package/bin/binaries/probe-v0.6.0-rc159-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc159-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc159-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc159-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc159-x86_64-unknown-linux-musl.tar.gz +0 -0
package/build/agent/index.js
CHANGED
|
@@ -552,6 +552,162 @@ var init_BytePairEncodingCore = __esm({
|
|
|
552
552
|
}
|
|
553
553
|
});
|
|
554
554
|
|
|
555
|
+
// node_modules/gpt-tokenizer/esm/functionCalling.js
|
|
556
|
+
function countMessageTokens(message, countStringTokens) {
|
|
557
|
+
let tokens = 0;
|
|
558
|
+
if (message.role) {
|
|
559
|
+
tokens += countStringTokens(message.role);
|
|
560
|
+
}
|
|
561
|
+
if (message.content) {
|
|
562
|
+
tokens += countStringTokens(message.content);
|
|
563
|
+
}
|
|
564
|
+
if (message.name) {
|
|
565
|
+
tokens += countStringTokens(message.name) + MESSAGE_NAME_TOKEN_OVERHEAD;
|
|
566
|
+
}
|
|
567
|
+
if (message.function_call) {
|
|
568
|
+
const { name, arguments: args } = message.function_call;
|
|
569
|
+
if (name) {
|
|
570
|
+
tokens += countStringTokens(name);
|
|
571
|
+
}
|
|
572
|
+
if (args) {
|
|
573
|
+
tokens += countStringTokens(args);
|
|
574
|
+
}
|
|
575
|
+
tokens += FUNCTION_CALL_METADATA_TOKEN_OVERHEAD;
|
|
576
|
+
}
|
|
577
|
+
tokens += MESSAGE_TOKEN_OVERHEAD;
|
|
578
|
+
if (message.role === "function") {
|
|
579
|
+
tokens -= FUNCTION_ROLE_TOKEN_DISCOUNT;
|
|
580
|
+
}
|
|
581
|
+
return tokens;
|
|
582
|
+
}
|
|
583
|
+
function formatObjectProperties(obj, indent, formatType) {
|
|
584
|
+
if (!obj.properties) {
|
|
585
|
+
return "";
|
|
586
|
+
}
|
|
587
|
+
const lines = [];
|
|
588
|
+
const requiredParams = new Set(obj.required ?? []);
|
|
589
|
+
const indentString = " ".repeat(indent);
|
|
590
|
+
for (const [name, param] of Object.entries(obj.properties)) {
|
|
591
|
+
if (param.description && indent < 2) {
|
|
592
|
+
lines.push(`${indentString}// ${param.description}`);
|
|
593
|
+
}
|
|
594
|
+
const isRequired = requiredParams.has(name);
|
|
595
|
+
const formattedType = formatType(param, indent);
|
|
596
|
+
lines.push(`${indentString}${name}${isRequired ? "" : "?"}: ${formattedType},`);
|
|
597
|
+
}
|
|
598
|
+
return lines.join("\n");
|
|
599
|
+
}
|
|
600
|
+
function formatFunctionType(param, indent) {
|
|
601
|
+
switch (param.type) {
|
|
602
|
+
case "string":
|
|
603
|
+
return param.enum?.map((value) => JSON.stringify(value)).join(" | ") ?? "string";
|
|
604
|
+
case "integer":
|
|
605
|
+
case "number":
|
|
606
|
+
return param.enum?.map((value) => `${value}`).join(" | ") ?? "number";
|
|
607
|
+
case "boolean":
|
|
608
|
+
return "boolean";
|
|
609
|
+
case "null":
|
|
610
|
+
return "null";
|
|
611
|
+
case "array":
|
|
612
|
+
return param.items ? `${formatFunctionType(param.items, indent)}[]` : "any[]";
|
|
613
|
+
case "object": {
|
|
614
|
+
const inner = formatObjectProperties(param, indent + 2, formatFunctionType);
|
|
615
|
+
const closingIndent = " ".repeat(indent);
|
|
616
|
+
return `{
|
|
617
|
+
${inner}
|
|
618
|
+
${closingIndent}}`;
|
|
619
|
+
}
|
|
620
|
+
default:
|
|
621
|
+
return "any";
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function formatFunctionDefinitions(functions) {
|
|
625
|
+
const lines = ["namespace functions {", ""];
|
|
626
|
+
for (const fn of functions) {
|
|
627
|
+
if (fn.description) {
|
|
628
|
+
lines.push(`// ${fn.description}`);
|
|
629
|
+
}
|
|
630
|
+
const { parameters } = fn;
|
|
631
|
+
const properties = parameters?.properties;
|
|
632
|
+
if (!parameters || !properties || Object.keys(properties).length === 0) {
|
|
633
|
+
lines.push(`type ${fn.name} = () => any;`);
|
|
634
|
+
} else {
|
|
635
|
+
lines.push(`type ${fn.name} = (_: {`);
|
|
636
|
+
const formattedProperties = formatObjectProperties(parameters, 0, formatFunctionType);
|
|
637
|
+
if (formattedProperties.length > 0) {
|
|
638
|
+
lines.push(formattedProperties);
|
|
639
|
+
}
|
|
640
|
+
lines.push("}) => any;");
|
|
641
|
+
}
|
|
642
|
+
lines.push("");
|
|
643
|
+
}
|
|
644
|
+
lines.push("} // namespace functions");
|
|
645
|
+
return lines.join("\n");
|
|
646
|
+
}
|
|
647
|
+
function estimateTokensInFunctions(functions, countStringTokens) {
|
|
648
|
+
const formatted = formatFunctionDefinitions(functions);
|
|
649
|
+
let tokens = countStringTokens(formatted);
|
|
650
|
+
tokens += FUNCTION_DEFINITION_TOKEN_OVERHEAD;
|
|
651
|
+
return tokens;
|
|
652
|
+
}
|
|
653
|
+
function padSystemMessage(message, hasFunctions, isSystemPadded) {
|
|
654
|
+
if (!hasFunctions || isSystemPadded || message.role !== "system") {
|
|
655
|
+
return message;
|
|
656
|
+
}
|
|
657
|
+
if (!message.content || message.content.endsWith(NEWLINE)) {
|
|
658
|
+
return message;
|
|
659
|
+
}
|
|
660
|
+
return {
|
|
661
|
+
...message,
|
|
662
|
+
content: `${message.content}${NEWLINE}`
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
function computeChatCompletionTokenCount(request, countStringTokens) {
|
|
666
|
+
const { messages, functions, function_call: functionCall } = request;
|
|
667
|
+
const hasFunctions = Boolean(functions && functions.length > 0);
|
|
668
|
+
let paddedSystem = false;
|
|
669
|
+
let total = 0;
|
|
670
|
+
for (const message of messages) {
|
|
671
|
+
const messageToCount = padSystemMessage(message, hasFunctions, paddedSystem);
|
|
672
|
+
if (messageToCount !== message && message.role === "system") {
|
|
673
|
+
paddedSystem = true;
|
|
674
|
+
} else if (message.role === "system" && hasFunctions && !paddedSystem) {
|
|
675
|
+
paddedSystem = true;
|
|
676
|
+
}
|
|
677
|
+
total += countMessageTokens(messageToCount, countStringTokens);
|
|
678
|
+
}
|
|
679
|
+
total += COMPLETION_REQUEST_TOKEN_OVERHEAD;
|
|
680
|
+
if (hasFunctions && functions) {
|
|
681
|
+
total += estimateTokensInFunctions(functions, countStringTokens);
|
|
682
|
+
if (messages.some((message) => message.role === "system")) {
|
|
683
|
+
total -= SYSTEM_FUNCTION_TOKEN_DEDUCTION;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (functionCall && functionCall !== "auto") {
|
|
687
|
+
if (functionCall === "none") {
|
|
688
|
+
total += FUNCTION_CALL_NONE_TOKEN_OVERHEAD;
|
|
689
|
+
} else if (typeof functionCall === "object" && functionCall.name) {
|
|
690
|
+
total += countStringTokens(functionCall.name) + FUNCTION_CALL_NAME_TOKEN_OVERHEAD;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return total;
|
|
694
|
+
}
|
|
695
|
+
var MESSAGE_TOKEN_OVERHEAD, MESSAGE_NAME_TOKEN_OVERHEAD, FUNCTION_ROLE_TOKEN_DISCOUNT, FUNCTION_CALL_METADATA_TOKEN_OVERHEAD, FUNCTION_DEFINITION_TOKEN_OVERHEAD, COMPLETION_REQUEST_TOKEN_OVERHEAD, FUNCTION_CALL_NAME_TOKEN_OVERHEAD, FUNCTION_CALL_NONE_TOKEN_OVERHEAD, SYSTEM_FUNCTION_TOKEN_DEDUCTION, NEWLINE;
|
|
696
|
+
var init_functionCalling = __esm({
|
|
697
|
+
"node_modules/gpt-tokenizer/esm/functionCalling.js"() {
|
|
698
|
+
MESSAGE_TOKEN_OVERHEAD = 3;
|
|
699
|
+
MESSAGE_NAME_TOKEN_OVERHEAD = 1;
|
|
700
|
+
FUNCTION_ROLE_TOKEN_DISCOUNT = 2;
|
|
701
|
+
FUNCTION_CALL_METADATA_TOKEN_OVERHEAD = 3;
|
|
702
|
+
FUNCTION_DEFINITION_TOKEN_OVERHEAD = 9;
|
|
703
|
+
COMPLETION_REQUEST_TOKEN_OVERHEAD = 3;
|
|
704
|
+
FUNCTION_CALL_NAME_TOKEN_OVERHEAD = 4;
|
|
705
|
+
FUNCTION_CALL_NONE_TOKEN_OVERHEAD = 1;
|
|
706
|
+
SYSTEM_FUNCTION_TOKEN_DEDUCTION = 4;
|
|
707
|
+
NEWLINE = "\n";
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
|
|
555
711
|
// node_modules/gpt-tokenizer/esm/modelsChatEnabled.gen.js
|
|
556
712
|
var chatEnabledModels;
|
|
557
713
|
var init_modelsChatEnabled_gen = __esm({
|
|
@@ -565,11 +721,12 @@ var modelsMap_exports = {};
|
|
|
565
721
|
__export(modelsMap_exports, {
|
|
566
722
|
cl100k_base: () => cl100k_base,
|
|
567
723
|
o200k_base: () => o200k_base,
|
|
724
|
+
o200k_harmony: () => o200k_harmony,
|
|
568
725
|
p50k_base: () => p50k_base,
|
|
569
726
|
p50k_edit: () => p50k_edit,
|
|
570
727
|
r50k_base: () => r50k_base
|
|
571
728
|
});
|
|
572
|
-
var p50k_base, r50k_base, p50k_edit, cl100k_base, o200k_base;
|
|
729
|
+
var p50k_base, r50k_base, p50k_edit, cl100k_base, o200k_base, o200k_harmony;
|
|
573
730
|
var init_modelsMap = __esm({
|
|
574
731
|
"node_modules/gpt-tokenizer/esm/modelsMap.js"() {
|
|
575
732
|
p50k_base = [
|
|
@@ -644,11 +801,15 @@ var init_modelsMap = __esm({
|
|
|
644
801
|
"davinci-002"
|
|
645
802
|
];
|
|
646
803
|
o200k_base = [];
|
|
804
|
+
o200k_harmony = [
|
|
805
|
+
"gpt-oss-20b",
|
|
806
|
+
"gpt-oss-120b"
|
|
807
|
+
];
|
|
647
808
|
}
|
|
648
809
|
});
|
|
649
810
|
|
|
650
811
|
// node_modules/gpt-tokenizer/esm/specialTokens.js
|
|
651
|
-
var EndOfText, FimPrefix, FimMiddle, FimSuffix, ImStart, ImEnd, ImSep, EndOfPrompt;
|
|
812
|
+
var EndOfText, FimPrefix, FimMiddle, FimSuffix, ImStart, ImEnd, ImSep, EndOfPrompt, HarmonyStartOfText, HarmonyStart, HarmonyEnd, HarmonyMessage, HarmonyChannel, HarmonyReturn, HarmonyConstrain, HarmonyCall;
|
|
652
813
|
var init_specialTokens = __esm({
|
|
653
814
|
"node_modules/gpt-tokenizer/esm/specialTokens.js"() {
|
|
654
815
|
EndOfText = "<|endoftext|>";
|
|
@@ -659,6 +820,14 @@ var init_specialTokens = __esm({
|
|
|
659
820
|
ImEnd = "<|im_end|>";
|
|
660
821
|
ImSep = "<|im_sep|>";
|
|
661
822
|
EndOfPrompt = "<|endofprompt|>";
|
|
823
|
+
HarmonyStartOfText = "<|startoftext|>";
|
|
824
|
+
HarmonyStart = "<|start|>";
|
|
825
|
+
HarmonyEnd = "<|end|>";
|
|
826
|
+
HarmonyMessage = "<|message|>";
|
|
827
|
+
HarmonyChannel = "<|channel|>";
|
|
828
|
+
HarmonyReturn = "<|return|>";
|
|
829
|
+
HarmonyConstrain = "<|constrain|>";
|
|
830
|
+
HarmonyCall = "<|call|>";
|
|
662
831
|
}
|
|
663
832
|
});
|
|
664
833
|
|
|
@@ -685,11 +854,16 @@ var init_mapping = __esm({
|
|
|
685
854
|
});
|
|
686
855
|
|
|
687
856
|
// node_modules/gpt-tokenizer/esm/encodingParams/constants.js
|
|
688
|
-
var R50K_TOKEN_SPLIT_REGEX,
|
|
857
|
+
var R50K_TOKEN_SPLIT_REGEX, CONTRACTION_SUFFIX_PATTERN, OPTIONAL_CONTRACTION_SUFFIX, CL100K_TOKEN_SPLIT_PATTERN, CL100K_TOKEN_SPLIT_REGEX, O200K_TOKEN_SPLIT_PATTERN, O200K_TOKEN_SPLIT_REGEX;
|
|
689
858
|
var init_constants2 = __esm({
|
|
690
859
|
"node_modules/gpt-tokenizer/esm/encodingParams/constants.js"() {
|
|
691
860
|
R50K_TOKEN_SPLIT_REGEX = new RegExp("'s|'t|'re|'ve|'m|'ll|'d| ?\\p{L}+| ?\\p{N}+| ?[^\\s\\p{L}\\p{N}]+|\\s+(?!\\S)|\\s+", "gu");
|
|
692
|
-
|
|
861
|
+
CONTRACTION_SUFFIX_PATTERN = String.raw`'(?:[sS]|[dD]|[mM]|[tT]|[lL][lL]|[vV][eE]|[rR][eE])`;
|
|
862
|
+
OPTIONAL_CONTRACTION_SUFFIX = String.raw`(?:${CONTRACTION_SUFFIX_PATTERN})?`;
|
|
863
|
+
CL100K_TOKEN_SPLIT_PATTERN = String.raw`${CONTRACTION_SUFFIX_PATTERN}|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s+$|\s*[\r\n]|\s+(?!\S)|\s`;
|
|
864
|
+
CL100K_TOKEN_SPLIT_REGEX = new RegExp(CL100K_TOKEN_SPLIT_PATTERN, "gu");
|
|
865
|
+
O200K_TOKEN_SPLIT_PATTERN = String.raw`[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]*[\p{Ll}\p{Lm}\p{Lo}\p{M}]+${OPTIONAL_CONTRACTION_SUFFIX}|[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]+[\p{Ll}\p{Lm}\p{Lo}\p{M}]*${OPTIONAL_CONTRACTION_SUFFIX}|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n/]*|\s*[\r\n]+|\s+(?!\S)|\s+`;
|
|
866
|
+
O200K_TOKEN_SPLIT_REGEX = new RegExp(O200K_TOKEN_SPLIT_PATTERN, "gu");
|
|
693
867
|
}
|
|
694
868
|
});
|
|
695
869
|
|
|
@@ -706,7 +880,7 @@ function Cl100KBase(bytePairRankDecoder) {
|
|
|
706
880
|
[EndOfPrompt, 100276]
|
|
707
881
|
]);
|
|
708
882
|
return {
|
|
709
|
-
tokenSplitRegex:
|
|
883
|
+
tokenSplitRegex: CL100K_TOKEN_SPLIT_REGEX,
|
|
710
884
|
bytePairRankDecoder,
|
|
711
885
|
specialTokensEncoder: specialTokenMapping
|
|
712
886
|
};
|
|
@@ -720,26 +894,69 @@ var init_cl100k_base = __esm({
|
|
|
720
894
|
|
|
721
895
|
// node_modules/gpt-tokenizer/esm/encodingParams/o200k_base.js
|
|
722
896
|
function O200KBase(bytePairRankDecoder) {
|
|
723
|
-
const specialTokenMapping = /* @__PURE__ */ new Map([
|
|
724
|
-
[EndOfText, 199999],
|
|
725
|
-
[FimPrefix, 2e5],
|
|
726
|
-
[FimMiddle, 200001],
|
|
727
|
-
[FimSuffix, 200002],
|
|
728
|
-
[ImStart, 200003],
|
|
729
|
-
[ImEnd, 200004],
|
|
730
|
-
[ImSep, 200005],
|
|
731
|
-
[EndOfPrompt, 200006]
|
|
732
|
-
]);
|
|
733
897
|
return {
|
|
734
|
-
tokenSplitRegex:
|
|
898
|
+
tokenSplitRegex: O200K_TOKEN_SPLIT_REGEX,
|
|
735
899
|
bytePairRankDecoder,
|
|
736
|
-
specialTokensEncoder:
|
|
900
|
+
specialTokensEncoder: createO200KSpecialTokenMap()
|
|
737
901
|
};
|
|
738
902
|
}
|
|
903
|
+
var O200K_BASE_SPECIAL_TOKEN_ENTRIES, createO200KSpecialTokenMap;
|
|
739
904
|
var init_o200k_base2 = __esm({
|
|
740
905
|
"node_modules/gpt-tokenizer/esm/encodingParams/o200k_base.js"() {
|
|
741
906
|
init_specialTokens();
|
|
742
907
|
init_constants2();
|
|
908
|
+
O200K_BASE_SPECIAL_TOKEN_ENTRIES = [
|
|
909
|
+
[EndOfText, 199999],
|
|
910
|
+
[FimPrefix, 2e5],
|
|
911
|
+
[FimMiddle, 200001],
|
|
912
|
+
[FimSuffix, 200002],
|
|
913
|
+
[ImStart, 200003],
|
|
914
|
+
[ImEnd, 200004],
|
|
915
|
+
[ImSep, 200005],
|
|
916
|
+
[EndOfPrompt, 200006]
|
|
917
|
+
];
|
|
918
|
+
createO200KSpecialTokenMap = () => new Map(O200K_BASE_SPECIAL_TOKEN_ENTRIES);
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
// node_modules/gpt-tokenizer/esm/encodingParams/o200k_harmony.js
|
|
923
|
+
function O200KHarmony(bytePairRankDecoder) {
|
|
924
|
+
const specialTokensEncoder = new Map(STATIC_SPECIAL_TOKEN_ENTRIES);
|
|
925
|
+
for (let tokenId = RESERVED_TOKEN_RANGE_START; tokenId < RESERVED_TOKEN_RANGE_END; tokenId += 1) {
|
|
926
|
+
specialTokensEncoder.set(`<|reserved_${tokenId}|>`, tokenId);
|
|
927
|
+
}
|
|
928
|
+
specialTokensEncoder.set(EndOfPrompt, 200018);
|
|
929
|
+
return {
|
|
930
|
+
tokenSplitRegex: O200K_TOKEN_SPLIT_REGEX,
|
|
931
|
+
bytePairRankDecoder,
|
|
932
|
+
specialTokensEncoder,
|
|
933
|
+
chatFormatter: "harmony"
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
var RESERVED_TOKEN_RANGE_START, RESERVED_TOKEN_RANGE_END, STATIC_SPECIAL_TOKEN_ENTRIES;
|
|
937
|
+
var init_o200k_harmony = __esm({
|
|
938
|
+
"node_modules/gpt-tokenizer/esm/encodingParams/o200k_harmony.js"() {
|
|
939
|
+
init_specialTokens();
|
|
940
|
+
init_constants2();
|
|
941
|
+
RESERVED_TOKEN_RANGE_START = 200013;
|
|
942
|
+
RESERVED_TOKEN_RANGE_END = 201088;
|
|
943
|
+
STATIC_SPECIAL_TOKEN_ENTRIES = [
|
|
944
|
+
[HarmonyStartOfText, 199998],
|
|
945
|
+
[EndOfText, 199999],
|
|
946
|
+
["<|reserved_200000|>", 2e5],
|
|
947
|
+
["<|reserved_200001|>", 200001],
|
|
948
|
+
[HarmonyReturn, 200002],
|
|
949
|
+
[HarmonyConstrain, 200003],
|
|
950
|
+
["<|reserved_200004|>", 200004],
|
|
951
|
+
[HarmonyChannel, 200005],
|
|
952
|
+
[HarmonyStart, 200006],
|
|
953
|
+
[HarmonyEnd, 200007],
|
|
954
|
+
[HarmonyMessage, 200008],
|
|
955
|
+
["<|reserved_200009|>", 200009],
|
|
956
|
+
["<|reserved_200010|>", 200010],
|
|
957
|
+
["<|reserved_200011|>", 200011],
|
|
958
|
+
[HarmonyCall, 200012]
|
|
959
|
+
];
|
|
743
960
|
}
|
|
744
961
|
});
|
|
745
962
|
|
|
@@ -813,6 +1030,8 @@ function getEncodingParams(encodingName, getMergeableRanks) {
|
|
|
813
1030
|
return Cl100KBase(mergeableBytePairRanks);
|
|
814
1031
|
case "o200k_base":
|
|
815
1032
|
return O200KBase(mergeableBytePairRanks);
|
|
1033
|
+
case "o200k_harmony":
|
|
1034
|
+
return O200KHarmony(mergeableBytePairRanks);
|
|
816
1035
|
default:
|
|
817
1036
|
throw new Error(`Unknown encoding name: ${encodingName}`);
|
|
818
1037
|
}
|
|
@@ -821,6 +1040,7 @@ var init_modelParams = __esm({
|
|
|
821
1040
|
"node_modules/gpt-tokenizer/esm/modelParams.js"() {
|
|
822
1041
|
init_cl100k_base();
|
|
823
1042
|
init_o200k_base2();
|
|
1043
|
+
init_o200k_harmony();
|
|
824
1044
|
init_p50k_base();
|
|
825
1045
|
init_p50k_edit();
|
|
826
1046
|
init_r50k_base();
|
|
@@ -833,6 +1053,7 @@ var init_GptEncoding = __esm({
|
|
|
833
1053
|
"node_modules/gpt-tokenizer/esm/GptEncoding.js"() {
|
|
834
1054
|
init_BytePairEncodingCore();
|
|
835
1055
|
init_constants();
|
|
1056
|
+
init_functionCalling();
|
|
836
1057
|
init_mapping();
|
|
837
1058
|
init_modelParams();
|
|
838
1059
|
init_specialTokens();
|
|
@@ -851,8 +1072,10 @@ var init_GptEncoding = __esm({
|
|
|
851
1072
|
specialTokensSet;
|
|
852
1073
|
allSpecialTokenRegex;
|
|
853
1074
|
defaultSpecialTokenConfig;
|
|
1075
|
+
chatFormatter;
|
|
1076
|
+
countChatCompletionTokens;
|
|
854
1077
|
vocabularySize;
|
|
855
|
-
constructor({ bytePairRankDecoder: mergeableBytePairRanks, specialTokensEncoder, expectedVocabularySize, modelName, modelSpec, ...rest }) {
|
|
1078
|
+
constructor({ bytePairRankDecoder: mergeableBytePairRanks, specialTokensEncoder, expectedVocabularySize, modelName, modelSpec, chatFormatter, ...rest }) {
|
|
856
1079
|
this.specialTokensEncoder = specialTokensEncoder;
|
|
857
1080
|
this.specialTokensSet = new Set(this.specialTokensEncoder.keys());
|
|
858
1081
|
this.allSpecialTokenRegex = getSpecialTokenRegex(this.specialTokensSet);
|
|
@@ -885,8 +1108,69 @@ var init_GptEncoding = __esm({
|
|
|
885
1108
|
this.setMergeCacheSize = this.setMergeCacheSize.bind(this);
|
|
886
1109
|
this.clearMergeCache = this.clearMergeCache.bind(this);
|
|
887
1110
|
this.estimateCost = this.estimateCost.bind(this);
|
|
1111
|
+
if (modelSpec?.supported_features?.includes("function_calling")) {
|
|
1112
|
+
this.countChatCompletionTokens = this.countChatCompletionTokensInternal.bind(this);
|
|
1113
|
+
}
|
|
888
1114
|
this.modelName = modelName;
|
|
889
1115
|
this.modelSpec = modelSpec;
|
|
1116
|
+
this.chatFormatter = chatFormatter ?? "chatml";
|
|
1117
|
+
}
|
|
1118
|
+
*encodeHarmonyChatGenerator(chat, encodeOptions) {
|
|
1119
|
+
const harmonyStart = this.specialTokensEncoder.get(HarmonyStart);
|
|
1120
|
+
const harmonyMessage = this.specialTokensEncoder.get(HarmonyMessage);
|
|
1121
|
+
const harmonyEnd = this.specialTokensEncoder.get(HarmonyEnd);
|
|
1122
|
+
const harmonyReturn = this.specialTokensEncoder.get(HarmonyReturn);
|
|
1123
|
+
const harmonyCall = this.specialTokensEncoder.get(HarmonyCall);
|
|
1124
|
+
const harmonyChannel = this.specialTokensEncoder.get(HarmonyChannel);
|
|
1125
|
+
const harmonyConstrain = this.specialTokensEncoder.get(HarmonyConstrain);
|
|
1126
|
+
if (harmonyStart === void 0 || harmonyMessage === void 0 || harmonyEnd === void 0 || harmonyReturn === void 0 || harmonyCall === void 0 || harmonyChannel === void 0 || harmonyConstrain === void 0) {
|
|
1127
|
+
throw new Error("Harmony chat format requires dedicated special tokens.");
|
|
1128
|
+
}
|
|
1129
|
+
const encodeHeaderText = (text) => text.length > 0 ? this.encode(text) : [];
|
|
1130
|
+
const resolveTerminatorToken = (terminator) => {
|
|
1131
|
+
switch (terminator) {
|
|
1132
|
+
case "<|return|>":
|
|
1133
|
+
return harmonyReturn;
|
|
1134
|
+
case "<|call|>":
|
|
1135
|
+
return harmonyCall;
|
|
1136
|
+
// eslint-disable-next-line unicorn/no-useless-switch-case
|
|
1137
|
+
case "<|end|>":
|
|
1138
|
+
default:
|
|
1139
|
+
return harmonyEnd;
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
for (const message of chat) {
|
|
1143
|
+
if (message.content === void 0) {
|
|
1144
|
+
throw new Error("Content must be defined for all messages.");
|
|
1145
|
+
}
|
|
1146
|
+
const roleOrName = message.name ?? message.role ?? "user";
|
|
1147
|
+
yield [harmonyStart];
|
|
1148
|
+
yield encodeHeaderText(roleOrName);
|
|
1149
|
+
const recipientInRole = message.recipient && (message.recipientPlacement === "role" || !message.channel);
|
|
1150
|
+
const recipientInChannel = message.recipient && !recipientInRole;
|
|
1151
|
+
if (recipientInRole) {
|
|
1152
|
+
yield encodeHeaderText(` to=${message.recipient}`);
|
|
1153
|
+
}
|
|
1154
|
+
if (message.channel) {
|
|
1155
|
+
yield [harmonyChannel];
|
|
1156
|
+
yield encodeHeaderText(message.channel);
|
|
1157
|
+
if (recipientInChannel) {
|
|
1158
|
+
yield encodeHeaderText(` to=${message.recipient}`);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
if (message.constraint) {
|
|
1162
|
+
yield [harmonyConstrain];
|
|
1163
|
+
yield encodeHeaderText(message.constraint);
|
|
1164
|
+
}
|
|
1165
|
+
yield [harmonyMessage];
|
|
1166
|
+
yield* this.encodeGenerator(message.content, encodeOptions);
|
|
1167
|
+
yield [resolveTerminatorToken(message.terminator)];
|
|
1168
|
+
}
|
|
1169
|
+
const assistantPrime = encodeOptions?.primeWithAssistantResponse ?? "assistant";
|
|
1170
|
+
if (assistantPrime.length > 0) {
|
|
1171
|
+
yield [harmonyStart];
|
|
1172
|
+
yield encodeHeaderText(assistantPrime);
|
|
1173
|
+
}
|
|
890
1174
|
}
|
|
891
1175
|
static getEncodingApi(encodingName, getMergeableRanks) {
|
|
892
1176
|
const modelParams = getEncodingParams(encodingName, getMergeableRanks);
|
|
@@ -959,9 +1243,16 @@ var init_GptEncoding = __esm({
|
|
|
959
1243
|
throw new Error("Model name must be provided either during initialization or passed in to the method.");
|
|
960
1244
|
}
|
|
961
1245
|
const params = chatModelParams[model];
|
|
1246
|
+
if (!params) {
|
|
1247
|
+
throw new Error(`Model '${model}' does not support chat.`);
|
|
1248
|
+
}
|
|
1249
|
+
if (this.chatFormatter === "harmony") {
|
|
1250
|
+
yield* this.encodeHarmonyChatGenerator(chat, encodeOptions);
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
962
1253
|
const chatStartToken = this.specialTokensEncoder.get(ImStart);
|
|
963
1254
|
const chatEndToken = this.specialTokensEncoder.get(ImEnd);
|
|
964
|
-
if (
|
|
1255
|
+
if (chatStartToken === void 0 || chatEndToken === void 0) {
|
|
965
1256
|
throw new Error(`Model '${model}' does not support chat.`);
|
|
966
1257
|
}
|
|
967
1258
|
const allowedSpecial = /* @__PURE__ */ new Set([ImSep]);
|
|
@@ -984,8 +1275,11 @@ var init_GptEncoding = __esm({
|
|
|
984
1275
|
yield [chatEndToken];
|
|
985
1276
|
yield encodedMessageSeparator;
|
|
986
1277
|
}
|
|
987
|
-
|
|
988
|
-
|
|
1278
|
+
const assistantPrime = encodeOptions?.primeWithAssistantResponse ?? "assistant";
|
|
1279
|
+
if (assistantPrime.length > 0) {
|
|
1280
|
+
yield [chatStartToken];
|
|
1281
|
+
yield* this.encodeGenerator(assistantPrime, encodeOptions);
|
|
1282
|
+
}
|
|
989
1283
|
if (encodedRoleSeparator.length > 0) {
|
|
990
1284
|
yield encodedRoleSeparator;
|
|
991
1285
|
}
|
|
@@ -1043,6 +1337,15 @@ var init_GptEncoding = __esm({
|
|
|
1043
1337
|
}
|
|
1044
1338
|
return count;
|
|
1045
1339
|
}
|
|
1340
|
+
countStringTokens(text) {
|
|
1341
|
+
if (!text) {
|
|
1342
|
+
return 0;
|
|
1343
|
+
}
|
|
1344
|
+
return this.bytePairEncodingCoreProcessor.countNative(text);
|
|
1345
|
+
}
|
|
1346
|
+
countChatCompletionTokensInternal(request) {
|
|
1347
|
+
return computeChatCompletionTokenCount(request, (text) => this.countStringTokens(text));
|
|
1348
|
+
}
|
|
1046
1349
|
setMergeCacheSize(size) {
|
|
1047
1350
|
this.bytePairEncodingCoreProcessor.setMergeCacheSize(size);
|
|
1048
1351
|
}
|
|
@@ -2007,7 +2310,7 @@ async function waitForFileLock(lockPath, binaryPath) {
|
|
|
2007
2310
|
}
|
|
2008
2311
|
} catch {
|
|
2009
2312
|
}
|
|
2010
|
-
await new Promise((
|
|
2313
|
+
await new Promise((resolve6) => setTimeout(resolve6, LOCK_POLL_INTERVAL_MS));
|
|
2011
2314
|
}
|
|
2012
2315
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
2013
2316
|
console.log(`Timeout waiting for file lock`);
|
|
@@ -2978,7 +3281,7 @@ Command: ${command}`;
|
|
|
2978
3281
|
}
|
|
2979
3282
|
}
|
|
2980
3283
|
function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
2981
|
-
return new Promise((
|
|
3284
|
+
return new Promise((resolve6, reject2) => {
|
|
2982
3285
|
const childProcess = spawn(binaryPath, ["extract", ...cliArgs], {
|
|
2983
3286
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2984
3287
|
});
|
|
@@ -3000,7 +3303,7 @@ function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
|
3000
3303
|
}
|
|
3001
3304
|
try {
|
|
3002
3305
|
const result = processExtractOutput(stdout, options);
|
|
3003
|
-
|
|
3306
|
+
resolve6(result);
|
|
3004
3307
|
} catch (error) {
|
|
3005
3308
|
reject2(error);
|
|
3006
3309
|
}
|
|
@@ -7483,7 +7786,15 @@ function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
|
7483
7786
|
if (openIndex === -1) {
|
|
7484
7787
|
continue;
|
|
7485
7788
|
}
|
|
7486
|
-
let closeIndex
|
|
7789
|
+
let closeIndex;
|
|
7790
|
+
if (toolName === "attempt_completion") {
|
|
7791
|
+
closeIndex = xmlString.lastIndexOf(closeTag);
|
|
7792
|
+
if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
|
|
7793
|
+
closeIndex = -1;
|
|
7794
|
+
}
|
|
7795
|
+
} else {
|
|
7796
|
+
closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
|
|
7797
|
+
}
|
|
7487
7798
|
let hasClosingTag = closeIndex !== -1;
|
|
7488
7799
|
if (closeIndex === -1) {
|
|
7489
7800
|
closeIndex = xmlString.length;
|
|
@@ -7560,7 +7871,7 @@ function parseTargets(targets) {
|
|
|
7560
7871
|
}
|
|
7561
7872
|
return targets.split(/\s+/).filter((f) => f.length > 0);
|
|
7562
7873
|
}
|
|
7563
|
-
var searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
|
|
7874
|
+
var searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
|
|
7564
7875
|
var init_common = __esm({
|
|
7565
7876
|
"src/tools/common.js"() {
|
|
7566
7877
|
"use strict";
|
|
@@ -7573,11 +7884,12 @@ var init_common = __esm({
|
|
|
7573
7884
|
pattern: external_exports.string().describe("AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc."),
|
|
7574
7885
|
path: external_exports.string().optional().default(".").describe("Path to search in"),
|
|
7575
7886
|
language: external_exports.string().optional().default("rust").describe("Programming language to use for parsing"),
|
|
7576
|
-
allow_tests: external_exports.boolean().optional().default(
|
|
7887
|
+
allow_tests: external_exports.boolean().optional().default(true).describe("Allow test files in search results")
|
|
7577
7888
|
});
|
|
7578
7889
|
extractSchema = external_exports.object({
|
|
7579
7890
|
targets: external_exports.string().optional().describe('File paths or symbols to extract from. Formats: "file.js" (whole file), "file.js:42" (line 42), "file.js:10-20" (lines 10-20), "file.js#funcName" (symbol). Multiple targets separated by spaces.'),
|
|
7580
|
-
input_content: external_exports.string().optional().describe("Text content to extract file paths from (alternative to targets)")
|
|
7891
|
+
input_content: external_exports.string().optional().describe("Text content to extract file paths from (alternative to targets)"),
|
|
7892
|
+
allow_tests: external_exports.boolean().optional().default(true).describe("Include test files in extraction results")
|
|
7581
7893
|
});
|
|
7582
7894
|
delegateSchema = external_exports.object({
|
|
7583
7895
|
task: external_exports.string().describe("The task to delegate to a subagent. Be specific about what needs to be accomplished.")
|
|
@@ -7704,7 +8016,7 @@ Parameters:
|
|
|
7704
8016
|
- pattern: (required) AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc.
|
|
7705
8017
|
- path: (optional, default: '.') Path to search in.
|
|
7706
8018
|
- language: (optional, default: 'rust') Programming language to use for parsing.
|
|
7707
|
-
- allow_tests: (optional, default:
|
|
8019
|
+
- allow_tests: (optional, default: true) Allow test files in search results (true/false).
|
|
7708
8020
|
Usage Example:
|
|
7709
8021
|
|
|
7710
8022
|
<examples>
|
|
@@ -7729,6 +8041,7 @@ Full file extraction should be the LAST RESORT! Always prefer search.
|
|
|
7729
8041
|
Parameters:
|
|
7730
8042
|
- targets: (required) File paths or symbols to extract from. Formats: "file.js" (whole file), "file.js:42" (code block at line 42), "file.js:10-20" (lines 10-20), "file.js#funcName" (specific symbol). Multiple targets separated by spaces.
|
|
7731
8043
|
- input_content: (optional) Text content to extract file paths from (alternative to targets for processing diffs/logs).
|
|
8044
|
+
- allow_tests: (optional, default: true) Include test files in extraction results.
|
|
7732
8045
|
|
|
7733
8046
|
Usage Example:
|
|
7734
8047
|
|
|
@@ -7795,6 +8108,61 @@ Usage Example:
|
|
|
7795
8108
|
<attempt_completion>
|
|
7796
8109
|
I have refactored the search module according to the requirements and verified the tests pass. The module now uses the new BM25 ranking algorithm and has improved error handling.
|
|
7797
8110
|
</attempt_completion>
|
|
8111
|
+
`;
|
|
8112
|
+
bashToolDefinition = `
|
|
8113
|
+
## bash
|
|
8114
|
+
Description: Execute bash commands for system exploration and development tasks. This tool has built-in security with allow/deny lists. By default, only safe read-only commands are allowed for code exploration.
|
|
8115
|
+
|
|
8116
|
+
Parameters:
|
|
8117
|
+
- command: (required) The bash command to execute
|
|
8118
|
+
- workingDirectory: (optional) Directory to execute the command in
|
|
8119
|
+
- timeout: (optional) Command timeout in milliseconds
|
|
8120
|
+
- env: (optional) Additional environment variables as an object
|
|
8121
|
+
|
|
8122
|
+
Security: Commands are filtered through allow/deny lists for safety:
|
|
8123
|
+
- Allowed by default: ls, cat, git status, npm list, find, grep, etc.
|
|
8124
|
+
- Denied by default: rm -rf, sudo, npm install, dangerous system commands
|
|
8125
|
+
|
|
8126
|
+
Usage Examples:
|
|
8127
|
+
|
|
8128
|
+
<examples>
|
|
8129
|
+
|
|
8130
|
+
User: What files are in the src directory?
|
|
8131
|
+
<bash>
|
|
8132
|
+
<command>ls -la src/</command>
|
|
8133
|
+
</bash>
|
|
8134
|
+
|
|
8135
|
+
User: Show me the git status
|
|
8136
|
+
<bash>
|
|
8137
|
+
<command>git status</command>
|
|
8138
|
+
</bash>
|
|
8139
|
+
|
|
8140
|
+
User: Find all TypeScript files
|
|
8141
|
+
<bash>
|
|
8142
|
+
<command>find . -name "*.ts" -type f</command>
|
|
8143
|
+
</bash>
|
|
8144
|
+
|
|
8145
|
+
User: Check installed npm packages
|
|
8146
|
+
<bash>
|
|
8147
|
+
<command>npm list --depth=0</command>
|
|
8148
|
+
</bash>
|
|
8149
|
+
|
|
8150
|
+
User: Search for TODO comments in code
|
|
8151
|
+
<bash>
|
|
8152
|
+
<command>grep -r "TODO" src/</command>
|
|
8153
|
+
</bash>
|
|
8154
|
+
|
|
8155
|
+
User: Show recent git commits
|
|
8156
|
+
<bash>
|
|
8157
|
+
<command>git log --oneline -10</command>
|
|
8158
|
+
</bash>
|
|
8159
|
+
|
|
8160
|
+
User: Check system info
|
|
8161
|
+
<bash>
|
|
8162
|
+
<command>uname -a</command>
|
|
8163
|
+
</bash>
|
|
8164
|
+
|
|
8165
|
+
</examples>
|
|
7798
8166
|
`;
|
|
7799
8167
|
searchDescription = "Search code in the repository using Elasticsearch-like query syntax. Use this tool first for any code-related questions.";
|
|
7800
8168
|
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
@@ -8894,14 +9262,14 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8894
9262
|
console.log(`[BashExecutor] Working directory: "${cwd}"`);
|
|
8895
9263
|
console.log(`[BashExecutor] Timeout: ${timeout}ms`);
|
|
8896
9264
|
}
|
|
8897
|
-
return new Promise((
|
|
9265
|
+
return new Promise((resolve6, reject2) => {
|
|
8898
9266
|
const processEnv = {
|
|
8899
9267
|
...process.env,
|
|
8900
9268
|
...env
|
|
8901
9269
|
};
|
|
8902
9270
|
const args = parseCommandForExecution(command);
|
|
8903
9271
|
if (!args || args.length === 0) {
|
|
8904
|
-
|
|
9272
|
+
resolve6({
|
|
8905
9273
|
success: false,
|
|
8906
9274
|
error: "Failed to parse command",
|
|
8907
9275
|
stdout: "",
|
|
@@ -8984,7 +9352,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8984
9352
|
success = false;
|
|
8985
9353
|
error = `Command exited with code ${code}`;
|
|
8986
9354
|
}
|
|
8987
|
-
|
|
9355
|
+
resolve6({
|
|
8988
9356
|
success,
|
|
8989
9357
|
error,
|
|
8990
9358
|
stdout: stdout.trim(),
|
|
@@ -9004,7 +9372,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
9004
9372
|
if (debug) {
|
|
9005
9373
|
console.log(`[BashExecutor] Spawn error:`, error);
|
|
9006
9374
|
}
|
|
9007
|
-
|
|
9375
|
+
resolve6({
|
|
9008
9376
|
success: false,
|
|
9009
9377
|
error: `Failed to execute command: ${error.message}`,
|
|
9010
9378
|
stdout: "",
|
|
@@ -9276,6 +9644,283 @@ Command failed with exit code ${result.exitCode}`;
|
|
|
9276
9644
|
}
|
|
9277
9645
|
});
|
|
9278
9646
|
|
|
9647
|
+
// src/tools/edit.js
|
|
9648
|
+
import { tool as tool3 } from "ai";
|
|
9649
|
+
import { promises as fs4 } from "fs";
|
|
9650
|
+
import { dirname, resolve as resolve3, isAbsolute, sep } from "path";
|
|
9651
|
+
import { existsSync as existsSync2 } from "fs";
|
|
9652
|
+
function isPathAllowed(filePath, allowedFolders) {
|
|
9653
|
+
if (!allowedFolders || allowedFolders.length === 0) {
|
|
9654
|
+
const resolvedPath2 = resolve3(filePath);
|
|
9655
|
+
const cwd = resolve3(process.cwd());
|
|
9656
|
+
return resolvedPath2 === cwd || resolvedPath2.startsWith(cwd + sep);
|
|
9657
|
+
}
|
|
9658
|
+
const resolvedPath = resolve3(filePath);
|
|
9659
|
+
return allowedFolders.some((folder) => {
|
|
9660
|
+
const allowedPath = resolve3(folder);
|
|
9661
|
+
return resolvedPath === allowedPath || resolvedPath.startsWith(allowedPath + sep);
|
|
9662
|
+
});
|
|
9663
|
+
}
|
|
9664
|
+
function parseFileToolOptions(options = {}) {
|
|
9665
|
+
return {
|
|
9666
|
+
debug: options.debug || false,
|
|
9667
|
+
allowedFolders: options.allowedFolders || [],
|
|
9668
|
+
defaultPath: options.defaultPath
|
|
9669
|
+
};
|
|
9670
|
+
}
|
|
9671
|
+
var editTool, createTool, editDescription, createDescription, editToolDefinition, createToolDefinition;
|
|
9672
|
+
var init_edit = __esm({
|
|
9673
|
+
"src/tools/edit.js"() {
|
|
9674
|
+
"use strict";
|
|
9675
|
+
editTool = (options = {}) => {
|
|
9676
|
+
const { debug, allowedFolders, defaultPath } = parseFileToolOptions(options);
|
|
9677
|
+
return tool3({
|
|
9678
|
+
name: "edit",
|
|
9679
|
+
description: `Edit files using exact string replacement (Claude Code style).
|
|
9680
|
+
|
|
9681
|
+
This tool performs exact string replacements in files. It requires the old_string to match exactly what's in the file, including all whitespace and indentation.
|
|
9682
|
+
|
|
9683
|
+
Parameters:
|
|
9684
|
+
- file_path: Path to the file to edit (absolute or relative)
|
|
9685
|
+
- old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
|
|
9686
|
+
- new_string: Text to replace with
|
|
9687
|
+
- replace_all: (optional) Replace all occurrences instead of requiring uniqueness
|
|
9688
|
+
|
|
9689
|
+
Important:
|
|
9690
|
+
- The old_string must match EXACTLY including whitespace
|
|
9691
|
+
- If old_string appears multiple times and replace_all is false, the edit will fail
|
|
9692
|
+
- Use larger context around the string to ensure uniqueness when needed`,
|
|
9693
|
+
inputSchema: {
|
|
9694
|
+
type: "object",
|
|
9695
|
+
properties: {
|
|
9696
|
+
file_path: {
|
|
9697
|
+
type: "string",
|
|
9698
|
+
description: "Path to the file to edit"
|
|
9699
|
+
},
|
|
9700
|
+
old_string: {
|
|
9701
|
+
type: "string",
|
|
9702
|
+
description: "Exact text to find and replace"
|
|
9703
|
+
},
|
|
9704
|
+
new_string: {
|
|
9705
|
+
type: "string",
|
|
9706
|
+
description: "Text to replace with"
|
|
9707
|
+
},
|
|
9708
|
+
replace_all: {
|
|
9709
|
+
type: "boolean",
|
|
9710
|
+
description: "Replace all occurrences (default: false)",
|
|
9711
|
+
default: false
|
|
9712
|
+
}
|
|
9713
|
+
},
|
|
9714
|
+
required: ["file_path", "old_string", "new_string"]
|
|
9715
|
+
},
|
|
9716
|
+
execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
|
|
9717
|
+
try {
|
|
9718
|
+
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
9719
|
+
return `Error editing file: Invalid file_path - must be a non-empty string`;
|
|
9720
|
+
}
|
|
9721
|
+
if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
|
|
9722
|
+
return `Error editing file: Invalid old_string - must be a string`;
|
|
9723
|
+
}
|
|
9724
|
+
if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
|
|
9725
|
+
return `Error editing file: Invalid new_string - must be a string`;
|
|
9726
|
+
}
|
|
9727
|
+
const resolvedPath = isAbsolute(file_path) ? file_path : resolve3(defaultPath || process.cwd(), file_path);
|
|
9728
|
+
if (debug) {
|
|
9729
|
+
console.error(`[Edit] Attempting to edit file: ${resolvedPath}`);
|
|
9730
|
+
}
|
|
9731
|
+
if (!isPathAllowed(resolvedPath, allowedFolders)) {
|
|
9732
|
+
return `Error editing file: Permission denied - ${file_path} is outside allowed directories`;
|
|
9733
|
+
}
|
|
9734
|
+
if (!existsSync2(resolvedPath)) {
|
|
9735
|
+
return `Error editing file: File not found - ${file_path}`;
|
|
9736
|
+
}
|
|
9737
|
+
const content = await fs4.readFile(resolvedPath, "utf-8");
|
|
9738
|
+
if (!content.includes(old_string)) {
|
|
9739
|
+
return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
|
|
9740
|
+
}
|
|
9741
|
+
const occurrences = content.split(old_string).length - 1;
|
|
9742
|
+
if (!replace_all && occurrences > 1) {
|
|
9743
|
+
return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times. Use replace_all: true to replace all occurrences, or provide more context to make the string unique.`;
|
|
9744
|
+
}
|
|
9745
|
+
let newContent;
|
|
9746
|
+
if (replace_all) {
|
|
9747
|
+
newContent = content.replaceAll(old_string, new_string);
|
|
9748
|
+
} else {
|
|
9749
|
+
newContent = content.replace(old_string, new_string);
|
|
9750
|
+
}
|
|
9751
|
+
if (newContent === content) {
|
|
9752
|
+
return `Error editing file: No changes made - old_string and new_string might be the same`;
|
|
9753
|
+
}
|
|
9754
|
+
await fs4.writeFile(resolvedPath, newContent, "utf-8");
|
|
9755
|
+
const replacedCount = replace_all ? occurrences : 1;
|
|
9756
|
+
if (debug) {
|
|
9757
|
+
console.error(`[Edit] Successfully edited ${resolvedPath}, replaced ${replacedCount} occurrence(s)`);
|
|
9758
|
+
}
|
|
9759
|
+
return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
|
|
9760
|
+
} catch (error) {
|
|
9761
|
+
console.error("[Edit] Error:", error);
|
|
9762
|
+
return `Error editing file: ${error.message}`;
|
|
9763
|
+
}
|
|
9764
|
+
}
|
|
9765
|
+
});
|
|
9766
|
+
};
|
|
9767
|
+
createTool = (options = {}) => {
|
|
9768
|
+
const { debug, allowedFolders, defaultPath } = parseFileToolOptions(options);
|
|
9769
|
+
return tool3({
|
|
9770
|
+
name: "create",
|
|
9771
|
+
description: `Create new files with specified content.
|
|
9772
|
+
|
|
9773
|
+
This tool creates new files in the filesystem. It will create parent directories if they don't exist.
|
|
9774
|
+
|
|
9775
|
+
Parameters:
|
|
9776
|
+
- file_path: Path where the file should be created (absolute or relative)
|
|
9777
|
+
- content: Content to write to the file
|
|
9778
|
+
- overwrite: (optional) Whether to overwrite if file exists (default: false)
|
|
9779
|
+
|
|
9780
|
+
Important:
|
|
9781
|
+
- By default, will fail if the file already exists
|
|
9782
|
+
- Set overwrite: true to replace existing files
|
|
9783
|
+
- Parent directories will be created automatically if needed`,
|
|
9784
|
+
inputSchema: {
|
|
9785
|
+
type: "object",
|
|
9786
|
+
properties: {
|
|
9787
|
+
file_path: {
|
|
9788
|
+
type: "string",
|
|
9789
|
+
description: "Path where the file should be created"
|
|
9790
|
+
},
|
|
9791
|
+
content: {
|
|
9792
|
+
type: "string",
|
|
9793
|
+
description: "Content to write to the file"
|
|
9794
|
+
},
|
|
9795
|
+
overwrite: {
|
|
9796
|
+
type: "boolean",
|
|
9797
|
+
description: "Overwrite if file exists (default: false)",
|
|
9798
|
+
default: false
|
|
9799
|
+
}
|
|
9800
|
+
},
|
|
9801
|
+
required: ["file_path", "content"]
|
|
9802
|
+
},
|
|
9803
|
+
execute: async ({ file_path, content, overwrite = false }) => {
|
|
9804
|
+
try {
|
|
9805
|
+
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
9806
|
+
return `Error creating file: Invalid file_path - must be a non-empty string`;
|
|
9807
|
+
}
|
|
9808
|
+
if (content === void 0 || content === null || typeof content !== "string") {
|
|
9809
|
+
return `Error creating file: Invalid content - must be a string`;
|
|
9810
|
+
}
|
|
9811
|
+
const resolvedPath = isAbsolute(file_path) ? file_path : resolve3(defaultPath || process.cwd(), file_path);
|
|
9812
|
+
if (debug) {
|
|
9813
|
+
console.error(`[Create] Attempting to create file: ${resolvedPath}`);
|
|
9814
|
+
}
|
|
9815
|
+
if (!isPathAllowed(resolvedPath, allowedFolders)) {
|
|
9816
|
+
return `Error creating file: Permission denied - ${file_path} is outside allowed directories`;
|
|
9817
|
+
}
|
|
9818
|
+
if (existsSync2(resolvedPath) && !overwrite) {
|
|
9819
|
+
return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
|
|
9820
|
+
}
|
|
9821
|
+
const dir = dirname(resolvedPath);
|
|
9822
|
+
await fs4.mkdir(dir, { recursive: true });
|
|
9823
|
+
await fs4.writeFile(resolvedPath, content, "utf-8");
|
|
9824
|
+
const action = existsSync2(resolvedPath) && overwrite ? "overwrote" : "created";
|
|
9825
|
+
const bytes = Buffer.byteLength(content, "utf-8");
|
|
9826
|
+
if (debug) {
|
|
9827
|
+
console.error(`[Create] Successfully ${action} ${resolvedPath}`);
|
|
9828
|
+
}
|
|
9829
|
+
return `Successfully ${action} ${file_path} (${bytes} bytes)`;
|
|
9830
|
+
} catch (error) {
|
|
9831
|
+
console.error("[Create] Error:", error);
|
|
9832
|
+
return `Error creating file: ${error.message}`;
|
|
9833
|
+
}
|
|
9834
|
+
}
|
|
9835
|
+
});
|
|
9836
|
+
};
|
|
9837
|
+
editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
|
|
9838
|
+
createDescription = "Create new files with specified content. Will create parent directories if needed.";
|
|
9839
|
+
editToolDefinition = `
|
|
9840
|
+
## edit
|
|
9841
|
+
Description: ${editDescription}
|
|
9842
|
+
|
|
9843
|
+
When to use:
|
|
9844
|
+
- For precise, surgical edits to existing files
|
|
9845
|
+
- When you need to change specific lines or blocks of code
|
|
9846
|
+
- For renaming functions, variables, or updating configuration values
|
|
9847
|
+
- When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
|
|
9848
|
+
|
|
9849
|
+
When NOT to use:
|
|
9850
|
+
- For creating new files (use 'create' tool instead)
|
|
9851
|
+
- When you cannot determine the exact text to replace
|
|
9852
|
+
- When changes span multiple locations that would be better handled together
|
|
9853
|
+
|
|
9854
|
+
Parameters:
|
|
9855
|
+
- file_path: (required) Path to the file to edit
|
|
9856
|
+
- old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
|
|
9857
|
+
- new_string: (required) Text to replace with
|
|
9858
|
+
- replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
|
|
9859
|
+
|
|
9860
|
+
Important notes:
|
|
9861
|
+
- The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
|
|
9862
|
+
- If old_string appears multiple times and replace_all is false, the tool will fail
|
|
9863
|
+
- Always verify the exact formatting of the text you want to replace
|
|
9864
|
+
|
|
9865
|
+
Examples:
|
|
9866
|
+
<edit>
|
|
9867
|
+
<file_path>src/main.js</file_path>
|
|
9868
|
+
<old_string>function oldName() {
|
|
9869
|
+
return 42;
|
|
9870
|
+
}</old_string>
|
|
9871
|
+
<new_string>function newName() {
|
|
9872
|
+
return 42;
|
|
9873
|
+
}</new_string>
|
|
9874
|
+
</edit>
|
|
9875
|
+
|
|
9876
|
+
<edit>
|
|
9877
|
+
<file_path>config.json</file_path>
|
|
9878
|
+
<old_string>"debug": false</old_string>
|
|
9879
|
+
<new_string>"debug": true</new_string>
|
|
9880
|
+
<replace_all>true</replace_all>
|
|
9881
|
+
</edit>`;
|
|
9882
|
+
createToolDefinition = `
|
|
9883
|
+
## create
|
|
9884
|
+
Description: ${createDescription}
|
|
9885
|
+
|
|
9886
|
+
When to use:
|
|
9887
|
+
- For creating brand new files from scratch
|
|
9888
|
+
- When you need to add configuration files, documentation, or new modules
|
|
9889
|
+
- For generating boilerplate code or templates
|
|
9890
|
+
- When you have the complete content ready to write
|
|
9891
|
+
|
|
9892
|
+
When NOT to use:
|
|
9893
|
+
- For editing existing files (use 'edit' tool instead)
|
|
9894
|
+
- When a file already exists unless you explicitly want to overwrite it
|
|
9895
|
+
|
|
9896
|
+
Parameters:
|
|
9897
|
+
- file_path: (required) Path where the file should be created
|
|
9898
|
+
- content: (required) Complete content to write to the file
|
|
9899
|
+
- overwrite: (optional, default: false) Whether to overwrite if file already exists
|
|
9900
|
+
|
|
9901
|
+
Important notes:
|
|
9902
|
+
- Parent directories will be created automatically if they don't exist
|
|
9903
|
+
- The tool will fail if the file already exists and overwrite is false
|
|
9904
|
+
- Be careful with the overwrite option as it completely replaces existing files
|
|
9905
|
+
|
|
9906
|
+
Examples:
|
|
9907
|
+
<create>
|
|
9908
|
+
<file_path>src/newFile.js</file_path>
|
|
9909
|
+
<content>export function hello() {
|
|
9910
|
+
return "Hello, world!";
|
|
9911
|
+
}</content>
|
|
9912
|
+
</create>
|
|
9913
|
+
|
|
9914
|
+
<create>
|
|
9915
|
+
<file_path>README.md</file_path>
|
|
9916
|
+
<content># My Project
|
|
9917
|
+
|
|
9918
|
+
This is a new project.</content>
|
|
9919
|
+
<overwrite>true</overwrite>
|
|
9920
|
+
</create>`;
|
|
9921
|
+
}
|
|
9922
|
+
});
|
|
9923
|
+
|
|
9279
9924
|
// src/tools/langchain.js
|
|
9280
9925
|
var init_langchain = __esm({
|
|
9281
9926
|
"src/tools/langchain.js"() {
|
|
@@ -9425,8 +10070,10 @@ var init_tools = __esm({
|
|
|
9425
10070
|
"use strict";
|
|
9426
10071
|
init_vercel();
|
|
9427
10072
|
init_bash();
|
|
10073
|
+
init_edit();
|
|
9428
10074
|
init_langchain();
|
|
9429
10075
|
init_common();
|
|
10076
|
+
init_edit();
|
|
9430
10077
|
init_system_message();
|
|
9431
10078
|
init_vercel();
|
|
9432
10079
|
init_bash();
|
|
@@ -9443,7 +10090,7 @@ var init_tools = __esm({
|
|
|
9443
10090
|
});
|
|
9444
10091
|
|
|
9445
10092
|
// src/utils/file-lister.js
|
|
9446
|
-
import
|
|
10093
|
+
import fs5 from "fs";
|
|
9447
10094
|
import path4 from "path";
|
|
9448
10095
|
import { promisify as promisify6 } from "util";
|
|
9449
10096
|
import { exec as exec4 } from "child_process";
|
|
@@ -9453,10 +10100,10 @@ async function listFilesByLevel(options) {
|
|
|
9453
10100
|
maxFiles = 100,
|
|
9454
10101
|
respectGitignore = true
|
|
9455
10102
|
} = options;
|
|
9456
|
-
if (!
|
|
10103
|
+
if (!fs5.existsSync(directory)) {
|
|
9457
10104
|
throw new Error(`Directory does not exist: ${directory}`);
|
|
9458
10105
|
}
|
|
9459
|
-
const gitDirExists =
|
|
10106
|
+
const gitDirExists = fs5.existsSync(path4.join(directory, ".git"));
|
|
9460
10107
|
if (gitDirExists && respectGitignore) {
|
|
9461
10108
|
try {
|
|
9462
10109
|
return await listFilesUsingGit(directory, maxFiles);
|
|
@@ -9487,7 +10134,7 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
|
|
|
9487
10134
|
while (queue.length > 0 && result.length < maxFiles) {
|
|
9488
10135
|
const { dir, level } = queue.shift();
|
|
9489
10136
|
try {
|
|
9490
|
-
const entries =
|
|
10137
|
+
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
9491
10138
|
const files = entries.filter((entry) => entry.isFile());
|
|
9492
10139
|
for (const file of files) {
|
|
9493
10140
|
if (result.length >= maxFiles) break;
|
|
@@ -9512,11 +10159,11 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
|
|
|
9512
10159
|
}
|
|
9513
10160
|
function loadGitignorePatterns(directory) {
|
|
9514
10161
|
const gitignorePath = path4.join(directory, ".gitignore");
|
|
9515
|
-
if (!
|
|
10162
|
+
if (!fs5.existsSync(gitignorePath)) {
|
|
9516
10163
|
return [];
|
|
9517
10164
|
}
|
|
9518
10165
|
try {
|
|
9519
|
-
const content =
|
|
10166
|
+
const content = fs5.readFileSync(gitignorePath, "utf8");
|
|
9520
10167
|
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
9521
10168
|
} catch (error) {
|
|
9522
10169
|
console.error(`Warning: Could not read .gitignore: ${error.message}`);
|
|
@@ -9543,8 +10190,8 @@ var init_file_lister = __esm({
|
|
|
9543
10190
|
});
|
|
9544
10191
|
|
|
9545
10192
|
// src/agent/simpleTelemetry.js
|
|
9546
|
-
import { existsSync as
|
|
9547
|
-
import { dirname } from "path";
|
|
10193
|
+
import { existsSync as existsSync3, mkdirSync, createWriteStream } from "fs";
|
|
10194
|
+
import { dirname as dirname2 } from "path";
|
|
9548
10195
|
function initializeSimpleTelemetryFromOptions(options) {
|
|
9549
10196
|
const telemetry = new SimpleTelemetry({
|
|
9550
10197
|
serviceName: "probe-agent",
|
|
@@ -9571,8 +10218,8 @@ var init_simpleTelemetry = __esm({
|
|
|
9571
10218
|
}
|
|
9572
10219
|
initializeFileExporter() {
|
|
9573
10220
|
try {
|
|
9574
|
-
const dir =
|
|
9575
|
-
if (!
|
|
10221
|
+
const dir = dirname2(this.filePath);
|
|
10222
|
+
if (!existsSync3(dir)) {
|
|
9576
10223
|
mkdirSync(dir, { recursive: true });
|
|
9577
10224
|
}
|
|
9578
10225
|
this.stream = createWriteStream(this.filePath, { flags: "a" });
|
|
@@ -9636,20 +10283,20 @@ var init_simpleTelemetry = __esm({
|
|
|
9636
10283
|
}
|
|
9637
10284
|
async flush() {
|
|
9638
10285
|
if (this.stream) {
|
|
9639
|
-
return new Promise((
|
|
9640
|
-
this.stream.once("drain",
|
|
10286
|
+
return new Promise((resolve6) => {
|
|
10287
|
+
this.stream.once("drain", resolve6);
|
|
9641
10288
|
if (!this.stream.writableNeedDrain) {
|
|
9642
|
-
|
|
10289
|
+
resolve6();
|
|
9643
10290
|
}
|
|
9644
10291
|
});
|
|
9645
10292
|
}
|
|
9646
10293
|
}
|
|
9647
10294
|
async shutdown() {
|
|
9648
10295
|
if (this.stream) {
|
|
9649
|
-
return new Promise((
|
|
10296
|
+
return new Promise((resolve6) => {
|
|
9650
10297
|
this.stream.end(() => {
|
|
9651
10298
|
console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
|
|
9652
|
-
|
|
10299
|
+
resolve6();
|
|
9653
10300
|
});
|
|
9654
10301
|
});
|
|
9655
10302
|
}
|
|
@@ -10612,7 +11259,7 @@ var init_escape = __esm({
|
|
|
10612
11259
|
});
|
|
10613
11260
|
|
|
10614
11261
|
// node_modules/minimatch/dist/esm/index.js
|
|
10615
|
-
var import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5,
|
|
11262
|
+
var import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep2, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
|
|
10616
11263
|
var init_esm = __esm({
|
|
10617
11264
|
"node_modules/minimatch/dist/esm/index.js"() {
|
|
10618
11265
|
import_brace_expansion = __toESM(require_brace_expansion(), 1);
|
|
@@ -10685,8 +11332,8 @@ var init_esm = __esm({
|
|
|
10685
11332
|
win32: { sep: "\\" },
|
|
10686
11333
|
posix: { sep: "/" }
|
|
10687
11334
|
};
|
|
10688
|
-
|
|
10689
|
-
minimatch.sep =
|
|
11335
|
+
sep2 = defaultPlatform === "win32" ? path5.win32.sep : path5.posix.sep;
|
|
11336
|
+
minimatch.sep = sep2;
|
|
10690
11337
|
GLOBSTAR = Symbol("globstar **");
|
|
10691
11338
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
10692
11339
|
qmark2 = "[^/]";
|
|
@@ -13448,10 +14095,10 @@ var init_esm3 = __esm({
|
|
|
13448
14095
|
* Return a void Promise that resolves once the stream ends.
|
|
13449
14096
|
*/
|
|
13450
14097
|
async promise() {
|
|
13451
|
-
return new Promise((
|
|
14098
|
+
return new Promise((resolve6, reject2) => {
|
|
13452
14099
|
this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
|
|
13453
14100
|
this.on("error", (er) => reject2(er));
|
|
13454
|
-
this.on("end", () =>
|
|
14101
|
+
this.on("end", () => resolve6());
|
|
13455
14102
|
});
|
|
13456
14103
|
}
|
|
13457
14104
|
/**
|
|
@@ -13475,7 +14122,7 @@ var init_esm3 = __esm({
|
|
|
13475
14122
|
return Promise.resolve({ done: false, value: res });
|
|
13476
14123
|
if (this[EOF])
|
|
13477
14124
|
return stop();
|
|
13478
|
-
let
|
|
14125
|
+
let resolve6;
|
|
13479
14126
|
let reject2;
|
|
13480
14127
|
const onerr = (er) => {
|
|
13481
14128
|
this.off("data", ondata);
|
|
@@ -13489,19 +14136,19 @@ var init_esm3 = __esm({
|
|
|
13489
14136
|
this.off("end", onend);
|
|
13490
14137
|
this.off(DESTROYED, ondestroy);
|
|
13491
14138
|
this.pause();
|
|
13492
|
-
|
|
14139
|
+
resolve6({ value, done: !!this[EOF] });
|
|
13493
14140
|
};
|
|
13494
14141
|
const onend = () => {
|
|
13495
14142
|
this.off("error", onerr);
|
|
13496
14143
|
this.off("data", ondata);
|
|
13497
14144
|
this.off(DESTROYED, ondestroy);
|
|
13498
14145
|
stop();
|
|
13499
|
-
|
|
14146
|
+
resolve6({ done: true, value: void 0 });
|
|
13500
14147
|
};
|
|
13501
14148
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
13502
14149
|
return new Promise((res2, rej) => {
|
|
13503
14150
|
reject2 = rej;
|
|
13504
|
-
|
|
14151
|
+
resolve6 = res2;
|
|
13505
14152
|
this.once(DESTROYED, ondestroy);
|
|
13506
14153
|
this.once("error", onerr);
|
|
13507
14154
|
this.once("end", onend);
|
|
@@ -14481,9 +15128,9 @@ var init_esm4 = __esm({
|
|
|
14481
15128
|
if (this.#asyncReaddirInFlight) {
|
|
14482
15129
|
await this.#asyncReaddirInFlight;
|
|
14483
15130
|
} else {
|
|
14484
|
-
let
|
|
15131
|
+
let resolve6 = () => {
|
|
14485
15132
|
};
|
|
14486
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
15133
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve6 = res);
|
|
14487
15134
|
try {
|
|
14488
15135
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
14489
15136
|
withFileTypes: true
|
|
@@ -14496,7 +15143,7 @@ var init_esm4 = __esm({
|
|
|
14496
15143
|
children.provisional = 0;
|
|
14497
15144
|
}
|
|
14498
15145
|
this.#asyncReaddirInFlight = void 0;
|
|
14499
|
-
|
|
15146
|
+
resolve6();
|
|
14500
15147
|
}
|
|
14501
15148
|
return children.slice(0, children.provisional);
|
|
14502
15149
|
}
|
|
@@ -14726,8 +15373,8 @@ var init_esm4 = __esm({
|
|
|
14726
15373
|
*
|
|
14727
15374
|
* @internal
|
|
14728
15375
|
*/
|
|
14729
|
-
constructor(cwd = process.cwd(), pathImpl,
|
|
14730
|
-
this.#fs = fsFromOption(
|
|
15376
|
+
constructor(cwd = process.cwd(), pathImpl, sep3, { nocase, childrenCacheSize = 16 * 1024, fs: fs7 = defaultFS } = {}) {
|
|
15377
|
+
this.#fs = fsFromOption(fs7);
|
|
14731
15378
|
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
|
14732
15379
|
cwd = fileURLToPath4(cwd);
|
|
14733
15380
|
}
|
|
@@ -14737,7 +15384,7 @@ var init_esm4 = __esm({
|
|
|
14737
15384
|
this.#resolveCache = new ResolveCache();
|
|
14738
15385
|
this.#resolvePosixCache = new ResolveCache();
|
|
14739
15386
|
this.#children = new ChildrenCache(childrenCacheSize);
|
|
14740
|
-
const split = cwdPath.substring(this.rootPath.length).split(
|
|
15387
|
+
const split = cwdPath.substring(this.rootPath.length).split(sep3);
|
|
14741
15388
|
if (split.length === 1 && !split[0]) {
|
|
14742
15389
|
split.pop();
|
|
14743
15390
|
}
|
|
@@ -15285,8 +15932,8 @@ var init_esm4 = __esm({
|
|
|
15285
15932
|
/**
|
|
15286
15933
|
* @internal
|
|
15287
15934
|
*/
|
|
15288
|
-
newRoot(
|
|
15289
|
-
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
15935
|
+
newRoot(fs7) {
|
|
15936
|
+
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs7 });
|
|
15290
15937
|
}
|
|
15291
15938
|
/**
|
|
15292
15939
|
* Return true if the provided path string is an absolute path
|
|
@@ -15314,8 +15961,8 @@ var init_esm4 = __esm({
|
|
|
15314
15961
|
/**
|
|
15315
15962
|
* @internal
|
|
15316
15963
|
*/
|
|
15317
|
-
newRoot(
|
|
15318
|
-
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
15964
|
+
newRoot(fs7) {
|
|
15965
|
+
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs7 });
|
|
15319
15966
|
}
|
|
15320
15967
|
/**
|
|
15321
15968
|
* Return true if the provided path string is an absolute path
|
|
@@ -16455,7 +17102,7 @@ import { exec as exec5 } from "child_process";
|
|
|
16455
17102
|
import { promisify as promisify7 } from "util";
|
|
16456
17103
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16457
17104
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
16458
|
-
import
|
|
17105
|
+
import fs6 from "fs";
|
|
16459
17106
|
import { promises as fsPromises } from "fs";
|
|
16460
17107
|
import path6 from "path";
|
|
16461
17108
|
function isSessionCancelled(sessionId) {
|
|
@@ -16515,6 +17162,20 @@ function createWrappedTools(baseTools) {
|
|
|
16515
17162
|
baseTools.bashTool.execute
|
|
16516
17163
|
);
|
|
16517
17164
|
}
|
|
17165
|
+
if (baseTools.editTool) {
|
|
17166
|
+
wrappedTools.editToolInstance = wrapToolWithEmitter(
|
|
17167
|
+
baseTools.editTool,
|
|
17168
|
+
"edit",
|
|
17169
|
+
baseTools.editTool.execute
|
|
17170
|
+
);
|
|
17171
|
+
}
|
|
17172
|
+
if (baseTools.createTool) {
|
|
17173
|
+
wrappedTools.createToolInstance = wrapToolWithEmitter(
|
|
17174
|
+
baseTools.createTool,
|
|
17175
|
+
"create",
|
|
17176
|
+
baseTools.createTool.execute
|
|
17177
|
+
);
|
|
17178
|
+
}
|
|
16518
17179
|
return wrappedTools;
|
|
16519
17180
|
}
|
|
16520
17181
|
var toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
|
|
@@ -16525,9 +17186,9 @@ var init_probeTool = __esm({
|
|
|
16525
17186
|
init_esm5();
|
|
16526
17187
|
toolCallEmitter = new EventEmitter2();
|
|
16527
17188
|
activeToolExecutions = /* @__PURE__ */ new Map();
|
|
16528
|
-
wrapToolWithEmitter = (
|
|
17189
|
+
wrapToolWithEmitter = (tool4, toolName, baseExecute) => {
|
|
16529
17190
|
return {
|
|
16530
|
-
...
|
|
17191
|
+
...tool4,
|
|
16531
17192
|
// Spread schema, description etc.
|
|
16532
17193
|
execute: async (params) => {
|
|
16533
17194
|
const debug = process.env.DEBUG === "1";
|
|
@@ -16762,8 +17423,10 @@ var init_index = __esm({
|
|
|
16762
17423
|
init_file_lister();
|
|
16763
17424
|
init_system_message();
|
|
16764
17425
|
init_common();
|
|
17426
|
+
init_edit();
|
|
16765
17427
|
init_vercel();
|
|
16766
17428
|
init_bash();
|
|
17429
|
+
init_edit();
|
|
16767
17430
|
init_ProbeAgent();
|
|
16768
17431
|
init_simpleTelemetry();
|
|
16769
17432
|
init_probeTool();
|
|
@@ -16796,10 +17459,22 @@ function extractThinkingContent(xmlString) {
|
|
|
16796
17459
|
return thinkingMatch ? thinkingMatch[1].trim() : null;
|
|
16797
17460
|
}
|
|
16798
17461
|
function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
|
|
16799
|
-
const
|
|
16800
|
-
if (
|
|
16801
|
-
const
|
|
16802
|
-
const
|
|
17462
|
+
const openTagIndex = cleanedXmlString.indexOf("<attempt_completion>");
|
|
17463
|
+
if (openTagIndex !== -1) {
|
|
17464
|
+
const afterOpenTag = cleanedXmlString.substring(openTagIndex + "<attempt_completion>".length);
|
|
17465
|
+
const closeTagIndex = cleanedXmlString.lastIndexOf("</attempt_completion>");
|
|
17466
|
+
let content;
|
|
17467
|
+
let hasClosingTag = false;
|
|
17468
|
+
if (closeTagIndex !== -1 && closeTagIndex >= openTagIndex + "<attempt_completion>".length) {
|
|
17469
|
+
content = cleanedXmlString.substring(
|
|
17470
|
+
openTagIndex + "<attempt_completion>".length,
|
|
17471
|
+
closeTagIndex
|
|
17472
|
+
).trim();
|
|
17473
|
+
hasClosingTag = true;
|
|
17474
|
+
} else {
|
|
17475
|
+
content = afterOpenTag.trim();
|
|
17476
|
+
hasClosingTag = false;
|
|
17477
|
+
}
|
|
16803
17478
|
if (content) {
|
|
16804
17479
|
return {
|
|
16805
17480
|
toolName: "attempt_completion",
|
|
@@ -16845,8 +17520,8 @@ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
|
|
|
16845
17520
|
function hasOtherToolTags(xmlString, validTools = []) {
|
|
16846
17521
|
const defaultTools = ["search", "query", "extract", "listFiles", "searchFiles", "implement", "attempt_completion"];
|
|
16847
17522
|
const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
|
|
16848
|
-
for (const
|
|
16849
|
-
if (
|
|
17523
|
+
for (const tool4 of toolsToCheck) {
|
|
17524
|
+
if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
|
|
16850
17525
|
return true;
|
|
16851
17526
|
}
|
|
16852
17527
|
}
|
|
@@ -16884,6 +17559,10 @@ function createTools(configOptions) {
|
|
|
16884
17559
|
if (configOptions.enableBash) {
|
|
16885
17560
|
tools2.bashTool = bashTool(configOptions);
|
|
16886
17561
|
}
|
|
17562
|
+
if (configOptions.allowEdit) {
|
|
17563
|
+
tools2.editTool = editTool(configOptions);
|
|
17564
|
+
tools2.createTool = createTool(configOptions);
|
|
17565
|
+
}
|
|
16887
17566
|
return tools2;
|
|
16888
17567
|
}
|
|
16889
17568
|
function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
@@ -16984,7 +17663,7 @@ function createMockProvider() {
|
|
|
16984
17663
|
provider: "mock",
|
|
16985
17664
|
// Mock the doGenerate method used by Vercel AI SDK
|
|
16986
17665
|
doGenerate: async ({ messages, tools: tools2 }) => {
|
|
16987
|
-
await new Promise((
|
|
17666
|
+
await new Promise((resolve6) => setTimeout(resolve6, 10));
|
|
16988
17667
|
return {
|
|
16989
17668
|
text: "This is a mock response for testing",
|
|
16990
17669
|
toolCalls: [],
|
|
@@ -28971,16 +29650,6 @@ var init_parser2 = __esm({
|
|
|
28971
29650
|
this.subgraph = this.RULE("subgraph", () => {
|
|
28972
29651
|
this.CONSUME(SubgraphKeyword);
|
|
28973
29652
|
this.OR([
|
|
28974
|
-
{
|
|
28975
|
-
ALT: () => {
|
|
28976
|
-
this.CONSUME(Identifier, { LABEL: "subgraphId" });
|
|
28977
|
-
this.OPTION(() => {
|
|
28978
|
-
this.CONSUME1(SquareOpen);
|
|
28979
|
-
this.SUBRULE(this.nodeContent);
|
|
28980
|
-
this.CONSUME1(SquareClose);
|
|
28981
|
-
});
|
|
28982
|
-
}
|
|
28983
|
-
},
|
|
28984
29653
|
{
|
|
28985
29654
|
ALT: () => {
|
|
28986
29655
|
this.CONSUME(QuotedString, { LABEL: "subgraphTitleQ" });
|
|
@@ -28992,6 +29661,33 @@ var init_parser2 = __esm({
|
|
|
28992
29661
|
this.SUBRULE2(this.nodeContent);
|
|
28993
29662
|
this.CONSUME2(SquareClose);
|
|
28994
29663
|
}
|
|
29664
|
+
},
|
|
29665
|
+
{
|
|
29666
|
+
ALT: () => {
|
|
29667
|
+
this.CONSUME1(Identifier, { LABEL: "subgraphIdOrFirstWord" });
|
|
29668
|
+
this.OPTION(() => {
|
|
29669
|
+
this.OR1([
|
|
29670
|
+
{
|
|
29671
|
+
ALT: () => {
|
|
29672
|
+
this.CONSUME1(SquareOpen);
|
|
29673
|
+
this.SUBRULE(this.nodeContent);
|
|
29674
|
+
this.CONSUME1(SquareClose);
|
|
29675
|
+
}
|
|
29676
|
+
},
|
|
29677
|
+
{
|
|
29678
|
+
ALT: () => {
|
|
29679
|
+
this.AT_LEAST_ONE(() => {
|
|
29680
|
+
this.OR2([
|
|
29681
|
+
{ ALT: () => this.CONSUME2(Identifier) },
|
|
29682
|
+
{ ALT: () => this.CONSUME(Text) },
|
|
29683
|
+
{ ALT: () => this.CONSUME(NumberLiteral) }
|
|
29684
|
+
]);
|
|
29685
|
+
});
|
|
29686
|
+
}
|
|
29687
|
+
}
|
|
29688
|
+
]);
|
|
29689
|
+
});
|
|
29690
|
+
}
|
|
28995
29691
|
}
|
|
28996
29692
|
]);
|
|
28997
29693
|
this.CONSUME(Newline);
|
|
@@ -29595,7 +30291,6 @@ var init_semantics = __esm({
|
|
|
29595
30291
|
const last2 = allChildren[allChildren.length - 1];
|
|
29596
30292
|
const isSlash = (t) => t.image === "/" || t.image === "\\";
|
|
29597
30293
|
if (isSlash(first2) && isSlash(last2)) {
|
|
29598
|
-
continue;
|
|
29599
30294
|
}
|
|
29600
30295
|
}
|
|
29601
30296
|
const opens = ch.RoundOpen || [];
|
|
@@ -30389,16 +31084,19 @@ function mapFlowchartParserError(err, text) {
|
|
|
30389
31084
|
const subgraphIdx = lineStr.indexOf("subgraph");
|
|
30390
31085
|
if (subgraphIdx !== -1) {
|
|
30391
31086
|
const afterSubgraph = lineStr.slice(subgraphIdx + 8).trim();
|
|
30392
|
-
if (afterSubgraph && !afterSubgraph.startsWith('"') && !afterSubgraph.startsWith("'")
|
|
30393
|
-
|
|
30394
|
-
|
|
30395
|
-
|
|
30396
|
-
|
|
30397
|
-
|
|
30398
|
-
|
|
30399
|
-
|
|
30400
|
-
|
|
30401
|
-
|
|
31087
|
+
if (afterSubgraph && !afterSubgraph.startsWith('"') && !afterSubgraph.startsWith("'")) {
|
|
31088
|
+
const hasHazard = /[\[\](){}/:|"'\\]/.test(afterSubgraph);
|
|
31089
|
+
if (hasHazard) {
|
|
31090
|
+
return {
|
|
31091
|
+
line,
|
|
31092
|
+
column,
|
|
31093
|
+
severity: "error",
|
|
31094
|
+
code: "FL-SUBGRAPH-UNQUOTED-TITLE",
|
|
31095
|
+
message: "Subgraph title contains special characters; wrap it in quotes.",
|
|
31096
|
+
hint: 'Example: subgraph "Streams (inside Gateway)"',
|
|
31097
|
+
length: afterSubgraph.length
|
|
31098
|
+
};
|
|
31099
|
+
}
|
|
30402
31100
|
}
|
|
30403
31101
|
}
|
|
30404
31102
|
}
|
|
@@ -31096,11 +31794,11 @@ function validateFlowchart(text, options = {}) {
|
|
|
31096
31794
|
const byLine = /* @__PURE__ */ new Map();
|
|
31097
31795
|
const collect = (arr) => {
|
|
31098
31796
|
for (const e of arr || []) {
|
|
31099
|
-
if (e && e.code === "FL-LABEL-PARENS-UNQUOTED") {
|
|
31797
|
+
if (e && (e.code === "FL-LABEL-PARENS-UNQUOTED" || e.code === "FL-LABEL-AT-IN-UNQUOTED")) {
|
|
31100
31798
|
const ln = e.line ?? 0;
|
|
31101
31799
|
const col = e.column ?? 1;
|
|
31102
31800
|
const list = byLine.get(ln) || [];
|
|
31103
|
-
list.push(col);
|
|
31801
|
+
list.push({ start: col, end: col });
|
|
31104
31802
|
byLine.set(ln, list);
|
|
31105
31803
|
}
|
|
31106
31804
|
}
|
|
@@ -31109,33 +31807,91 @@ function validateFlowchart(text, options = {}) {
|
|
|
31109
31807
|
collect(errs);
|
|
31110
31808
|
const lines2 = text2.split(/\r?\n/);
|
|
31111
31809
|
for (let ii = 0; ii < lines2.length; ii++) {
|
|
31112
|
-
const
|
|
31113
|
-
if (!
|
|
31810
|
+
const raw = lines2[ii] || "";
|
|
31811
|
+
if (!raw.includes("[") || !raw.includes("]"))
|
|
31114
31812
|
continue;
|
|
31115
|
-
let
|
|
31116
|
-
|
|
31117
|
-
|
|
31118
|
-
|
|
31119
|
-
|
|
31120
|
-
const
|
|
31121
|
-
if (
|
|
31122
|
-
|
|
31123
|
-
|
|
31124
|
-
|
|
31125
|
-
|
|
31126
|
-
|
|
31127
|
-
|
|
31128
|
-
|
|
31129
|
-
|
|
31130
|
-
|
|
31131
|
-
|
|
31132
|
-
|
|
31133
|
-
|
|
31134
|
-
|
|
31135
|
-
|
|
31136
|
-
|
|
31813
|
+
let i = 0;
|
|
31814
|
+
const n = raw.length;
|
|
31815
|
+
let inQuote = false;
|
|
31816
|
+
let esc = false;
|
|
31817
|
+
while (i < n) {
|
|
31818
|
+
const ch = raw[i];
|
|
31819
|
+
if (inQuote) {
|
|
31820
|
+
if (esc) {
|
|
31821
|
+
esc = false;
|
|
31822
|
+
} else if (ch === "\\") {
|
|
31823
|
+
esc = true;
|
|
31824
|
+
} else if (ch === '"') {
|
|
31825
|
+
inQuote = false;
|
|
31826
|
+
}
|
|
31827
|
+
i++;
|
|
31828
|
+
continue;
|
|
31829
|
+
}
|
|
31830
|
+
if (ch === '"') {
|
|
31831
|
+
inQuote = true;
|
|
31832
|
+
i++;
|
|
31833
|
+
continue;
|
|
31834
|
+
}
|
|
31835
|
+
if (ch === "[") {
|
|
31836
|
+
let j = i + 1;
|
|
31837
|
+
let inQ = false;
|
|
31838
|
+
let esc2 = false;
|
|
31839
|
+
let depth = 1;
|
|
31840
|
+
while (j < n && depth > 0) {
|
|
31841
|
+
const cj = raw[j];
|
|
31842
|
+
if (inQ) {
|
|
31843
|
+
if (esc2) {
|
|
31844
|
+
esc2 = false;
|
|
31845
|
+
} else if (cj === "\\") {
|
|
31846
|
+
esc2 = true;
|
|
31847
|
+
} else if (cj === '"') {
|
|
31848
|
+
inQ = false;
|
|
31849
|
+
}
|
|
31850
|
+
j++;
|
|
31851
|
+
continue;
|
|
31852
|
+
}
|
|
31853
|
+
if (cj === '"') {
|
|
31854
|
+
inQ = true;
|
|
31855
|
+
j++;
|
|
31856
|
+
continue;
|
|
31857
|
+
}
|
|
31858
|
+
if (cj === "[")
|
|
31859
|
+
depth++;
|
|
31860
|
+
else if (cj === "]")
|
|
31861
|
+
depth--;
|
|
31862
|
+
j++;
|
|
31863
|
+
}
|
|
31864
|
+
if (depth === 0) {
|
|
31865
|
+
const startCol = i + 2;
|
|
31866
|
+
const endCol = j;
|
|
31867
|
+
const seg = raw.slice(i + 1, j - 1);
|
|
31868
|
+
const trimmed = seg.trim();
|
|
31869
|
+
const ln = ii + 1;
|
|
31870
|
+
const lsp = trimmed.slice(0, 1), rsp = trimmed.slice(-1);
|
|
31871
|
+
const isSlashPair = (lsp === "/" || lsp === "\\") && (rsp === "/" || rsp === "\\");
|
|
31872
|
+
const isParenWrapped = lsp === "(" && rsp === ")";
|
|
31873
|
+
const isQuoted = /^"[\s\S]*"$/.test(trimmed);
|
|
31874
|
+
const existing = byLine.get(ln) || [];
|
|
31875
|
+
const covered = existing.some((r) => !(endCol < r.start || startCol > r.end));
|
|
31876
|
+
const hasParens = seg.includes("(") || seg.includes(")");
|
|
31877
|
+
const hasAt = seg.includes("@");
|
|
31878
|
+
if (!covered && !isQuoted && !isParenWrapped && hasParens) {
|
|
31879
|
+
errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-PARENS-UNQUOTED", message: "Parentheses inside an unquoted label are not supported by Mermaid.", hint: 'Wrap the label in quotes, e.g., A["Mark (X)"] \u2014 or replace ( and ) with HTML entities: ( and ).' });
|
|
31880
|
+
existing.push({ start: startCol, end: endCol });
|
|
31881
|
+
byLine.set(ln, existing);
|
|
31882
|
+
}
|
|
31883
|
+
if (!covered && !isQuoted && !isSlashPair && hasAt) {
|
|
31884
|
+
errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-AT-IN-UNQUOTED", message: "'@' inside an unquoted label can be misparsed by Mermaid.", hint: 'Wrap the label in quotes, e.g., B["@probelabs/probe v0.6.0-rc149"]' });
|
|
31885
|
+
existing.push({ start: startCol, end: endCol });
|
|
31886
|
+
byLine.set(ln, existing);
|
|
31887
|
+
}
|
|
31888
|
+
i = j;
|
|
31889
|
+
continue;
|
|
31890
|
+
} else {
|
|
31891
|
+
break;
|
|
31892
|
+
}
|
|
31137
31893
|
}
|
|
31138
|
-
|
|
31894
|
+
i++;
|
|
31139
31895
|
}
|
|
31140
31896
|
}
|
|
31141
31897
|
}
|
|
@@ -42621,7 +43377,7 @@ var require_bk = __commonJS({
|
|
|
42621
43377
|
return xs;
|
|
42622
43378
|
}
|
|
42623
43379
|
function buildBlockGraph(g, layering, root2, reverseSep) {
|
|
42624
|
-
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn =
|
|
43380
|
+
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn = sep3(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
|
|
42625
43381
|
_.forEach(layering, function(layer) {
|
|
42626
43382
|
var u;
|
|
42627
43383
|
_.forEach(layer, function(v) {
|
|
@@ -42711,7 +43467,7 @@ var require_bk = __commonJS({
|
|
|
42711
43467
|
alignCoordinates(xss, smallestWidth);
|
|
42712
43468
|
return balance(xss, g.graph().align);
|
|
42713
43469
|
}
|
|
42714
|
-
function
|
|
43470
|
+
function sep3(nodeSep, edgeSep, reverseSep) {
|
|
42715
43471
|
return function(g, v, w) {
|
|
42716
43472
|
var vLabel = g.node(v);
|
|
42717
43473
|
var wLabel = g.node(w);
|
|
@@ -50005,7 +50761,7 @@ var require_compile = __commonJS({
|
|
|
50005
50761
|
const schOrFunc = root2.refs[ref];
|
|
50006
50762
|
if (schOrFunc)
|
|
50007
50763
|
return schOrFunc;
|
|
50008
|
-
let _sch =
|
|
50764
|
+
let _sch = resolve6.call(this, root2, ref);
|
|
50009
50765
|
if (_sch === void 0) {
|
|
50010
50766
|
const schema = (_a = root2.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
50011
50767
|
const { schemaId } = this.opts;
|
|
@@ -50032,7 +50788,7 @@ var require_compile = __commonJS({
|
|
|
50032
50788
|
function sameSchemaEnv(s1, s2) {
|
|
50033
50789
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
50034
50790
|
}
|
|
50035
|
-
function
|
|
50791
|
+
function resolve6(root2, ref) {
|
|
50036
50792
|
let sch;
|
|
50037
50793
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
50038
50794
|
ref = sch;
|
|
@@ -50607,7 +51363,7 @@ var require_fast_uri = __commonJS({
|
|
|
50607
51363
|
}
|
|
50608
51364
|
return uri;
|
|
50609
51365
|
}
|
|
50610
|
-
function
|
|
51366
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
50611
51367
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
50612
51368
|
const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
50613
51369
|
schemelessOptions.skipEscape = true;
|
|
@@ -50834,7 +51590,7 @@ var require_fast_uri = __commonJS({
|
|
|
50834
51590
|
var fastUri = {
|
|
50835
51591
|
SCHEMES,
|
|
50836
51592
|
normalize: normalize2,
|
|
50837
|
-
resolve:
|
|
51593
|
+
resolve: resolve6,
|
|
50838
51594
|
resolveComponent,
|
|
50839
51595
|
equal,
|
|
50840
51596
|
serialize,
|
|
@@ -54852,15 +55608,15 @@ Provide only the corrected Mermaid diagram within a mermaid code block. Do not a
|
|
|
54852
55608
|
});
|
|
54853
55609
|
|
|
54854
55610
|
// src/agent/mcp/config.js
|
|
54855
|
-
import { readFileSync, existsSync as
|
|
54856
|
-
import { join as join2, dirname as
|
|
55611
|
+
import { readFileSync, existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync } from "fs";
|
|
55612
|
+
import { join as join2, dirname as dirname3 } from "path";
|
|
54857
55613
|
import { homedir } from "os";
|
|
54858
55614
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
54859
55615
|
function loadMCPConfigurationFromPath(configPath) {
|
|
54860
55616
|
if (!configPath) {
|
|
54861
55617
|
throw new Error("Config path is required");
|
|
54862
55618
|
}
|
|
54863
|
-
if (!
|
|
55619
|
+
if (!existsSync4(configPath)) {
|
|
54864
55620
|
throw new Error(`MCP configuration file not found: ${configPath}`);
|
|
54865
55621
|
}
|
|
54866
55622
|
try {
|
|
@@ -54889,7 +55645,7 @@ function loadMCPConfiguration() {
|
|
|
54889
55645
|
].filter(Boolean);
|
|
54890
55646
|
let config = null;
|
|
54891
55647
|
for (const configPath of configPaths) {
|
|
54892
|
-
if (
|
|
55648
|
+
if (existsSync4(configPath)) {
|
|
54893
55649
|
try {
|
|
54894
55650
|
const content = readFileSync(configPath, "utf8");
|
|
54895
55651
|
config = JSON.parse(content);
|
|
@@ -54992,7 +55748,7 @@ var init_config = __esm({
|
|
|
54992
55748
|
"src/agent/mcp/config.js"() {
|
|
54993
55749
|
"use strict";
|
|
54994
55750
|
__filename4 = fileURLToPath6(import.meta.url);
|
|
54995
|
-
__dirname4 =
|
|
55751
|
+
__dirname4 = dirname3(__filename4);
|
|
54996
55752
|
DEFAULT_CONFIG = {
|
|
54997
55753
|
mcpServers: {
|
|
54998
55754
|
// Example probe server configuration
|
|
@@ -55181,12 +55937,12 @@ var init_client = __esm({
|
|
|
55181
55937
|
const toolsResponse = await client.listTools();
|
|
55182
55938
|
const toolCount = toolsResponse?.tools?.length || 0;
|
|
55183
55939
|
if (toolsResponse && toolsResponse.tools) {
|
|
55184
|
-
for (const
|
|
55185
|
-
const qualifiedName = `${name}_${
|
|
55940
|
+
for (const tool4 of toolsResponse.tools) {
|
|
55941
|
+
const qualifiedName = `${name}_${tool4.name}`;
|
|
55186
55942
|
this.tools.set(qualifiedName, {
|
|
55187
|
-
...
|
|
55943
|
+
...tool4,
|
|
55188
55944
|
serverName: name,
|
|
55189
|
-
originalName:
|
|
55945
|
+
originalName: tool4.name
|
|
55190
55946
|
});
|
|
55191
55947
|
if (this.debug) {
|
|
55192
55948
|
console.error(`[MCP DEBUG] Registered tool: ${qualifiedName}`);
|
|
@@ -55209,13 +55965,13 @@ var init_client = __esm({
|
|
|
55209
55965
|
* @param {Object} args - Tool arguments
|
|
55210
55966
|
*/
|
|
55211
55967
|
async callTool(toolName, args) {
|
|
55212
|
-
const
|
|
55213
|
-
if (!
|
|
55968
|
+
const tool4 = this.tools.get(toolName);
|
|
55969
|
+
if (!tool4) {
|
|
55214
55970
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
55215
55971
|
}
|
|
55216
|
-
const clientInfo = this.clients.get(
|
|
55972
|
+
const clientInfo = this.clients.get(tool4.serverName);
|
|
55217
55973
|
if (!clientInfo) {
|
|
55218
|
-
throw new Error(`Server ${
|
|
55974
|
+
throw new Error(`Server ${tool4.serverName} not connected`);
|
|
55219
55975
|
}
|
|
55220
55976
|
try {
|
|
55221
55977
|
if (this.debug) {
|
|
@@ -55229,7 +55985,7 @@ var init_client = __esm({
|
|
|
55229
55985
|
});
|
|
55230
55986
|
const result = await Promise.race([
|
|
55231
55987
|
clientInfo.client.callTool({
|
|
55232
|
-
name:
|
|
55988
|
+
name: tool4.originalName,
|
|
55233
55989
|
arguments: args
|
|
55234
55990
|
}),
|
|
55235
55991
|
timeoutPromise
|
|
@@ -55252,11 +56008,11 @@ var init_client = __esm({
|
|
|
55252
56008
|
*/
|
|
55253
56009
|
getTools() {
|
|
55254
56010
|
const tools2 = {};
|
|
55255
|
-
for (const [name,
|
|
56011
|
+
for (const [name, tool4] of this.tools.entries()) {
|
|
55256
56012
|
tools2[name] = {
|
|
55257
|
-
description:
|
|
55258
|
-
inputSchema:
|
|
55259
|
-
serverName:
|
|
56013
|
+
description: tool4.description,
|
|
56014
|
+
inputSchema: tool4.inputSchema,
|
|
56015
|
+
serverName: tool4.serverName
|
|
55260
56016
|
};
|
|
55261
56017
|
}
|
|
55262
56018
|
return tools2;
|
|
@@ -55267,10 +56023,10 @@ var init_client = __esm({
|
|
|
55267
56023
|
*/
|
|
55268
56024
|
getVercelTools() {
|
|
55269
56025
|
const tools2 = {};
|
|
55270
|
-
for (const [name,
|
|
56026
|
+
for (const [name, tool4] of this.tools.entries()) {
|
|
55271
56027
|
tools2[name] = {
|
|
55272
|
-
description:
|
|
55273
|
-
inputSchema:
|
|
56028
|
+
description: tool4.description,
|
|
56029
|
+
inputSchema: tool4.inputSchema,
|
|
55274
56030
|
execute: async (args) => {
|
|
55275
56031
|
const result = await this.callTool(name, args);
|
|
55276
56032
|
if (result.content && result.content[0]) {
|
|
@@ -55319,9 +56075,9 @@ var init_client = __esm({
|
|
|
55319
56075
|
});
|
|
55320
56076
|
|
|
55321
56077
|
// src/agent/mcp/xmlBridge.js
|
|
55322
|
-
function mcpToolToXmlDefinition(name,
|
|
55323
|
-
const description =
|
|
55324
|
-
const inputSchema =
|
|
56078
|
+
function mcpToolToXmlDefinition(name, tool4) {
|
|
56079
|
+
const description = tool4.description || "MCP tool";
|
|
56080
|
+
const inputSchema = tool4.inputSchema || tool4.parameters || {};
|
|
55325
56081
|
let paramDocs = "";
|
|
55326
56082
|
if (inputSchema.properties) {
|
|
55327
56083
|
paramDocs = "\n\nParameters (provide as JSON object):";
|
|
@@ -55500,8 +56256,8 @@ var init_xmlBridge = __esm({
|
|
|
55500
56256
|
const vercelTools = this.mcpManager.getVercelTools();
|
|
55501
56257
|
this.mcpTools = vercelTools;
|
|
55502
56258
|
const toolCount = Object.keys(vercelTools).length;
|
|
55503
|
-
for (const [name,
|
|
55504
|
-
this.xmlDefinitions[name] = mcpToolToXmlDefinition(name,
|
|
56259
|
+
for (const [name, tool4] of Object.entries(vercelTools)) {
|
|
56260
|
+
this.xmlDefinitions[name] = mcpToolToXmlDefinition(name, tool4);
|
|
55505
56261
|
}
|
|
55506
56262
|
if (toolCount === 0) {
|
|
55507
56263
|
console.error("[MCP INFO] MCP initialization complete: 0 tools loaded");
|
|
@@ -55548,14 +56304,14 @@ var init_xmlBridge = __esm({
|
|
|
55548
56304
|
console.error(`[MCP DEBUG] Executing MCP tool: ${toolName}`);
|
|
55549
56305
|
console.error(`[MCP DEBUG] Parameters:`, JSON.stringify(params, null, 2));
|
|
55550
56306
|
}
|
|
55551
|
-
const
|
|
55552
|
-
if (!
|
|
56307
|
+
const tool4 = this.mcpTools[toolName];
|
|
56308
|
+
if (!tool4) {
|
|
55553
56309
|
console.error(`[MCP ERROR] Unknown MCP tool: ${toolName}`);
|
|
55554
56310
|
console.error(`[MCP ERROR] Available tools: ${this.getToolNames().join(", ")}`);
|
|
55555
56311
|
throw new Error(`Unknown MCP tool: ${toolName}`);
|
|
55556
56312
|
}
|
|
55557
56313
|
try {
|
|
55558
|
-
const result = await
|
|
56314
|
+
const result = await tool4.execute(params);
|
|
55559
56315
|
if (this.debug) {
|
|
55560
56316
|
console.error(`[MCP DEBUG] Tool ${toolName} executed successfully`);
|
|
55561
56317
|
}
|
|
@@ -55609,22 +56365,800 @@ var init_mcp = __esm({
|
|
|
55609
56365
|
}
|
|
55610
56366
|
});
|
|
55611
56367
|
|
|
56368
|
+
// src/agent/RetryManager.js
|
|
56369
|
+
function isRetryableError(error, retryableErrors = DEFAULT_RETRYABLE_ERRORS) {
|
|
56370
|
+
if (!error) return false;
|
|
56371
|
+
const errorString = error.toString().toLowerCase();
|
|
56372
|
+
const errorMessage = (error.message || "").toLowerCase();
|
|
56373
|
+
const errorCode = (error.code || "").toLowerCase();
|
|
56374
|
+
const errorType = (error.type || "").toLowerCase();
|
|
56375
|
+
const statusCode = error.statusCode || error.status;
|
|
56376
|
+
for (const pattern of retryableErrors) {
|
|
56377
|
+
const lowerPattern = pattern.toLowerCase();
|
|
56378
|
+
if (errorString.includes(lowerPattern) || errorMessage.includes(lowerPattern) || errorCode.includes(lowerPattern) || errorType.includes(lowerPattern) || statusCode?.toString() === pattern) {
|
|
56379
|
+
return true;
|
|
56380
|
+
}
|
|
56381
|
+
}
|
|
56382
|
+
return false;
|
|
56383
|
+
}
|
|
56384
|
+
function extractErrorInfo(error) {
|
|
56385
|
+
return {
|
|
56386
|
+
message: error.message || error.toString(),
|
|
56387
|
+
type: error.type || error.constructor.name,
|
|
56388
|
+
code: error.code,
|
|
56389
|
+
statusCode: error.statusCode || error.status,
|
|
56390
|
+
provider: error.provider,
|
|
56391
|
+
isRetryable: isRetryableError(error)
|
|
56392
|
+
};
|
|
56393
|
+
}
|
|
56394
|
+
function sleep(ms) {
|
|
56395
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
56396
|
+
}
|
|
56397
|
+
var DEFAULT_RETRYABLE_ERRORS, RetryManager;
|
|
56398
|
+
var init_RetryManager = __esm({
|
|
56399
|
+
"src/agent/RetryManager.js"() {
|
|
56400
|
+
"use strict";
|
|
56401
|
+
DEFAULT_RETRYABLE_ERRORS = [
|
|
56402
|
+
"Overloaded",
|
|
56403
|
+
"overloaded",
|
|
56404
|
+
"rate_limit",
|
|
56405
|
+
"rate limit",
|
|
56406
|
+
"429",
|
|
56407
|
+
"500",
|
|
56408
|
+
"502",
|
|
56409
|
+
"503",
|
|
56410
|
+
"504",
|
|
56411
|
+
"timeout",
|
|
56412
|
+
"ECONNRESET",
|
|
56413
|
+
"ETIMEDOUT",
|
|
56414
|
+
"ENOTFOUND",
|
|
56415
|
+
"api_error"
|
|
56416
|
+
];
|
|
56417
|
+
RetryManager = class {
|
|
56418
|
+
/**
|
|
56419
|
+
* Create a new RetryManager
|
|
56420
|
+
* @param {Object} options - Configuration options
|
|
56421
|
+
* @param {number} [options.maxRetries=3] - Maximum retry attempts
|
|
56422
|
+
* @param {number} [options.initialDelay=1000] - Initial delay in ms (1 second)
|
|
56423
|
+
* @param {number} [options.maxDelay=30000] - Maximum delay in ms (30 seconds)
|
|
56424
|
+
* @param {number} [options.backoffFactor=2] - Exponential backoff multiplier
|
|
56425
|
+
* @param {Array<string>} [options.retryableErrors] - List of retryable error patterns
|
|
56426
|
+
* @param {boolean} [options.debug=false] - Enable debug logging
|
|
56427
|
+
*/
|
|
56428
|
+
constructor(options = {}) {
|
|
56429
|
+
this.maxRetries = this._validateNumber(options.maxRetries, 3, "maxRetries", 0, 100);
|
|
56430
|
+
this.initialDelay = this._validateNumber(options.initialDelay, 1e3, "initialDelay", 0, 6e4);
|
|
56431
|
+
this.maxDelay = this._validateNumber(options.maxDelay, 3e4, "maxDelay", 0, 3e5);
|
|
56432
|
+
this.backoffFactor = this._validateNumber(options.backoffFactor, 2, "backoffFactor", 1, 10);
|
|
56433
|
+
this.retryableErrors = options.retryableErrors || DEFAULT_RETRYABLE_ERRORS;
|
|
56434
|
+
this.debug = options.debug ?? false;
|
|
56435
|
+
this.jitter = options.jitter ?? true;
|
|
56436
|
+
if (this.maxDelay < this.initialDelay) {
|
|
56437
|
+
throw new Error("maxDelay must be greater than or equal to initialDelay");
|
|
56438
|
+
}
|
|
56439
|
+
this.stats = {
|
|
56440
|
+
totalAttempts: 0,
|
|
56441
|
+
totalRetries: 0,
|
|
56442
|
+
successfulRetries: 0,
|
|
56443
|
+
failedRetries: 0
|
|
56444
|
+
};
|
|
56445
|
+
}
|
|
56446
|
+
/**
|
|
56447
|
+
* Validate a numeric parameter
|
|
56448
|
+
* @param {*} value - Value to validate
|
|
56449
|
+
* @param {number} defaultValue - Default if undefined
|
|
56450
|
+
* @param {string} name - Parameter name for error messages
|
|
56451
|
+
* @param {number} min - Minimum allowed value
|
|
56452
|
+
* @param {number} max - Maximum allowed value
|
|
56453
|
+
* @returns {number} - Validated number
|
|
56454
|
+
* @private
|
|
56455
|
+
*/
|
|
56456
|
+
_validateNumber(value, defaultValue, name, min, max) {
|
|
56457
|
+
if (value === void 0 || value === null) {
|
|
56458
|
+
return defaultValue;
|
|
56459
|
+
}
|
|
56460
|
+
const num = Number(value);
|
|
56461
|
+
if (isNaN(num)) {
|
|
56462
|
+
throw new Error(`${name} must be a number, got: ${value}`);
|
|
56463
|
+
}
|
|
56464
|
+
if (num < min || num > max) {
|
|
56465
|
+
throw new Error(`${name} must be between ${min} and ${max}, got: ${num}`);
|
|
56466
|
+
}
|
|
56467
|
+
return num;
|
|
56468
|
+
}
|
|
56469
|
+
/**
|
|
56470
|
+
* Execute a function with retry logic
|
|
56471
|
+
* @param {Function} fn - Async function to execute
|
|
56472
|
+
* @param {Object} [context={}] - Context information for logging
|
|
56473
|
+
* @param {AbortSignal} [context.signal] - Optional abort signal for cancellation
|
|
56474
|
+
* @returns {Promise<*>} - Result from the function
|
|
56475
|
+
* @throws {Error} - If all retries are exhausted or operation is aborted
|
|
56476
|
+
*/
|
|
56477
|
+
async executeWithRetry(fn, context = {}) {
|
|
56478
|
+
let lastError = null;
|
|
56479
|
+
let currentDelay = this.initialDelay;
|
|
56480
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
56481
|
+
if (context.signal?.aborted) {
|
|
56482
|
+
const abortError = new Error("Operation aborted");
|
|
56483
|
+
abortError.name = "AbortError";
|
|
56484
|
+
throw abortError;
|
|
56485
|
+
}
|
|
56486
|
+
this.stats.totalAttempts++;
|
|
56487
|
+
try {
|
|
56488
|
+
if (this.debug && attempt > 0) {
|
|
56489
|
+
console.log(`[RetryManager] Retry attempt ${attempt}/${this.maxRetries}`, context);
|
|
56490
|
+
}
|
|
56491
|
+
const result = await fn();
|
|
56492
|
+
if (attempt > 0) {
|
|
56493
|
+
this.stats.successfulRetries++;
|
|
56494
|
+
if (this.debug) {
|
|
56495
|
+
console.log(`[RetryManager] \u2705 Retry successful on attempt ${attempt + 1}`, context);
|
|
56496
|
+
}
|
|
56497
|
+
}
|
|
56498
|
+
return result;
|
|
56499
|
+
} catch (error) {
|
|
56500
|
+
lastError = error;
|
|
56501
|
+
const errorInfo = extractErrorInfo(error);
|
|
56502
|
+
const shouldRetry = isRetryableError(error, this.retryableErrors);
|
|
56503
|
+
const hasRetriesLeft = attempt < this.maxRetries;
|
|
56504
|
+
if (this.debug) {
|
|
56505
|
+
console.log(`[RetryManager] \u274C Attempt ${attempt + 1}/${this.maxRetries + 1} failed:`, {
|
|
56506
|
+
...context,
|
|
56507
|
+
error: errorInfo,
|
|
56508
|
+
shouldRetry,
|
|
56509
|
+
hasRetriesLeft
|
|
56510
|
+
});
|
|
56511
|
+
}
|
|
56512
|
+
if (!shouldRetry) {
|
|
56513
|
+
if (this.debug) {
|
|
56514
|
+
console.log(`[RetryManager] Error is not retryable, failing immediately`, errorInfo);
|
|
56515
|
+
}
|
|
56516
|
+
throw error;
|
|
56517
|
+
}
|
|
56518
|
+
if (!hasRetriesLeft) {
|
|
56519
|
+
this.stats.failedRetries++;
|
|
56520
|
+
if (this.debug) {
|
|
56521
|
+
console.log(`[RetryManager] Max retries (${this.maxRetries}) exhausted`, context);
|
|
56522
|
+
}
|
|
56523
|
+
throw error;
|
|
56524
|
+
}
|
|
56525
|
+
this.stats.totalRetries++;
|
|
56526
|
+
let delayWithJitter = currentDelay;
|
|
56527
|
+
if (this.jitter) {
|
|
56528
|
+
const jitterAmount = currentDelay * 0.25;
|
|
56529
|
+
delayWithJitter = currentDelay + (Math.random() * jitterAmount * 2 - jitterAmount);
|
|
56530
|
+
}
|
|
56531
|
+
if (this.debug) {
|
|
56532
|
+
console.log(`[RetryManager] Waiting ${Math.round(delayWithJitter)}ms before retry...`);
|
|
56533
|
+
}
|
|
56534
|
+
await sleep(delayWithJitter);
|
|
56535
|
+
currentDelay = Math.min(currentDelay * this.backoffFactor, this.maxDelay);
|
|
56536
|
+
}
|
|
56537
|
+
}
|
|
56538
|
+
throw lastError;
|
|
56539
|
+
}
|
|
56540
|
+
/**
|
|
56541
|
+
* Check if an error is retryable
|
|
56542
|
+
* @param {Error} error - The error to check
|
|
56543
|
+
* @returns {boolean} - True if error should be retried
|
|
56544
|
+
*/
|
|
56545
|
+
isRetryable(error) {
|
|
56546
|
+
return isRetryableError(error, this.retryableErrors);
|
|
56547
|
+
}
|
|
56548
|
+
/**
|
|
56549
|
+
* Get retry statistics
|
|
56550
|
+
* @returns {Object} - Statistics object
|
|
56551
|
+
*/
|
|
56552
|
+
getStats() {
|
|
56553
|
+
return { ...this.stats };
|
|
56554
|
+
}
|
|
56555
|
+
/**
|
|
56556
|
+
* Reset statistics
|
|
56557
|
+
*/
|
|
56558
|
+
resetStats() {
|
|
56559
|
+
this.stats = {
|
|
56560
|
+
totalAttempts: 0,
|
|
56561
|
+
totalRetries: 0,
|
|
56562
|
+
successfulRetries: 0,
|
|
56563
|
+
failedRetries: 0
|
|
56564
|
+
};
|
|
56565
|
+
}
|
|
56566
|
+
};
|
|
56567
|
+
}
|
|
56568
|
+
});
|
|
56569
|
+
|
|
56570
|
+
// src/agent/FallbackManager.js
|
|
56571
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
56572
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
56573
|
+
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
56574
|
+
import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
|
|
56575
|
+
function createFallbackManagerFromEnv(debug = false) {
|
|
56576
|
+
const fallbackProvidersEnv = process.env.FALLBACK_PROVIDERS;
|
|
56577
|
+
const fallbackModelsEnv = process.env.FALLBACK_MODELS;
|
|
56578
|
+
if (!fallbackProvidersEnv && !fallbackModelsEnv) {
|
|
56579
|
+
return null;
|
|
56580
|
+
}
|
|
56581
|
+
let providers = [];
|
|
56582
|
+
let models = [];
|
|
56583
|
+
let strategy = FALLBACK_STRATEGIES.ANY;
|
|
56584
|
+
if (fallbackProvidersEnv) {
|
|
56585
|
+
try {
|
|
56586
|
+
if (typeof fallbackProvidersEnv !== "string" || fallbackProvidersEnv.length > 1e4) {
|
|
56587
|
+
console.error("[FallbackManager] FALLBACK_PROVIDERS must be a valid JSON string under 10KB");
|
|
56588
|
+
return null;
|
|
56589
|
+
}
|
|
56590
|
+
const parsed = JSON.parse(fallbackProvidersEnv);
|
|
56591
|
+
if (!Array.isArray(parsed)) {
|
|
56592
|
+
console.error("[FallbackManager] FALLBACK_PROVIDERS must be a JSON array");
|
|
56593
|
+
return null;
|
|
56594
|
+
}
|
|
56595
|
+
providers = parsed;
|
|
56596
|
+
strategy = FALLBACK_STRATEGIES.CUSTOM;
|
|
56597
|
+
} catch (error) {
|
|
56598
|
+
console.error("[FallbackManager] Failed to parse FALLBACK_PROVIDERS:", error.message);
|
|
56599
|
+
return null;
|
|
56600
|
+
}
|
|
56601
|
+
}
|
|
56602
|
+
if (fallbackModelsEnv) {
|
|
56603
|
+
try {
|
|
56604
|
+
if (typeof fallbackModelsEnv !== "string" || fallbackModelsEnv.length > 1e4) {
|
|
56605
|
+
console.error("[FallbackManager] FALLBACK_MODELS must be a valid JSON string under 10KB");
|
|
56606
|
+
return null;
|
|
56607
|
+
}
|
|
56608
|
+
const parsed = JSON.parse(fallbackModelsEnv);
|
|
56609
|
+
if (!Array.isArray(parsed)) {
|
|
56610
|
+
console.error("[FallbackManager] FALLBACK_MODELS must be a JSON array");
|
|
56611
|
+
return null;
|
|
56612
|
+
}
|
|
56613
|
+
models = parsed;
|
|
56614
|
+
strategy = FALLBACK_STRATEGIES.SAME_PROVIDER;
|
|
56615
|
+
} catch (error) {
|
|
56616
|
+
console.error("[FallbackManager] Failed to parse FALLBACK_MODELS:", error.message);
|
|
56617
|
+
return null;
|
|
56618
|
+
}
|
|
56619
|
+
}
|
|
56620
|
+
const maxTotalAttempts = process.env.FALLBACK_MAX_TOTAL_ATTEMPTS ? (() => {
|
|
56621
|
+
const val = parseInt(process.env.FALLBACK_MAX_TOTAL_ATTEMPTS, 10);
|
|
56622
|
+
if (isNaN(val) || val < 1 || val > 100) {
|
|
56623
|
+
console.warn("[FallbackManager] FALLBACK_MAX_TOTAL_ATTEMPTS must be between 1 and 100, using default: 10");
|
|
56624
|
+
return 10;
|
|
56625
|
+
}
|
|
56626
|
+
return val;
|
|
56627
|
+
})() : 10;
|
|
56628
|
+
return new FallbackManager({
|
|
56629
|
+
strategy,
|
|
56630
|
+
providers,
|
|
56631
|
+
models,
|
|
56632
|
+
maxTotalAttempts,
|
|
56633
|
+
debug
|
|
56634
|
+
});
|
|
56635
|
+
}
|
|
56636
|
+
function buildFallbackProvidersFromEnv(options = {}) {
|
|
56637
|
+
const providers = [];
|
|
56638
|
+
const anthropicApiKey = process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN;
|
|
56639
|
+
const openaiApiKey = process.env.OPENAI_API_KEY;
|
|
56640
|
+
const googleApiKey = process.env.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GOOGLE_API_KEY;
|
|
56641
|
+
const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID;
|
|
56642
|
+
const awsSecretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
|
|
56643
|
+
const awsRegion = process.env.AWS_REGION;
|
|
56644
|
+
const awsApiKey = process.env.AWS_BEDROCK_API_KEY;
|
|
56645
|
+
const llmBaseUrl = process.env.LLM_BASE_URL;
|
|
56646
|
+
const anthropicApiUrl = process.env.ANTHROPIC_API_URL || process.env.ANTHROPIC_BASE_URL || llmBaseUrl;
|
|
56647
|
+
const openaiApiUrl = process.env.OPENAI_API_URL || llmBaseUrl;
|
|
56648
|
+
const googleApiUrl = process.env.GOOGLE_API_URL || llmBaseUrl;
|
|
56649
|
+
const awsBedrockBaseUrl = process.env.AWS_BEDROCK_BASE_URL || llmBaseUrl;
|
|
56650
|
+
const primaryProvider = options.primaryProvider?.toLowerCase();
|
|
56651
|
+
const primaryModel = options.primaryModel;
|
|
56652
|
+
if (primaryProvider === "anthropic" && anthropicApiKey) {
|
|
56653
|
+
providers.push({
|
|
56654
|
+
provider: "anthropic",
|
|
56655
|
+
apiKey: anthropicApiKey,
|
|
56656
|
+
...anthropicApiUrl && { baseURL: anthropicApiUrl },
|
|
56657
|
+
...primaryModel && { model: primaryModel }
|
|
56658
|
+
});
|
|
56659
|
+
} else if (primaryProvider === "openai" && openaiApiKey) {
|
|
56660
|
+
providers.push({
|
|
56661
|
+
provider: "openai",
|
|
56662
|
+
apiKey: openaiApiKey,
|
|
56663
|
+
...openaiApiUrl && { baseURL: openaiApiUrl },
|
|
56664
|
+
...primaryModel && { model: primaryModel }
|
|
56665
|
+
});
|
|
56666
|
+
} else if (primaryProvider === "google" && googleApiKey) {
|
|
56667
|
+
providers.push({
|
|
56668
|
+
provider: "google",
|
|
56669
|
+
apiKey: googleApiKey,
|
|
56670
|
+
...googleApiUrl && { baseURL: googleApiUrl },
|
|
56671
|
+
...primaryModel && { model: primaryModel }
|
|
56672
|
+
});
|
|
56673
|
+
} else if (primaryProvider === "bedrock" && (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey)) {
|
|
56674
|
+
const config = { provider: "bedrock" };
|
|
56675
|
+
if (awsApiKey) {
|
|
56676
|
+
config.apiKey = awsApiKey;
|
|
56677
|
+
} else {
|
|
56678
|
+
config.accessKeyId = awsAccessKeyId;
|
|
56679
|
+
config.secretAccessKey = awsSecretAccessKey;
|
|
56680
|
+
config.region = awsRegion;
|
|
56681
|
+
if (process.env.AWS_SESSION_TOKEN) {
|
|
56682
|
+
config.sessionToken = process.env.AWS_SESSION_TOKEN;
|
|
56683
|
+
}
|
|
56684
|
+
}
|
|
56685
|
+
if (awsBedrockBaseUrl) config.baseURL = awsBedrockBaseUrl;
|
|
56686
|
+
if (primaryModel) config.model = primaryModel;
|
|
56687
|
+
providers.push(config);
|
|
56688
|
+
}
|
|
56689
|
+
if (anthropicApiKey && primaryProvider !== "anthropic") {
|
|
56690
|
+
providers.push({
|
|
56691
|
+
provider: "anthropic",
|
|
56692
|
+
apiKey: anthropicApiKey,
|
|
56693
|
+
...anthropicApiUrl && { baseURL: anthropicApiUrl }
|
|
56694
|
+
});
|
|
56695
|
+
}
|
|
56696
|
+
if (openaiApiKey && primaryProvider !== "openai") {
|
|
56697
|
+
providers.push({
|
|
56698
|
+
provider: "openai",
|
|
56699
|
+
apiKey: openaiApiKey,
|
|
56700
|
+
...openaiApiUrl && { baseURL: openaiApiUrl }
|
|
56701
|
+
});
|
|
56702
|
+
}
|
|
56703
|
+
if (googleApiKey && primaryProvider !== "google") {
|
|
56704
|
+
providers.push({
|
|
56705
|
+
provider: "google",
|
|
56706
|
+
apiKey: googleApiKey,
|
|
56707
|
+
...googleApiUrl && { baseURL: googleApiUrl }
|
|
56708
|
+
});
|
|
56709
|
+
}
|
|
56710
|
+
if ((awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey) && primaryProvider !== "bedrock") {
|
|
56711
|
+
const config = { provider: "bedrock" };
|
|
56712
|
+
if (awsApiKey) {
|
|
56713
|
+
config.apiKey = awsApiKey;
|
|
56714
|
+
} else {
|
|
56715
|
+
config.accessKeyId = awsAccessKeyId;
|
|
56716
|
+
config.secretAccessKey = awsSecretAccessKey;
|
|
56717
|
+
config.region = awsRegion;
|
|
56718
|
+
if (process.env.AWS_SESSION_TOKEN) {
|
|
56719
|
+
config.sessionToken = process.env.AWS_SESSION_TOKEN;
|
|
56720
|
+
}
|
|
56721
|
+
}
|
|
56722
|
+
if (awsBedrockBaseUrl) config.baseURL = awsBedrockBaseUrl;
|
|
56723
|
+
providers.push(config);
|
|
56724
|
+
}
|
|
56725
|
+
return providers;
|
|
56726
|
+
}
|
|
56727
|
+
var FALLBACK_STRATEGIES, DEFAULT_MODELS, FallbackManager;
|
|
56728
|
+
var init_FallbackManager = __esm({
|
|
56729
|
+
"src/agent/FallbackManager.js"() {
|
|
56730
|
+
"use strict";
|
|
56731
|
+
FALLBACK_STRATEGIES = {
|
|
56732
|
+
SAME_MODEL: "same-model",
|
|
56733
|
+
// Try same model on different providers
|
|
56734
|
+
SAME_PROVIDER: "same-provider",
|
|
56735
|
+
// Try different models on same provider
|
|
56736
|
+
ANY: "any",
|
|
56737
|
+
// Try any available provider/model
|
|
56738
|
+
CUSTOM: "custom"
|
|
56739
|
+
// Use custom provider list
|
|
56740
|
+
};
|
|
56741
|
+
DEFAULT_MODELS = {
|
|
56742
|
+
anthropic: "claude-sonnet-4-5-20250929",
|
|
56743
|
+
openai: "gpt-4o",
|
|
56744
|
+
google: "gemini-2.0-flash-exp",
|
|
56745
|
+
bedrock: "anthropic.claude-sonnet-4-20250514-v1:0"
|
|
56746
|
+
};
|
|
56747
|
+
FallbackManager = class {
|
|
56748
|
+
/**
|
|
56749
|
+
* Create a new FallbackManager
|
|
56750
|
+
* @param {Object} options - Configuration options
|
|
56751
|
+
* @param {string} [options.strategy='any'] - Fallback strategy
|
|
56752
|
+
* @param {Array<string>} [options.models] - List of models for same-provider fallback
|
|
56753
|
+
* @param {Array<ProviderConfig>} [options.providers] - List of provider configurations
|
|
56754
|
+
* @param {boolean} [options.stopOnSuccess=true] - Stop on first success
|
|
56755
|
+
* @param {boolean} [options.continueOnNonRetryableError=false] - Continue to fallback on non-retryable errors
|
|
56756
|
+
* @param {number} [options.maxTotalAttempts=10] - Maximum total attempts across all providers
|
|
56757
|
+
* @param {boolean} [options.debug=false] - Enable debug logging
|
|
56758
|
+
*/
|
|
56759
|
+
constructor(options = {}) {
|
|
56760
|
+
this.strategy = options.strategy || FALLBACK_STRATEGIES.ANY;
|
|
56761
|
+
this.models = Array.isArray(options.models) ? options.models : [];
|
|
56762
|
+
this.providers = Array.isArray(options.providers) ? options.providers : [];
|
|
56763
|
+
this.stopOnSuccess = options.stopOnSuccess ?? true;
|
|
56764
|
+
this.continueOnNonRetryableError = options.continueOnNonRetryableError ?? false;
|
|
56765
|
+
this.debug = options.debug ?? false;
|
|
56766
|
+
const maxAttempts = options.maxTotalAttempts ?? 10;
|
|
56767
|
+
if (typeof maxAttempts !== "number" || isNaN(maxAttempts) || maxAttempts < 1 || maxAttempts > 100) {
|
|
56768
|
+
throw new Error(`FallbackManager: maxTotalAttempts must be a number between 1 and 100, got: ${maxAttempts}`);
|
|
56769
|
+
}
|
|
56770
|
+
this.maxTotalAttempts = maxAttempts;
|
|
56771
|
+
this.stats = {
|
|
56772
|
+
totalAttempts: 0,
|
|
56773
|
+
providerAttempts: {},
|
|
56774
|
+
successfulProvider: null,
|
|
56775
|
+
failedProviders: []
|
|
56776
|
+
};
|
|
56777
|
+
this._validateConfiguration();
|
|
56778
|
+
}
|
|
56779
|
+
/**
|
|
56780
|
+
* Validate the fallback configuration
|
|
56781
|
+
* @private
|
|
56782
|
+
*/
|
|
56783
|
+
_validateConfiguration() {
|
|
56784
|
+
if (this.strategy === FALLBACK_STRATEGIES.SAME_PROVIDER && this.models.length === 0) {
|
|
56785
|
+
throw new Error('FallbackManager: strategy "same-provider" requires models list');
|
|
56786
|
+
}
|
|
56787
|
+
if (this.strategy === FALLBACK_STRATEGIES.CUSTOM && this.providers.length === 0) {
|
|
56788
|
+
throw new Error('FallbackManager: strategy "custom" requires providers list');
|
|
56789
|
+
}
|
|
56790
|
+
for (const config of this.providers) {
|
|
56791
|
+
if (!config.provider) {
|
|
56792
|
+
throw new Error('FallbackManager: Each provider config must have a "provider" field');
|
|
56793
|
+
}
|
|
56794
|
+
if (!["anthropic", "openai", "google", "bedrock"].includes(config.provider)) {
|
|
56795
|
+
throw new Error(`FallbackManager: Invalid provider "${config.provider}". Must be: anthropic, openai, google, or bedrock`);
|
|
56796
|
+
}
|
|
56797
|
+
if (config.provider === "bedrock") {
|
|
56798
|
+
const hasCredentials = config.accessKeyId && config.secretAccessKey && config.region;
|
|
56799
|
+
const hasApiKey = config.apiKey;
|
|
56800
|
+
if (!hasCredentials && !hasApiKey) {
|
|
56801
|
+
throw new Error("FallbackManager: Bedrock provider requires either (accessKeyId, secretAccessKey, region) or apiKey");
|
|
56802
|
+
}
|
|
56803
|
+
} else {
|
|
56804
|
+
if (!config.apiKey) {
|
|
56805
|
+
throw new Error(`FallbackManager: Provider "${config.provider}" requires apiKey`);
|
|
56806
|
+
}
|
|
56807
|
+
}
|
|
56808
|
+
}
|
|
56809
|
+
}
|
|
56810
|
+
/**
|
|
56811
|
+
* Create a provider instance from configuration
|
|
56812
|
+
* @param {ProviderConfig} config - Provider configuration
|
|
56813
|
+
* @returns {Object} - Provider instance
|
|
56814
|
+
* @throws {Error} - If provider creation fails
|
|
56815
|
+
* @private
|
|
56816
|
+
*/
|
|
56817
|
+
_createProviderInstance(config) {
|
|
56818
|
+
try {
|
|
56819
|
+
switch (config.provider) {
|
|
56820
|
+
case "anthropic":
|
|
56821
|
+
return createAnthropic({
|
|
56822
|
+
apiKey: config.apiKey,
|
|
56823
|
+
...config.baseURL && { baseURL: config.baseURL }
|
|
56824
|
+
});
|
|
56825
|
+
case "openai":
|
|
56826
|
+
return createOpenAI({
|
|
56827
|
+
compatibility: "strict",
|
|
56828
|
+
apiKey: config.apiKey,
|
|
56829
|
+
...config.baseURL && { baseURL: config.baseURL }
|
|
56830
|
+
});
|
|
56831
|
+
case "google":
|
|
56832
|
+
return createGoogleGenerativeAI({
|
|
56833
|
+
apiKey: config.apiKey,
|
|
56834
|
+
...config.baseURL && { baseURL: config.baseURL }
|
|
56835
|
+
});
|
|
56836
|
+
case "bedrock": {
|
|
56837
|
+
const bedrockConfig = {};
|
|
56838
|
+
if (config.apiKey) {
|
|
56839
|
+
bedrockConfig.apiKey = config.apiKey;
|
|
56840
|
+
} else if (config.accessKeyId && config.secretAccessKey) {
|
|
56841
|
+
bedrockConfig.accessKeyId = config.accessKeyId;
|
|
56842
|
+
bedrockConfig.secretAccessKey = config.secretAccessKey;
|
|
56843
|
+
if (config.sessionToken) {
|
|
56844
|
+
bedrockConfig.sessionToken = config.sessionToken;
|
|
56845
|
+
}
|
|
56846
|
+
}
|
|
56847
|
+
if (config.region) {
|
|
56848
|
+
bedrockConfig.region = config.region;
|
|
56849
|
+
}
|
|
56850
|
+
if (config.baseURL) {
|
|
56851
|
+
bedrockConfig.baseURL = config.baseURL;
|
|
56852
|
+
}
|
|
56853
|
+
return createAmazonBedrock(bedrockConfig);
|
|
56854
|
+
}
|
|
56855
|
+
default:
|
|
56856
|
+
throw new Error(`FallbackManager: Unknown provider "${config.provider}"`);
|
|
56857
|
+
}
|
|
56858
|
+
} catch (error) {
|
|
56859
|
+
const providerName = this._getProviderDisplayName(config);
|
|
56860
|
+
throw new Error(`Failed to create provider instance for ${providerName}: ${error.message}`);
|
|
56861
|
+
}
|
|
56862
|
+
}
|
|
56863
|
+
/**
|
|
56864
|
+
* Get the model name for a provider configuration
|
|
56865
|
+
* @param {ProviderConfig} config - Provider configuration
|
|
56866
|
+
* @returns {string} - Model name
|
|
56867
|
+
* @private
|
|
56868
|
+
*/
|
|
56869
|
+
_getModelName(config) {
|
|
56870
|
+
return config.model || DEFAULT_MODELS[config.provider];
|
|
56871
|
+
}
|
|
56872
|
+
/**
|
|
56873
|
+
* Get provider display name for logging
|
|
56874
|
+
* @param {ProviderConfig} config - Provider configuration
|
|
56875
|
+
* @returns {string} - Display name
|
|
56876
|
+
* @private
|
|
56877
|
+
*/
|
|
56878
|
+
_getProviderDisplayName(config) {
|
|
56879
|
+
const model = this._getModelName(config);
|
|
56880
|
+
const provider = config.provider;
|
|
56881
|
+
const url = config.baseURL ? ` (${config.baseURL})` : "";
|
|
56882
|
+
return `${provider}/${model}${url}`;
|
|
56883
|
+
}
|
|
56884
|
+
/**
|
|
56885
|
+
* Execute a function with fallback support
|
|
56886
|
+
* @param {Function} fn - Function that takes (provider, model, config) and returns a Promise
|
|
56887
|
+
* @returns {Promise<*>} - Result from the function
|
|
56888
|
+
* @throws {Error} - If all fallbacks are exhausted
|
|
56889
|
+
*/
|
|
56890
|
+
async executeWithFallback(fn) {
|
|
56891
|
+
if (this.providers.length === 0) {
|
|
56892
|
+
throw new Error("FallbackManager: No providers configured for fallback");
|
|
56893
|
+
}
|
|
56894
|
+
let lastError = null;
|
|
56895
|
+
let totalAttempts = 0;
|
|
56896
|
+
for (const config of this.providers) {
|
|
56897
|
+
if (totalAttempts >= this.maxTotalAttempts) {
|
|
56898
|
+
if (this.debug) {
|
|
56899
|
+
console.log(`[FallbackManager] \u26A0\uFE0F Max total attempts (${this.maxTotalAttempts}) reached`);
|
|
56900
|
+
}
|
|
56901
|
+
break;
|
|
56902
|
+
}
|
|
56903
|
+
totalAttempts++;
|
|
56904
|
+
this.stats.totalAttempts++;
|
|
56905
|
+
const providerName = this._getProviderDisplayName(config);
|
|
56906
|
+
this.stats.providerAttempts[providerName] = (this.stats.providerAttempts[providerName] || 0) + 1;
|
|
56907
|
+
try {
|
|
56908
|
+
if (this.debug) {
|
|
56909
|
+
console.log(`[FallbackManager] Attempting provider: ${providerName} (attempt ${totalAttempts}/${this.maxTotalAttempts})`);
|
|
56910
|
+
}
|
|
56911
|
+
const provider = this._createProviderInstance(config);
|
|
56912
|
+
const model = this._getModelName(config);
|
|
56913
|
+
const result = await fn(provider, model, config);
|
|
56914
|
+
this.stats.successfulProvider = providerName;
|
|
56915
|
+
if (this.debug) {
|
|
56916
|
+
console.log(`[FallbackManager] \u2705 Success with provider: ${providerName}`);
|
|
56917
|
+
}
|
|
56918
|
+
return result;
|
|
56919
|
+
} catch (error) {
|
|
56920
|
+
lastError = error;
|
|
56921
|
+
const errorInfo = {
|
|
56922
|
+
message: error.message || error.toString(),
|
|
56923
|
+
type: error.type || error.constructor.name,
|
|
56924
|
+
statusCode: error.statusCode || error.status
|
|
56925
|
+
};
|
|
56926
|
+
this.stats.failedProviders.push({
|
|
56927
|
+
provider: providerName,
|
|
56928
|
+
error: errorInfo
|
|
56929
|
+
});
|
|
56930
|
+
if (this.debug) {
|
|
56931
|
+
console.log(`[FallbackManager] \u274C Failed with provider: ${providerName}`, errorInfo);
|
|
56932
|
+
}
|
|
56933
|
+
if (!this.continueOnNonRetryableError && error.nonRetryable) {
|
|
56934
|
+
if (this.debug) {
|
|
56935
|
+
console.log(`[FallbackManager] Non-retryable error, stopping fallback chain`);
|
|
56936
|
+
}
|
|
56937
|
+
throw error;
|
|
56938
|
+
}
|
|
56939
|
+
if (this.debug) {
|
|
56940
|
+
const remaining = this.providers.length - (this.providers.indexOf(config) + 1);
|
|
56941
|
+
console.log(`[FallbackManager] Trying next provider (${remaining} remaining)...`);
|
|
56942
|
+
}
|
|
56943
|
+
}
|
|
56944
|
+
}
|
|
56945
|
+
if (this.debug) {
|
|
56946
|
+
console.log(`[FallbackManager] \u274C All providers exhausted. Total attempts: ${totalAttempts}`);
|
|
56947
|
+
}
|
|
56948
|
+
const fallbackError = new Error(
|
|
56949
|
+
`All provider fallbacks exhausted after ${totalAttempts} attempts. Last error: ${lastError?.message || "Unknown error"}`
|
|
56950
|
+
);
|
|
56951
|
+
fallbackError.cause = lastError;
|
|
56952
|
+
fallbackError.stats = this.getStats();
|
|
56953
|
+
fallbackError.allProvidersFailed = true;
|
|
56954
|
+
throw fallbackError;
|
|
56955
|
+
}
|
|
56956
|
+
/**
|
|
56957
|
+
* Get fallback statistics
|
|
56958
|
+
* @returns {Object} - Statistics object
|
|
56959
|
+
*/
|
|
56960
|
+
getStats() {
|
|
56961
|
+
return {
|
|
56962
|
+
...this.stats,
|
|
56963
|
+
providerAttempts: { ...this.stats.providerAttempts },
|
|
56964
|
+
failedProviders: [...this.stats.failedProviders]
|
|
56965
|
+
};
|
|
56966
|
+
}
|
|
56967
|
+
/**
|
|
56968
|
+
* Reset statistics
|
|
56969
|
+
*/
|
|
56970
|
+
resetStats() {
|
|
56971
|
+
this.stats = {
|
|
56972
|
+
totalAttempts: 0,
|
|
56973
|
+
providerAttempts: {},
|
|
56974
|
+
successfulProvider: null,
|
|
56975
|
+
failedProviders: []
|
|
56976
|
+
};
|
|
56977
|
+
}
|
|
56978
|
+
};
|
|
56979
|
+
}
|
|
56980
|
+
});
|
|
56981
|
+
|
|
56982
|
+
// src/agent/contextCompactor.js
|
|
56983
|
+
var contextCompactor_exports = {};
|
|
56984
|
+
__export(contextCompactor_exports, {
|
|
56985
|
+
calculateCompactionStats: () => calculateCompactionStats,
|
|
56986
|
+
compactMessages: () => compactMessages,
|
|
56987
|
+
handleContextLimitError: () => handleContextLimitError,
|
|
56988
|
+
identifyMessageSegments: () => identifyMessageSegments,
|
|
56989
|
+
isContextLimitError: () => isContextLimitError
|
|
56990
|
+
});
|
|
56991
|
+
function isContextLimitError(error) {
|
|
56992
|
+
if (!error) return false;
|
|
56993
|
+
const errorMessage = (typeof error === "string" ? error : error?.message || "").toLowerCase();
|
|
56994
|
+
const errorString = error.toString().toLowerCase();
|
|
56995
|
+
for (const pattern of CONTEXT_LIMIT_ERROR_PATTERNS) {
|
|
56996
|
+
const lowerPattern = pattern.toLowerCase();
|
|
56997
|
+
if (errorMessage.includes(lowerPattern) || errorString.includes(lowerPattern)) {
|
|
56998
|
+
return true;
|
|
56999
|
+
}
|
|
57000
|
+
}
|
|
57001
|
+
return false;
|
|
57002
|
+
}
|
|
57003
|
+
function identifyMessageSegments(messages) {
|
|
57004
|
+
const segments = [];
|
|
57005
|
+
let currentSegment = null;
|
|
57006
|
+
for (let i = 0; i < messages.length; i++) {
|
|
57007
|
+
const msg = messages[i];
|
|
57008
|
+
if (msg.role === "system") {
|
|
57009
|
+
continue;
|
|
57010
|
+
}
|
|
57011
|
+
if (msg.role === "user") {
|
|
57012
|
+
const content = typeof msg.content === "string" ? msg.content : "";
|
|
57013
|
+
const isToolResult = content.includes("<tool_result>");
|
|
57014
|
+
if (isToolResult && currentSegment) {
|
|
57015
|
+
currentSegment.finalIndex = i;
|
|
57016
|
+
segments.push(currentSegment);
|
|
57017
|
+
currentSegment = null;
|
|
57018
|
+
} else {
|
|
57019
|
+
if (currentSegment) {
|
|
57020
|
+
segments.push(currentSegment);
|
|
57021
|
+
}
|
|
57022
|
+
currentSegment = {
|
|
57023
|
+
userIndex: i,
|
|
57024
|
+
monologueIndices: [],
|
|
57025
|
+
finalIndex: null
|
|
57026
|
+
};
|
|
57027
|
+
}
|
|
57028
|
+
}
|
|
57029
|
+
if (msg.role === "assistant" && currentSegment) {
|
|
57030
|
+
const content = typeof msg.content === "string" ? msg.content : "";
|
|
57031
|
+
if (content.includes("<attempt_completion>") || content.includes("attempt_completion")) {
|
|
57032
|
+
currentSegment.monologueIndices.push(i);
|
|
57033
|
+
currentSegment.finalIndex = i;
|
|
57034
|
+
segments.push(currentSegment);
|
|
57035
|
+
currentSegment = null;
|
|
57036
|
+
} else {
|
|
57037
|
+
currentSegment.monologueIndices.push(i);
|
|
57038
|
+
}
|
|
57039
|
+
}
|
|
57040
|
+
}
|
|
57041
|
+
if (currentSegment) {
|
|
57042
|
+
segments.push(currentSegment);
|
|
57043
|
+
}
|
|
57044
|
+
return segments;
|
|
57045
|
+
}
|
|
57046
|
+
function compactMessages(messages, options = {}) {
|
|
57047
|
+
const {
|
|
57048
|
+
keepLastSegment = true,
|
|
57049
|
+
minSegmentsToKeep = 1
|
|
57050
|
+
} = options;
|
|
57051
|
+
if (!messages || messages.length === 0) {
|
|
57052
|
+
return messages;
|
|
57053
|
+
}
|
|
57054
|
+
const segments = identifyMessageSegments(messages);
|
|
57055
|
+
if (segments.length === 0) {
|
|
57056
|
+
return messages;
|
|
57057
|
+
}
|
|
57058
|
+
const segmentsToPreserve = keepLastSegment ? Math.max(minSegmentsToKeep, 1) : minSegmentsToKeep;
|
|
57059
|
+
const compactableSegments = segments.slice(0, -segmentsToPreserve);
|
|
57060
|
+
const preservedSegments = segments.slice(-segmentsToPreserve);
|
|
57061
|
+
const indicesToKeep = /* @__PURE__ */ new Set();
|
|
57062
|
+
messages.forEach((msg, idx) => {
|
|
57063
|
+
if (msg.role === "system") {
|
|
57064
|
+
indicesToKeep.add(idx);
|
|
57065
|
+
}
|
|
57066
|
+
});
|
|
57067
|
+
compactableSegments.forEach((segment) => {
|
|
57068
|
+
indicesToKeep.add(segment.userIndex);
|
|
57069
|
+
if (segment.finalIndex !== null) {
|
|
57070
|
+
indicesToKeep.add(segment.finalIndex);
|
|
57071
|
+
}
|
|
57072
|
+
});
|
|
57073
|
+
preservedSegments.forEach((segment) => {
|
|
57074
|
+
indicesToKeep.add(segment.userIndex);
|
|
57075
|
+
segment.monologueIndices.forEach((idx) => indicesToKeep.add(idx));
|
|
57076
|
+
if (segment.finalIndex !== null) {
|
|
57077
|
+
indicesToKeep.add(segment.finalIndex);
|
|
57078
|
+
}
|
|
57079
|
+
});
|
|
57080
|
+
const compactedMessages = messages.filter((_, idx) => indicesToKeep.has(idx));
|
|
57081
|
+
return compactedMessages;
|
|
57082
|
+
}
|
|
57083
|
+
function calculateCompactionStats(originalMessages, compactedMessages) {
|
|
57084
|
+
const originalCount = originalMessages.length;
|
|
57085
|
+
const compactedCount = compactedMessages.length;
|
|
57086
|
+
const removed = originalCount - compactedCount;
|
|
57087
|
+
const reductionPercent = originalCount > 0 ? (removed / originalCount * 100).toFixed(1) : 0;
|
|
57088
|
+
const estimateTokens = (msgs) => {
|
|
57089
|
+
return msgs.reduce((sum, msg) => {
|
|
57090
|
+
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
57091
|
+
return sum + Math.ceil(content.length / 4);
|
|
57092
|
+
}, 0);
|
|
57093
|
+
};
|
|
57094
|
+
const originalTokens = estimateTokens(originalMessages);
|
|
57095
|
+
const compactedTokens = estimateTokens(compactedMessages);
|
|
57096
|
+
const tokensSaved = originalTokens - compactedTokens;
|
|
57097
|
+
return {
|
|
57098
|
+
originalCount,
|
|
57099
|
+
compactedCount,
|
|
57100
|
+
removed,
|
|
57101
|
+
reductionPercent: parseFloat(reductionPercent),
|
|
57102
|
+
originalTokens,
|
|
57103
|
+
compactedTokens,
|
|
57104
|
+
tokensSaved
|
|
57105
|
+
};
|
|
57106
|
+
}
|
|
57107
|
+
function handleContextLimitError(error, messages, options = {}) {
|
|
57108
|
+
if (!isContextLimitError(error)) {
|
|
57109
|
+
return null;
|
|
57110
|
+
}
|
|
57111
|
+
const compactedMessages = compactMessages(messages, options);
|
|
57112
|
+
const stats = calculateCompactionStats(messages, compactedMessages);
|
|
57113
|
+
return {
|
|
57114
|
+
compacted: true,
|
|
57115
|
+
messages: compactedMessages,
|
|
57116
|
+
stats
|
|
57117
|
+
};
|
|
57118
|
+
}
|
|
57119
|
+
var CONTEXT_LIMIT_ERROR_PATTERNS;
|
|
57120
|
+
var init_contextCompactor = __esm({
|
|
57121
|
+
"src/agent/contextCompactor.js"() {
|
|
57122
|
+
"use strict";
|
|
57123
|
+
CONTEXT_LIMIT_ERROR_PATTERNS = [
|
|
57124
|
+
// Anthropic
|
|
57125
|
+
"context_length_exceeded",
|
|
57126
|
+
"prompt is too long",
|
|
57127
|
+
// OpenAI
|
|
57128
|
+
"maximum context length",
|
|
57129
|
+
"context length is",
|
|
57130
|
+
// Google/Gemini
|
|
57131
|
+
"input token count exceeds",
|
|
57132
|
+
"token limit exceeded",
|
|
57133
|
+
// Generic patterns
|
|
57134
|
+
"context window",
|
|
57135
|
+
"too many tokens",
|
|
57136
|
+
"token limit",
|
|
57137
|
+
"context limit",
|
|
57138
|
+
"exceed",
|
|
57139
|
+
// Catches "exceeds", "exceed maximum", etc.
|
|
57140
|
+
"over the limit",
|
|
57141
|
+
"maximum tokens"
|
|
57142
|
+
];
|
|
57143
|
+
}
|
|
57144
|
+
});
|
|
57145
|
+
|
|
55612
57146
|
// src/agent/ProbeAgent.js
|
|
55613
57147
|
var ProbeAgent_exports = {};
|
|
55614
57148
|
__export(ProbeAgent_exports, {
|
|
55615
57149
|
ProbeAgent: () => ProbeAgent
|
|
55616
57150
|
});
|
|
55617
57151
|
import dotenv2 from "dotenv";
|
|
55618
|
-
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
55619
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
55620
|
-
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
55621
|
-
import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
|
|
57152
|
+
import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
|
|
57153
|
+
import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
|
|
57154
|
+
import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
|
|
57155
|
+
import { createAmazonBedrock as createAmazonBedrock2 } from "@ai-sdk/amazon-bedrock";
|
|
55622
57156
|
import { streamText } from "ai";
|
|
55623
57157
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
55624
57158
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
55625
|
-
import { existsSync as
|
|
57159
|
+
import { existsSync as existsSync5 } from "fs";
|
|
55626
57160
|
import { readFile, stat } from "fs/promises";
|
|
55627
|
-
import { resolve as
|
|
57161
|
+
import { resolve as resolve4, isAbsolute as isAbsolute2, dirname as dirname4 } from "path";
|
|
55628
57162
|
var MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
55629
57163
|
var init_ProbeAgent = __esm({
|
|
55630
57164
|
"src/agent/ProbeAgent.js"() {
|
|
@@ -55641,8 +57175,18 @@ var init_ProbeAgent = __esm({
|
|
|
55641
57175
|
init_schemaUtils();
|
|
55642
57176
|
init_xmlParsingUtils();
|
|
55643
57177
|
init_mcp();
|
|
57178
|
+
init_RetryManager();
|
|
57179
|
+
init_FallbackManager();
|
|
57180
|
+
init_contextCompactor();
|
|
55644
57181
|
dotenv2.config();
|
|
55645
|
-
MAX_TOOL_ITERATIONS =
|
|
57182
|
+
MAX_TOOL_ITERATIONS = (() => {
|
|
57183
|
+
const val = parseInt(process.env.MAX_TOOL_ITERATIONS || "30", 10);
|
|
57184
|
+
if (isNaN(val) || val < 1 || val > 200) {
|
|
57185
|
+
console.warn("[ProbeAgent] MAX_TOOL_ITERATIONS must be between 1 and 200, using default: 30");
|
|
57186
|
+
return 30;
|
|
57187
|
+
}
|
|
57188
|
+
return val;
|
|
57189
|
+
})();
|
|
55646
57190
|
MAX_HISTORY_MESSAGES = 100;
|
|
55647
57191
|
MAX_IMAGE_FILE_SIZE = 20 * 1024 * 1024;
|
|
55648
57192
|
ProbeAgent = class _ProbeAgent {
|
|
@@ -55669,6 +57213,20 @@ var init_ProbeAgent = __esm({
|
|
|
55669
57213
|
* @param {Array} [options.mcpServers] - Deprecated, use mcpConfig instead
|
|
55670
57214
|
* @param {Object} [options.storageAdapter] - Custom storage adapter for history management
|
|
55671
57215
|
* @param {Object} [options.hooks] - Hook callbacks for events (e.g., {'tool:start': callback})
|
|
57216
|
+
* @param {Array<string>|null} [options.allowedTools] - List of allowed tool names. Use ['*'] for all tools (default), [] or null for no tools (raw AI mode), or specific tool names like ['search', 'query', 'extract']. Supports exclusion with '!' prefix (e.g., ['*', '!bash'])
|
|
57217
|
+
* @param {boolean} [options.disableTools=false] - Convenience flag to disable all tools (equivalent to allowedTools: []). Takes precedence over allowedTools if set.
|
|
57218
|
+
* @param {Object} [options.retry] - Retry configuration
|
|
57219
|
+
* @param {number} [options.retry.maxRetries=3] - Maximum retry attempts per provider
|
|
57220
|
+
* @param {number} [options.retry.initialDelay=1000] - Initial delay in ms
|
|
57221
|
+
* @param {number} [options.retry.maxDelay=30000] - Maximum delay in ms
|
|
57222
|
+
* @param {number} [options.retry.backoffFactor=2] - Exponential backoff multiplier
|
|
57223
|
+
* @param {Array<string>} [options.retry.retryableErrors] - List of retryable error patterns
|
|
57224
|
+
* @param {Object} [options.fallback] - Fallback configuration
|
|
57225
|
+
* @param {string} [options.fallback.strategy] - Fallback strategy: 'same-model', 'same-provider', 'any', 'custom'
|
|
57226
|
+
* @param {Array<string>} [options.fallback.models] - List of models for same-provider fallback
|
|
57227
|
+
* @param {Array<Object>} [options.fallback.providers] - List of provider configurations for custom fallback
|
|
57228
|
+
* @param {boolean} [options.fallback.stopOnSuccess=true] - Stop on first success
|
|
57229
|
+
* @param {number} [options.fallback.maxTotalAttempts=10] - Maximum total attempts across all providers
|
|
55672
57230
|
*/
|
|
55673
57231
|
constructor(options = {}) {
|
|
55674
57232
|
this.sessionId = options.sessionId || randomUUID4();
|
|
@@ -55680,10 +57238,18 @@ var init_ProbeAgent = __esm({
|
|
|
55680
57238
|
this.cancelled = false;
|
|
55681
57239
|
this.tracer = options.tracer || null;
|
|
55682
57240
|
this.outline = !!options.outline;
|
|
55683
|
-
this.maxResponseTokens = options.maxResponseTokens ||
|
|
57241
|
+
this.maxResponseTokens = options.maxResponseTokens || (() => {
|
|
57242
|
+
const val = parseInt(process.env.MAX_RESPONSE_TOKENS || "0", 10);
|
|
57243
|
+
if (isNaN(val) || val < 0 || val > 2e5) {
|
|
57244
|
+
return null;
|
|
57245
|
+
}
|
|
57246
|
+
return val || null;
|
|
57247
|
+
})();
|
|
55684
57248
|
this.maxIterations = options.maxIterations || null;
|
|
55685
57249
|
this.disableMermaidValidation = !!options.disableMermaidValidation;
|
|
55686
57250
|
this.disableJsonValidation = !!options.disableJsonValidation;
|
|
57251
|
+
const effectiveAllowedTools = options.disableTools ? [] : options.allowedTools;
|
|
57252
|
+
this.allowedTools = this._parseAllowedTools(effectiveAllowedTools);
|
|
55687
57253
|
this.storageAdapter = options.storageAdapter || new InMemoryStorageAdapter();
|
|
55688
57254
|
this.hooks = new HookManager();
|
|
55689
57255
|
if (options.hooks) {
|
|
@@ -55721,8 +57287,67 @@ var init_ProbeAgent = __esm({
|
|
|
55721
57287
|
this.mcpServers = options.mcpServers || null;
|
|
55722
57288
|
this.mcpBridge = null;
|
|
55723
57289
|
this._mcpInitialized = false;
|
|
57290
|
+
this.retryConfig = options.retry || {};
|
|
57291
|
+
this.retryManager = null;
|
|
57292
|
+
this.fallbackConfig = options.fallback || null;
|
|
57293
|
+
this.fallbackManager = null;
|
|
55724
57294
|
this.initializeModel();
|
|
55725
57295
|
}
|
|
57296
|
+
/**
|
|
57297
|
+
* Parse allowedTools configuration
|
|
57298
|
+
* @param {Array<string>|null|undefined} allowedTools - Tool filtering configuration
|
|
57299
|
+
* @returns {Object} Parsed configuration with isEnabled method
|
|
57300
|
+
* @private
|
|
57301
|
+
*/
|
|
57302
|
+
_parseAllowedTools(allowedTools) {
|
|
57303
|
+
const matchesPattern2 = (toolName, pattern) => {
|
|
57304
|
+
if (!pattern.includes("*")) {
|
|
57305
|
+
return toolName === pattern;
|
|
57306
|
+
}
|
|
57307
|
+
const regexPattern = pattern.replace(/\*/g, ".*");
|
|
57308
|
+
return new RegExp(`^${regexPattern}$`).test(toolName);
|
|
57309
|
+
};
|
|
57310
|
+
if (!allowedTools || Array.isArray(allowedTools) && allowedTools.includes("*")) {
|
|
57311
|
+
const exclusions = Array.isArray(allowedTools) ? allowedTools.filter((t) => t.startsWith("!")).map((t) => t.slice(1)) : [];
|
|
57312
|
+
return {
|
|
57313
|
+
mode: "all",
|
|
57314
|
+
exclusions,
|
|
57315
|
+
isEnabled: (toolName) => !exclusions.some((pattern) => matchesPattern2(toolName, pattern))
|
|
57316
|
+
};
|
|
57317
|
+
}
|
|
57318
|
+
if (Array.isArray(allowedTools) && allowedTools.length === 0) {
|
|
57319
|
+
return {
|
|
57320
|
+
mode: "none",
|
|
57321
|
+
isEnabled: () => false
|
|
57322
|
+
};
|
|
57323
|
+
}
|
|
57324
|
+
const allowedPatterns = allowedTools.filter((t) => !t.startsWith("!"));
|
|
57325
|
+
return {
|
|
57326
|
+
mode: "whitelist",
|
|
57327
|
+
allowed: allowedPatterns,
|
|
57328
|
+
isEnabled: (toolName) => allowedPatterns.some((pattern) => matchesPattern2(toolName, pattern))
|
|
57329
|
+
};
|
|
57330
|
+
}
|
|
57331
|
+
/**
|
|
57332
|
+
* Check if an MCP tool is allowed based on allowedTools configuration
|
|
57333
|
+
* Uses mcp__ prefix convention (like Claude Code)
|
|
57334
|
+
* @param {string} toolName - The MCP tool name (without mcp__ prefix)
|
|
57335
|
+
* @returns {boolean} - Whether the tool is allowed
|
|
57336
|
+
* @private
|
|
57337
|
+
*/
|
|
57338
|
+
_isMcpToolAllowed(toolName) {
|
|
57339
|
+
const mcpToolName = `mcp__${toolName}`;
|
|
57340
|
+
return this.allowedTools.isEnabled(mcpToolName) || this.allowedTools.isEnabled(toolName);
|
|
57341
|
+
}
|
|
57342
|
+
/**
|
|
57343
|
+
* Filter MCP tools based on allowedTools configuration
|
|
57344
|
+
* @param {string[]} mcpToolNames - Array of MCP tool names
|
|
57345
|
+
* @returns {string[]} - Filtered array of allowed MCP tool names
|
|
57346
|
+
* @private
|
|
57347
|
+
*/
|
|
57348
|
+
_filterMcpTools(mcpToolNames) {
|
|
57349
|
+
return mcpToolNames.filter((toolName) => this._isMcpToolAllowed(toolName));
|
|
57350
|
+
}
|
|
55726
57351
|
/**
|
|
55727
57352
|
* Initialize the agent asynchronously (must be called after constructor)
|
|
55728
57353
|
* This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
|
|
@@ -55749,7 +57374,11 @@ var init_ProbeAgent = __esm({
|
|
|
55749
57374
|
if (this.mcpBridge) {
|
|
55750
57375
|
const mcpTools = this.mcpBridge.mcpTools || {};
|
|
55751
57376
|
for (const [toolName, toolImpl] of Object.entries(mcpTools)) {
|
|
55752
|
-
this.
|
|
57377
|
+
if (this._isMcpToolAllowed(toolName)) {
|
|
57378
|
+
this.toolImplementations[toolName] = toolImpl;
|
|
57379
|
+
} else if (this.debug) {
|
|
57380
|
+
console.error(`[DEBUG] MCP tool '${toolName}' filtered out by allowedTools`);
|
|
57381
|
+
}
|
|
55753
57382
|
}
|
|
55754
57383
|
}
|
|
55755
57384
|
if (this.debug) {
|
|
@@ -55805,6 +57434,14 @@ var init_ProbeAgent = __esm({
|
|
|
55805
57434
|
if (this.enableBash && wrappedTools.bashToolInstance) {
|
|
55806
57435
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
55807
57436
|
}
|
|
57437
|
+
if (this.allowEdit) {
|
|
57438
|
+
if (wrappedTools.editToolInstance) {
|
|
57439
|
+
this.toolImplementations.edit = wrappedTools.editToolInstance;
|
|
57440
|
+
}
|
|
57441
|
+
if (wrappedTools.createToolInstance) {
|
|
57442
|
+
this.toolImplementations.create = wrappedTools.createToolInstance;
|
|
57443
|
+
}
|
|
57444
|
+
}
|
|
55808
57445
|
this.wrappedTools = wrappedTools;
|
|
55809
57446
|
if (this.debug) {
|
|
55810
57447
|
console.error("\n[DEBUG] ========================================");
|
|
@@ -55855,36 +57492,147 @@ var init_ProbeAgent = __esm({
|
|
|
55855
57492
|
if (forceProvider) {
|
|
55856
57493
|
if (forceProvider === "anthropic" && anthropicApiKey) {
|
|
55857
57494
|
this.initializeAnthropicModel(anthropicApiKey, anthropicApiUrl, modelName);
|
|
57495
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55858
57496
|
return;
|
|
55859
57497
|
} else if (forceProvider === "openai" && openaiApiKey) {
|
|
55860
57498
|
this.initializeOpenAIModel(openaiApiKey, openaiApiUrl, modelName);
|
|
57499
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55861
57500
|
return;
|
|
55862
57501
|
} else if (forceProvider === "google" && googleApiKey) {
|
|
55863
57502
|
this.initializeGoogleModel(googleApiKey, googleApiUrl, modelName);
|
|
57503
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55864
57504
|
return;
|
|
55865
57505
|
} else if (forceProvider === "bedrock" && (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey)) {
|
|
55866
57506
|
this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
|
|
57507
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55867
57508
|
return;
|
|
55868
57509
|
}
|
|
55869
57510
|
console.warn(`WARNING: Forced provider "${forceProvider}" selected but required API key is missing or invalid! Falling back to auto-detection.`);
|
|
55870
57511
|
}
|
|
55871
57512
|
if (anthropicApiKey) {
|
|
55872
57513
|
this.initializeAnthropicModel(anthropicApiKey, anthropicApiUrl, modelName);
|
|
57514
|
+
this.initializeFallbackManager("anthropic", modelName);
|
|
55873
57515
|
} else if (openaiApiKey) {
|
|
55874
57516
|
this.initializeOpenAIModel(openaiApiKey, openaiApiUrl, modelName);
|
|
57517
|
+
this.initializeFallbackManager("openai", modelName);
|
|
55875
57518
|
} else if (googleApiKey) {
|
|
55876
57519
|
this.initializeGoogleModel(googleApiKey, googleApiUrl, modelName);
|
|
57520
|
+
this.initializeFallbackManager("google", modelName);
|
|
55877
57521
|
} else if (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey) {
|
|
55878
57522
|
this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
|
|
57523
|
+
this.initializeFallbackManager("bedrock", modelName);
|
|
55879
57524
|
} else {
|
|
55880
57525
|
throw new Error("No API key provided. Please set ANTHROPIC_API_KEY (or ANTHROPIC_AUTH_TOKEN), OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY (or GOOGLE_API_KEY), AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION), or AWS_BEDROCK_API_KEY environment variables.");
|
|
55881
57526
|
}
|
|
55882
57527
|
}
|
|
57528
|
+
/**
|
|
57529
|
+
* Initialize fallback manager based on configuration
|
|
57530
|
+
* @param {string} primaryProvider - The primary provider being used
|
|
57531
|
+
* @param {string} primaryModel - The primary model being used
|
|
57532
|
+
* @private
|
|
57533
|
+
*/
|
|
57534
|
+
initializeFallbackManager(primaryProvider, primaryModel) {
|
|
57535
|
+
if (this.fallbackConfig === false || process.env.DISABLE_FALLBACK === "1") {
|
|
57536
|
+
return;
|
|
57537
|
+
}
|
|
57538
|
+
if (this.fallbackConfig && this.fallbackConfig.providers) {
|
|
57539
|
+
try {
|
|
57540
|
+
this.fallbackManager = new FallbackManager({
|
|
57541
|
+
...this.fallbackConfig,
|
|
57542
|
+
debug: this.debug
|
|
57543
|
+
});
|
|
57544
|
+
if (this.debug) {
|
|
57545
|
+
console.log(`[DEBUG] Fallback manager initialized with ${this.fallbackManager.providers.length} providers`);
|
|
57546
|
+
}
|
|
57547
|
+
} catch (error) {
|
|
57548
|
+
console.error("[WARNING] Failed to initialize fallback manager:", error.message);
|
|
57549
|
+
}
|
|
57550
|
+
return;
|
|
57551
|
+
}
|
|
57552
|
+
const envFallbackManager = createFallbackManagerFromEnv(this.debug);
|
|
57553
|
+
if (envFallbackManager) {
|
|
57554
|
+
this.fallbackManager = envFallbackManager;
|
|
57555
|
+
if (this.debug) {
|
|
57556
|
+
console.log(`[DEBUG] Fallback manager initialized from environment variables`);
|
|
57557
|
+
}
|
|
57558
|
+
return;
|
|
57559
|
+
}
|
|
57560
|
+
if (process.env.AUTO_FALLBACK === "1" || this.fallbackConfig?.auto) {
|
|
57561
|
+
const providers = buildFallbackProvidersFromEnv({
|
|
57562
|
+
primaryProvider,
|
|
57563
|
+
primaryModel
|
|
57564
|
+
});
|
|
57565
|
+
if (providers.length > 1) {
|
|
57566
|
+
try {
|
|
57567
|
+
this.fallbackManager = new FallbackManager({
|
|
57568
|
+
strategy: "custom",
|
|
57569
|
+
providers,
|
|
57570
|
+
debug: this.debug
|
|
57571
|
+
});
|
|
57572
|
+
if (this.debug) {
|
|
57573
|
+
console.log(`[DEBUG] Auto-fallback enabled with ${providers.length} providers`);
|
|
57574
|
+
}
|
|
57575
|
+
} catch (error) {
|
|
57576
|
+
console.error("[WARNING] Failed to initialize auto-fallback:", error.message);
|
|
57577
|
+
}
|
|
57578
|
+
}
|
|
57579
|
+
}
|
|
57580
|
+
}
|
|
57581
|
+
/**
|
|
57582
|
+
* Execute streamText with retry and fallback support
|
|
57583
|
+
* @param {Object} options - streamText options
|
|
57584
|
+
* @returns {Promise<Object>} - streamText result
|
|
57585
|
+
* @private
|
|
57586
|
+
*/
|
|
57587
|
+
async streamTextWithRetryAndFallback(options) {
|
|
57588
|
+
if (!this.retryManager) {
|
|
57589
|
+
this.retryManager = new RetryManager({
|
|
57590
|
+
maxRetries: this.retryConfig.maxRetries ?? 3,
|
|
57591
|
+
initialDelay: this.retryConfig.initialDelay ?? 1e3,
|
|
57592
|
+
maxDelay: this.retryConfig.maxDelay ?? 3e4,
|
|
57593
|
+
backoffFactor: this.retryConfig.backoffFactor ?? 2,
|
|
57594
|
+
retryableErrors: this.retryConfig.retryableErrors,
|
|
57595
|
+
debug: this.debug
|
|
57596
|
+
});
|
|
57597
|
+
}
|
|
57598
|
+
if (!this.fallbackManager) {
|
|
57599
|
+
return await this.retryManager.executeWithRetry(
|
|
57600
|
+
() => streamText(options),
|
|
57601
|
+
{
|
|
57602
|
+
provider: this.apiType,
|
|
57603
|
+
model: this.model
|
|
57604
|
+
}
|
|
57605
|
+
);
|
|
57606
|
+
}
|
|
57607
|
+
return await this.fallbackManager.executeWithFallback(
|
|
57608
|
+
async (provider, model, config) => {
|
|
57609
|
+
const fallbackOptions = {
|
|
57610
|
+
...options,
|
|
57611
|
+
model: provider(model)
|
|
57612
|
+
};
|
|
57613
|
+
const providerRetryManager = new RetryManager({
|
|
57614
|
+
maxRetries: config.maxRetries ?? this.retryConfig.maxRetries ?? 3,
|
|
57615
|
+
initialDelay: this.retryConfig.initialDelay ?? 1e3,
|
|
57616
|
+
maxDelay: this.retryConfig.maxDelay ?? 3e4,
|
|
57617
|
+
backoffFactor: this.retryConfig.backoffFactor ?? 2,
|
|
57618
|
+
retryableErrors: this.retryConfig.retryableErrors,
|
|
57619
|
+
debug: this.debug
|
|
57620
|
+
});
|
|
57621
|
+
return await providerRetryManager.executeWithRetry(
|
|
57622
|
+
() => streamText(fallbackOptions),
|
|
57623
|
+
{
|
|
57624
|
+
provider: config.provider,
|
|
57625
|
+
model
|
|
57626
|
+
}
|
|
57627
|
+
);
|
|
57628
|
+
}
|
|
57629
|
+
);
|
|
57630
|
+
}
|
|
55883
57631
|
/**
|
|
55884
57632
|
* Initialize Anthropic model
|
|
55885
57633
|
*/
|
|
55886
57634
|
initializeAnthropicModel(apiKey, apiUrl, modelName) {
|
|
55887
|
-
this.provider =
|
|
57635
|
+
this.provider = createAnthropic2({
|
|
55888
57636
|
apiKey,
|
|
55889
57637
|
...apiUrl && { baseURL: apiUrl }
|
|
55890
57638
|
});
|
|
@@ -55898,7 +57646,7 @@ var init_ProbeAgent = __esm({
|
|
|
55898
57646
|
* Initialize OpenAI model
|
|
55899
57647
|
*/
|
|
55900
57648
|
initializeOpenAIModel(apiKey, apiUrl, modelName) {
|
|
55901
|
-
this.provider =
|
|
57649
|
+
this.provider = createOpenAI2({
|
|
55902
57650
|
compatibility: "strict",
|
|
55903
57651
|
apiKey,
|
|
55904
57652
|
...apiUrl && { baseURL: apiUrl }
|
|
@@ -55913,7 +57661,7 @@ var init_ProbeAgent = __esm({
|
|
|
55913
57661
|
* Initialize Google model
|
|
55914
57662
|
*/
|
|
55915
57663
|
initializeGoogleModel(apiKey, apiUrl, modelName) {
|
|
55916
|
-
this.provider =
|
|
57664
|
+
this.provider = createGoogleGenerativeAI2({
|
|
55917
57665
|
apiKey,
|
|
55918
57666
|
...apiUrl && { baseURL: apiUrl }
|
|
55919
57667
|
});
|
|
@@ -55943,7 +57691,7 @@ var init_ProbeAgent = __esm({
|
|
|
55943
57691
|
if (baseURL) {
|
|
55944
57692
|
config.baseURL = baseURL;
|
|
55945
57693
|
}
|
|
55946
|
-
this.provider =
|
|
57694
|
+
this.provider = createAmazonBedrock2(config);
|
|
55947
57695
|
this.model = modelName || "anthropic.claude-sonnet-4-20250514-v1:0";
|
|
55948
57696
|
this.apiType = "bedrock";
|
|
55949
57697
|
if (this.debug) {
|
|
@@ -55988,7 +57736,7 @@ var init_ProbeAgent = __esm({
|
|
|
55988
57736
|
let resolvedPath = imagePath;
|
|
55989
57737
|
if (!imagePath.includes("/") && !imagePath.includes("\\")) {
|
|
55990
57738
|
for (const dir of listFilesDirectories) {
|
|
55991
|
-
const potentialPath =
|
|
57739
|
+
const potentialPath = resolve4(dir, imagePath);
|
|
55992
57740
|
const loaded = await this.loadImageIfValid(potentialPath);
|
|
55993
57741
|
if (loaded) {
|
|
55994
57742
|
if (this.debug) {
|
|
@@ -56013,7 +57761,7 @@ var init_ProbeAgent = __esm({
|
|
|
56013
57761
|
let match2;
|
|
56014
57762
|
while ((match2 = fileHeaderPattern.exec(content)) !== null) {
|
|
56015
57763
|
const filePath = match2[1].trim();
|
|
56016
|
-
const dir =
|
|
57764
|
+
const dir = dirname4(filePath);
|
|
56017
57765
|
if (dir && dir !== ".") {
|
|
56018
57766
|
directories.push(dir);
|
|
56019
57767
|
if (this.debug) {
|
|
@@ -56057,21 +57805,21 @@ var init_ProbeAgent = __esm({
|
|
|
56057
57805
|
}
|
|
56058
57806
|
const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
|
|
56059
57807
|
let absolutePath;
|
|
56060
|
-
let
|
|
56061
|
-
if (
|
|
57808
|
+
let isPathAllowed2 = false;
|
|
57809
|
+
if (isAbsolute2(imagePath)) {
|
|
56062
57810
|
absolutePath = imagePath;
|
|
56063
|
-
|
|
57811
|
+
isPathAllowed2 = allowedDirs.some((dir) => absolutePath.startsWith(resolve4(dir)));
|
|
56064
57812
|
} else {
|
|
56065
57813
|
for (const dir of allowedDirs) {
|
|
56066
|
-
const resolvedPath =
|
|
56067
|
-
if (resolvedPath.startsWith(
|
|
57814
|
+
const resolvedPath = resolve4(dir, imagePath);
|
|
57815
|
+
if (resolvedPath.startsWith(resolve4(dir))) {
|
|
56068
57816
|
absolutePath = resolvedPath;
|
|
56069
|
-
|
|
57817
|
+
isPathAllowed2 = true;
|
|
56070
57818
|
break;
|
|
56071
57819
|
}
|
|
56072
57820
|
}
|
|
56073
57821
|
}
|
|
56074
|
-
if (!
|
|
57822
|
+
if (!isPathAllowed2) {
|
|
56075
57823
|
if (this.debug) {
|
|
56076
57824
|
console.log(`[DEBUG] Image path outside allowed directories: ${imagePath}`);
|
|
56077
57825
|
}
|
|
@@ -56250,7 +57998,11 @@ var init_ProbeAgent = __esm({
|
|
|
56250
57998
|
if (this.mcpBridge) {
|
|
56251
57999
|
const mcpTools = this.mcpBridge.mcpTools || {};
|
|
56252
58000
|
for (const [toolName, toolImpl] of Object.entries(mcpTools)) {
|
|
56253
|
-
this.
|
|
58001
|
+
if (this._isMcpToolAllowed(toolName)) {
|
|
58002
|
+
this.toolImplementations[toolName] = toolImpl;
|
|
58003
|
+
} else if (this.debug) {
|
|
58004
|
+
console.error(`[DEBUG] MCP tool '${toolName}' filtered out by allowedTools`);
|
|
58005
|
+
}
|
|
56254
58006
|
}
|
|
56255
58007
|
}
|
|
56256
58008
|
} catch (error) {
|
|
@@ -56260,19 +58012,49 @@ var init_ProbeAgent = __esm({
|
|
|
56260
58012
|
}
|
|
56261
58013
|
}
|
|
56262
58014
|
}
|
|
56263
|
-
let toolDefinitions =
|
|
56264
|
-
|
|
56265
|
-
|
|
56266
|
-
|
|
56267
|
-
${listFilesToolDefinition}
|
|
56268
|
-
${searchFilesToolDefinition}
|
|
56269
|
-
${attemptCompletionToolDefinition}
|
|
58015
|
+
let toolDefinitions = "";
|
|
58016
|
+
const isToolAllowed = (toolName) => this.allowedTools.isEnabled(toolName);
|
|
58017
|
+
if (isToolAllowed("search")) {
|
|
58018
|
+
toolDefinitions += `${searchToolDefinition}
|
|
56270
58019
|
`;
|
|
56271
|
-
|
|
58020
|
+
}
|
|
58021
|
+
if (isToolAllowed("query")) {
|
|
58022
|
+
toolDefinitions += `${queryToolDefinition}
|
|
58023
|
+
`;
|
|
58024
|
+
}
|
|
58025
|
+
if (isToolAllowed("extract")) {
|
|
58026
|
+
toolDefinitions += `${extractToolDefinition}
|
|
58027
|
+
`;
|
|
58028
|
+
}
|
|
58029
|
+
if (isToolAllowed("listFiles")) {
|
|
58030
|
+
toolDefinitions += `${listFilesToolDefinition}
|
|
58031
|
+
`;
|
|
58032
|
+
}
|
|
58033
|
+
if (isToolAllowed("searchFiles")) {
|
|
58034
|
+
toolDefinitions += `${searchFilesToolDefinition}
|
|
58035
|
+
`;
|
|
58036
|
+
}
|
|
58037
|
+
if (this.allowEdit && isToolAllowed("implement")) {
|
|
56272
58038
|
toolDefinitions += `${implementToolDefinition}
|
|
56273
58039
|
`;
|
|
56274
58040
|
}
|
|
56275
|
-
if (this.
|
|
58041
|
+
if (this.allowEdit && isToolAllowed("edit")) {
|
|
58042
|
+
toolDefinitions += `${editToolDefinition}
|
|
58043
|
+
`;
|
|
58044
|
+
}
|
|
58045
|
+
if (this.allowEdit && isToolAllowed("create")) {
|
|
58046
|
+
toolDefinitions += `${createToolDefinition}
|
|
58047
|
+
`;
|
|
58048
|
+
}
|
|
58049
|
+
if (this.enableBash && isToolAllowed("bash")) {
|
|
58050
|
+
toolDefinitions += `${bashToolDefinition}
|
|
58051
|
+
`;
|
|
58052
|
+
}
|
|
58053
|
+
if (isToolAllowed("attempt_completion")) {
|
|
58054
|
+
toolDefinitions += `${attemptCompletionToolDefinition}
|
|
58055
|
+
`;
|
|
58056
|
+
}
|
|
58057
|
+
if (this.enableDelegate && isToolAllowed("delegate")) {
|
|
56276
58058
|
toolDefinitions += `${delegateToolDefinition}
|
|
56277
58059
|
`;
|
|
56278
58060
|
}
|
|
@@ -56337,7 +58119,7 @@ Available Tools:
|
|
|
56337
58119
|
- extract: Extract specific code blocks or lines from files.
|
|
56338
58120
|
- listFiles: List files and directories in a specified location.
|
|
56339
58121
|
- searchFiles: Find files matching a glob pattern with recursive search capability.
|
|
56340
|
-
${this.allowEdit ? "- implement: Implement a feature or fix a bug using aider.\n" : ""}${this.enableDelegate ? "- delegate: Delegate big distinct tasks to specialized probe subagents.\n" : ""}
|
|
58122
|
+
${this.allowEdit ? "- implement: Implement a feature or fix a bug using aider.\n- edit: Edit files using exact string replacement.\n- create: Create new files with specified content.\n" : ""}${this.enableDelegate ? "- delegate: Delegate big distinct tasks to specialized probe subagents.\n" : ""}${this.enableBash ? "- bash: Execute bash commands for system operations.\n" : ""}
|
|
56341
58123
|
- attempt_completion: Finalize the task and provide the result to the user.
|
|
56342
58124
|
- attempt_complete: Quick completion using previous response (shorthand).
|
|
56343
58125
|
`;
|
|
@@ -56351,7 +58133,10 @@ Follow these instructions carefully:
|
|
|
56351
58133
|
6. You MUST respond with exactly ONE tool call per message, using the specified XML format, until the task is complete.
|
|
56352
58134
|
7. Wait for the tool execution result (provided in the next user message in a <tool_result> block) before proceeding to the next step.
|
|
56353
58135
|
8. Once the task is fully completed, use the '<attempt_completion>' tool to provide the final result. This is the ONLY way to signal completion.
|
|
56354
|
-
9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.
|
|
58136
|
+
9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.${this.allowEdit ? `
|
|
58137
|
+
10. When modifying files, choose the appropriate tool:
|
|
58138
|
+
- Use 'edit' for precise changes to existing files (requires exact string match)
|
|
58139
|
+
- Use 'create' for new files or complete file rewrites` : ""}
|
|
56355
58140
|
</instructions>
|
|
56356
58141
|
`;
|
|
56357
58142
|
const predefinedPrompts = {
|
|
@@ -56431,11 +58216,14 @@ ${xmlToolGuidelines}
|
|
|
56431
58216
|
${toolDefinitions}
|
|
56432
58217
|
`;
|
|
56433
58218
|
if (this.mcpBridge && this.mcpBridge.getToolNames().length > 0) {
|
|
56434
|
-
|
|
58219
|
+
const allMcpTools = this.mcpBridge.getToolNames();
|
|
58220
|
+
const allowedMcpTools = this._filterMcpTools(allMcpTools);
|
|
58221
|
+
if (allowedMcpTools.length > 0) {
|
|
58222
|
+
systemMessage += `
|
|
56435
58223
|
## MCP Tools (JSON parameters in <params> tag)
|
|
56436
58224
|
`;
|
|
56437
|
-
|
|
56438
|
-
|
|
58225
|
+
systemMessage += this.mcpBridge.getXmlToolDefinitions(allowedMcpTools);
|
|
58226
|
+
systemMessage += `
|
|
56439
58227
|
|
|
56440
58228
|
For MCP tools, use JSON format within the params tag, e.g.:
|
|
56441
58229
|
<mcp_tool>
|
|
@@ -56444,6 +58232,7 @@ For MCP tools, use JSON format within the params tag, e.g.:
|
|
|
56444
58232
|
</params>
|
|
56445
58233
|
</mcp_tool>
|
|
56446
58234
|
`;
|
|
58235
|
+
}
|
|
56447
58236
|
}
|
|
56448
58237
|
const searchDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
|
|
56449
58238
|
if (this.debug) {
|
|
@@ -56600,44 +58389,83 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
56600
58389
|
}
|
|
56601
58390
|
}
|
|
56602
58391
|
let assistantResponseContent = "";
|
|
56603
|
-
|
|
56604
|
-
|
|
56605
|
-
|
|
56606
|
-
const
|
|
56607
|
-
|
|
56608
|
-
|
|
56609
|
-
|
|
56610
|
-
|
|
56611
|
-
|
|
56612
|
-
|
|
56613
|
-
|
|
56614
|
-
|
|
56615
|
-
|
|
56616
|
-
|
|
58392
|
+
let compactionAttempted = false;
|
|
58393
|
+
while (true) {
|
|
58394
|
+
try {
|
|
58395
|
+
const executeAIRequest = async () => {
|
|
58396
|
+
const messagesForAI = this.prepareMessagesWithImages(currentMessages);
|
|
58397
|
+
const result = await this.streamTextWithRetryAndFallback({
|
|
58398
|
+
model: this.provider(this.model),
|
|
58399
|
+
messages: messagesForAI,
|
|
58400
|
+
maxTokens: maxResponseTokens,
|
|
58401
|
+
temperature: 0.3
|
|
58402
|
+
});
|
|
58403
|
+
const usagePromise = result.usage;
|
|
58404
|
+
for await (const delta of result.textStream) {
|
|
58405
|
+
assistantResponseContent += delta;
|
|
58406
|
+
if (options.onStream) {
|
|
58407
|
+
options.onStream(delta);
|
|
58408
|
+
}
|
|
58409
|
+
}
|
|
58410
|
+
const usage = await usagePromise;
|
|
58411
|
+
if (usage) {
|
|
58412
|
+
this.tokenCounter.recordUsage(usage, result.experimental_providerMetadata);
|
|
56617
58413
|
}
|
|
58414
|
+
return result;
|
|
58415
|
+
};
|
|
58416
|
+
if (this.tracer) {
|
|
58417
|
+
await this.tracer.withSpan("ai.request", executeAIRequest, {
|
|
58418
|
+
"ai.model": this.model,
|
|
58419
|
+
"ai.provider": this.clientApiProvider || "auto",
|
|
58420
|
+
"iteration": currentIteration,
|
|
58421
|
+
"max_tokens": maxResponseTokens,
|
|
58422
|
+
"temperature": 0.3,
|
|
58423
|
+
"message_count": currentMessages.length
|
|
58424
|
+
});
|
|
58425
|
+
} else {
|
|
58426
|
+
await executeAIRequest();
|
|
56618
58427
|
}
|
|
56619
|
-
|
|
56620
|
-
|
|
56621
|
-
|
|
58428
|
+
break;
|
|
58429
|
+
} catch (error) {
|
|
58430
|
+
if (!compactionAttempted && handleContextLimitError) {
|
|
58431
|
+
const compactionResult = handleContextLimitError(error, currentMessages, {
|
|
58432
|
+
keepLastSegment: true,
|
|
58433
|
+
minSegmentsToKeep: 1
|
|
58434
|
+
});
|
|
58435
|
+
if (compactionResult) {
|
|
58436
|
+
const { messages: compactedMessages, stats } = compactionResult;
|
|
58437
|
+
if (stats.removed === 0) {
|
|
58438
|
+
console.error(`[ERROR] Context window exceeded but no messages can be compacted.`);
|
|
58439
|
+
console.error(`[ERROR] The conversation history is already minimal (${stats.originalCount} messages).`);
|
|
58440
|
+
finalResult = `Error: Context window limit exceeded and conversation cannot be compacted further. Consider starting a new session or reducing system message size.`;
|
|
58441
|
+
throw new Error(finalResult);
|
|
58442
|
+
}
|
|
58443
|
+
compactionAttempted = true;
|
|
58444
|
+
console.log(`[INFO] Context window limit exceeded. Compacting conversation...`);
|
|
58445
|
+
console.log(`[INFO] Removed ${stats.removed} messages (${stats.reductionPercent}% reduction)`);
|
|
58446
|
+
console.log(`[INFO] Estimated token savings: ${stats.tokensSaved} tokens`);
|
|
58447
|
+
if (this.debug) {
|
|
58448
|
+
console.log(`[DEBUG] Compaction stats:`, stats);
|
|
58449
|
+
console.log(`[DEBUG] Original message count: ${stats.originalCount}`);
|
|
58450
|
+
console.log(`[DEBUG] Compacted message count: ${stats.compactedCount}`);
|
|
58451
|
+
}
|
|
58452
|
+
currentMessages = [...compactedMessages];
|
|
58453
|
+
if (this.tracer) {
|
|
58454
|
+
this.tracer.addEvent("context.compacted", {
|
|
58455
|
+
"iteration": currentIteration,
|
|
58456
|
+
"original_count": stats.originalCount,
|
|
58457
|
+
"compacted_count": stats.compactedCount,
|
|
58458
|
+
"reduction_percent": stats.reductionPercent,
|
|
58459
|
+
"tokens_saved": stats.tokensSaved
|
|
58460
|
+
});
|
|
58461
|
+
}
|
|
58462
|
+
continue;
|
|
58463
|
+
}
|
|
56622
58464
|
}
|
|
56623
|
-
|
|
56624
|
-
|
|
56625
|
-
|
|
56626
|
-
await this.tracer.withSpan("ai.request", executeAIRequest, {
|
|
56627
|
-
"ai.model": this.model,
|
|
56628
|
-
"ai.provider": this.clientApiProvider || "auto",
|
|
56629
|
-
"iteration": currentIteration,
|
|
56630
|
-
"max_tokens": maxResponseTokens,
|
|
56631
|
-
"temperature": 0.3,
|
|
56632
|
-
"message_count": currentMessages.length
|
|
56633
|
-
});
|
|
56634
|
-
} else {
|
|
56635
|
-
await executeAIRequest();
|
|
58465
|
+
console.error(`Error during streamText (Iter ${currentIteration}):`, error);
|
|
58466
|
+
finalResult = `Error: Failed to get response from AI model during iteration ${currentIteration}. ${error.message}`;
|
|
58467
|
+
throw new Error(finalResult);
|
|
56636
58468
|
}
|
|
56637
|
-
} catch (error) {
|
|
56638
|
-
console.error(`Error during streamText (Iter ${currentIteration}):`, error);
|
|
56639
|
-
finalResult = `Error: Failed to get response from AI model during iteration ${currentIteration}. ${error.message}`;
|
|
56640
|
-
throw new Error(finalResult);
|
|
56641
58469
|
}
|
|
56642
58470
|
if (this.debug && assistantResponseContent) {
|
|
56643
58471
|
const assistantPreview = createMessagePreview(assistantResponseContent);
|
|
@@ -56655,7 +58483,10 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
56655
58483
|
"attempt_completion"
|
|
56656
58484
|
];
|
|
56657
58485
|
if (this.allowEdit) {
|
|
56658
|
-
validTools.push("implement");
|
|
58486
|
+
validTools.push("implement", "edit", "create");
|
|
58487
|
+
}
|
|
58488
|
+
if (this.enableBash) {
|
|
58489
|
+
validTools.push("bash");
|
|
56659
58490
|
}
|
|
56660
58491
|
if (this.enableDelegate) {
|
|
56661
58492
|
validTools.push("delegate");
|
|
@@ -56999,7 +58830,6 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
56999
58830
|
...options,
|
|
57000
58831
|
_schemaFormatted: true
|
|
57001
58832
|
});
|
|
57002
|
-
finalResult = cleanSchemaResponse(finalResult);
|
|
57003
58833
|
if (!this.disableMermaidValidation) {
|
|
57004
58834
|
try {
|
|
57005
58835
|
if (this.debug) {
|
|
@@ -57055,14 +58885,11 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
57055
58885
|
} else if (this.debug) {
|
|
57056
58886
|
console.log(`[DEBUG] Mermaid validation: Skipped due to disableMermaidValidation option`);
|
|
57057
58887
|
}
|
|
58888
|
+
finalResult = cleanSchemaResponse(finalResult);
|
|
57058
58889
|
if (isJsonSchema(options.schema)) {
|
|
57059
58890
|
if (this.debug) {
|
|
57060
58891
|
console.log(`[DEBUG] JSON validation: Starting validation process for schema response`);
|
|
57061
|
-
console.log(`[DEBUG] JSON validation:
|
|
57062
|
-
}
|
|
57063
|
-
finalResult = cleanSchemaResponse(finalResult);
|
|
57064
|
-
if (this.debug) {
|
|
57065
|
-
console.log(`[DEBUG] JSON validation: After cleaning, length: ${finalResult.length} chars`);
|
|
58892
|
+
console.log(`[DEBUG] JSON validation: Cleaned response length: ${finalResult.length} chars`);
|
|
57066
58893
|
}
|
|
57067
58894
|
if (this.tracer) {
|
|
57068
58895
|
this.tracer.recordJsonValidationEvent("started", {
|
|
@@ -57152,10 +58979,9 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
57152
58979
|
console.log("[DEBUG] Skipping schema formatting due to max iterations reached without completion");
|
|
57153
58980
|
} else if (completionAttempted && options.schema && !options._schemaFormatted && !options._skipValidation) {
|
|
57154
58981
|
try {
|
|
57155
|
-
finalResult = cleanSchemaResponse(finalResult);
|
|
57156
58982
|
if (!this.disableMermaidValidation) {
|
|
57157
58983
|
if (this.debug) {
|
|
57158
|
-
console.log(`[DEBUG] Mermaid validation: Validating attempt_completion result...`);
|
|
58984
|
+
console.log(`[DEBUG] Mermaid validation: Validating attempt_completion result BEFORE schema cleaning...`);
|
|
57159
58985
|
}
|
|
57160
58986
|
const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
|
|
57161
58987
|
debug: this.debug,
|
|
@@ -57178,6 +59004,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
57178
59004
|
} else if (this.debug) {
|
|
57179
59005
|
console.log(`[DEBUG] Mermaid validation: Skipped for attempt_completion result due to disableMermaidValidation option`);
|
|
57180
59006
|
}
|
|
59007
|
+
finalResult = cleanSchemaResponse(finalResult);
|
|
57181
59008
|
if (isJsonSchema(options.schema)) {
|
|
57182
59009
|
if (this.debug) {
|
|
57183
59010
|
console.log(`[DEBUG] JSON validation: Starting validation process for attempt_completion result`);
|
|
@@ -57351,6 +59178,56 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
57351
59178
|
console.log(`[DEBUG] Cleared conversation history and reset counters for session ${this.sessionId}`);
|
|
57352
59179
|
}
|
|
57353
59180
|
}
|
|
59181
|
+
/**
|
|
59182
|
+
* Manually compact conversation history
|
|
59183
|
+
* Removes intermediate monologues from older segments while preserving
|
|
59184
|
+
* user messages, final answers, and the most recent segment
|
|
59185
|
+
*
|
|
59186
|
+
* @param {Object} options - Compaction options
|
|
59187
|
+
* @param {boolean} [options.keepLastSegment=true] - Keep the most recent segment intact
|
|
59188
|
+
* @param {number} [options.minSegmentsToKeep=1] - Number of recent segments to preserve fully
|
|
59189
|
+
* @returns {Object} Compaction statistics
|
|
59190
|
+
*/
|
|
59191
|
+
async compactHistory(options = {}) {
|
|
59192
|
+
const { compactMessages: compactMessages2, calculateCompactionStats: calculateCompactionStats2 } = await Promise.resolve().then(() => (init_contextCompactor(), contextCompactor_exports));
|
|
59193
|
+
if (this.history.length === 0) {
|
|
59194
|
+
if (this.debug) {
|
|
59195
|
+
console.log(`[DEBUG] No history to compact for session ${this.sessionId}`);
|
|
59196
|
+
}
|
|
59197
|
+
return {
|
|
59198
|
+
originalCount: 0,
|
|
59199
|
+
compactedCount: 0,
|
|
59200
|
+
removed: 0,
|
|
59201
|
+
reductionPercent: 0,
|
|
59202
|
+
originalTokens: 0,
|
|
59203
|
+
compactedTokens: 0,
|
|
59204
|
+
tokensSaved: 0
|
|
59205
|
+
};
|
|
59206
|
+
}
|
|
59207
|
+
const compactedMessages = compactMessages2(this.history, options);
|
|
59208
|
+
const stats = calculateCompactionStats2(this.history, compactedMessages);
|
|
59209
|
+
this.history = compactedMessages;
|
|
59210
|
+
try {
|
|
59211
|
+
await this.storageAdapter.clearHistory(this.sessionId);
|
|
59212
|
+
for (const message of compactedMessages) {
|
|
59213
|
+
await this.storageAdapter.saveMessage(this.sessionId, message);
|
|
59214
|
+
}
|
|
59215
|
+
} catch (error) {
|
|
59216
|
+
console.error(`[ERROR] Failed to save compacted messages to storage:`, error);
|
|
59217
|
+
}
|
|
59218
|
+
console.log(`[INFO] Manually compacted conversation history`);
|
|
59219
|
+
console.log(`[INFO] Removed ${stats.removed} messages (${stats.reductionPercent}% reduction)`);
|
|
59220
|
+
console.log(`[INFO] Estimated token savings: ${stats.tokensSaved} tokens`);
|
|
59221
|
+
if (this.debug) {
|
|
59222
|
+
console.log(`[DEBUG] Compaction stats:`, stats);
|
|
59223
|
+
}
|
|
59224
|
+
await this.hooks.emit(HOOK_TYPES.STORAGE_SAVE, {
|
|
59225
|
+
sessionId: this.sessionId,
|
|
59226
|
+
compacted: true,
|
|
59227
|
+
stats
|
|
59228
|
+
});
|
|
59229
|
+
return stats;
|
|
59230
|
+
}
|
|
57354
59231
|
/**
|
|
57355
59232
|
* Clone this agent's session to create a new agent with shared conversation history
|
|
57356
59233
|
* @param {Object} options - Clone options
|
|
@@ -57373,6 +59250,14 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
57373
59250
|
if (stripInternalMessages) {
|
|
57374
59251
|
clonedHistory = this._stripInternalMessages(clonedHistory, keepSystemMessage);
|
|
57375
59252
|
}
|
|
59253
|
+
let allowedToolsArray = null;
|
|
59254
|
+
if (this.allowedTools.mode === "whitelist") {
|
|
59255
|
+
allowedToolsArray = [...this.allowedTools.allowed];
|
|
59256
|
+
} else if (this.allowedTools.mode === "none") {
|
|
59257
|
+
allowedToolsArray = [];
|
|
59258
|
+
} else if (this.allowedTools.mode === "all" && this.allowedTools.exclusions.length > 0) {
|
|
59259
|
+
allowedToolsArray = ["*", ...this.allowedTools.exclusions.map((t) => "!" + t)];
|
|
59260
|
+
}
|
|
57376
59261
|
const clonedAgent = new _ProbeAgent({
|
|
57377
59262
|
// Copy current agent's config
|
|
57378
59263
|
customPrompt: this.customPrompt,
|
|
@@ -57390,6 +59275,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
57390
59275
|
maxIterations: this.maxIterations,
|
|
57391
59276
|
disableMermaidValidation: this.disableMermaidValidation,
|
|
57392
59277
|
disableJsonValidation: this.disableJsonValidation,
|
|
59278
|
+
allowedTools: allowedToolsArray,
|
|
57393
59279
|
enableMcp: !!this.mcpBridge,
|
|
57394
59280
|
mcpConfig: this.mcpConfig,
|
|
57395
59281
|
enableBash: this.enableBash,
|
|
@@ -57569,8 +59455,8 @@ import {
|
|
|
57569
59455
|
ListToolsRequestSchema,
|
|
57570
59456
|
McpError
|
|
57571
59457
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
57572
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
57573
|
-
import { resolve as
|
|
59458
|
+
import { readFileSync as readFileSync2, existsSync as existsSync6 } from "fs";
|
|
59459
|
+
import { resolve as resolve5 } from "path";
|
|
57574
59460
|
|
|
57575
59461
|
// src/agent/acp/server.js
|
|
57576
59462
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -57829,8 +59715,8 @@ var ACPConnection = class extends EventEmitter4 {
|
|
|
57829
59715
|
if (params !== null) {
|
|
57830
59716
|
message.params = params;
|
|
57831
59717
|
}
|
|
57832
|
-
return new Promise((
|
|
57833
|
-
this.pendingRequests.set(id, { resolve:
|
|
59718
|
+
return new Promise((resolve6, reject2) => {
|
|
59719
|
+
this.pendingRequests.set(id, { resolve: resolve6, reject: reject2 });
|
|
57834
59720
|
this.sendMessage(message);
|
|
57835
59721
|
setTimeout(() => {
|
|
57836
59722
|
if (this.pendingRequests.has(id)) {
|
|
@@ -58244,8 +60130,8 @@ dotenv3.config();
|
|
|
58244
60130
|
function readInputContent(input) {
|
|
58245
60131
|
if (!input) return null;
|
|
58246
60132
|
try {
|
|
58247
|
-
const resolvedPath =
|
|
58248
|
-
if (
|
|
60133
|
+
const resolvedPath = resolve5(input);
|
|
60134
|
+
if (existsSync6(resolvedPath)) {
|
|
58249
60135
|
return readFileSync2(resolvedPath, "utf-8").trim();
|
|
58250
60136
|
}
|
|
58251
60137
|
} catch (error) {
|
|
@@ -58253,7 +60139,7 @@ function readInputContent(input) {
|
|
|
58253
60139
|
return input;
|
|
58254
60140
|
}
|
|
58255
60141
|
function readFromStdin() {
|
|
58256
|
-
return new Promise((
|
|
60142
|
+
return new Promise((resolve6, reject2) => {
|
|
58257
60143
|
let data = "";
|
|
58258
60144
|
let hasReceivedData = false;
|
|
58259
60145
|
let dataChunks = [];
|
|
@@ -58278,7 +60164,7 @@ function readFromStdin() {
|
|
|
58278
60164
|
if (!trimmed && dataChunks.length === 0) {
|
|
58279
60165
|
reject2(new Error("No input received from stdin"));
|
|
58280
60166
|
} else {
|
|
58281
|
-
|
|
60167
|
+
resolve6(trimmed);
|
|
58282
60168
|
}
|
|
58283
60169
|
});
|
|
58284
60170
|
process.stdin.on("error", (error) => {
|
|
@@ -58324,6 +60210,10 @@ function parseArgs() {
|
|
|
58324
60210
|
// New flag to enable outline format
|
|
58325
60211
|
noMermaidValidation: false,
|
|
58326
60212
|
// New flag to disable mermaid validation
|
|
60213
|
+
allowedTools: null,
|
|
60214
|
+
// Tool filtering: ['*'] = all, [] = none, ['tool1', 'tool2'] = specific
|
|
60215
|
+
disableTools: false,
|
|
60216
|
+
// Convenience flag to disable all tools
|
|
58327
60217
|
// Bash tool configuration
|
|
58328
60218
|
enableBash: false,
|
|
58329
60219
|
bashAllow: null,
|
|
@@ -58377,6 +60267,17 @@ function parseArgs() {
|
|
|
58377
60267
|
config.outline = true;
|
|
58378
60268
|
} else if (arg === "--no-mermaid-validation") {
|
|
58379
60269
|
config.noMermaidValidation = true;
|
|
60270
|
+
} else if (arg === "--allowed-tools" && i + 1 < args.length) {
|
|
60271
|
+
const toolsArg = args[++i];
|
|
60272
|
+
if (toolsArg === "*" || toolsArg === "all") {
|
|
60273
|
+
config.allowedTools = ["*"];
|
|
60274
|
+
} else if (toolsArg === "none" || toolsArg === "") {
|
|
60275
|
+
config.allowedTools = [];
|
|
60276
|
+
} else {
|
|
60277
|
+
config.allowedTools = toolsArg.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
60278
|
+
}
|
|
60279
|
+
} else if (arg === "--disable-tools") {
|
|
60280
|
+
config.disableTools = true;
|
|
58380
60281
|
} else if (arg === "--enable-bash") {
|
|
58381
60282
|
config.enableBash = true;
|
|
58382
60283
|
} else if (arg === "--bash-allow" && i + 1 < args.length) {
|
|
@@ -58421,6 +60322,13 @@ Options:
|
|
|
58421
60322
|
--model <name> Override model name
|
|
58422
60323
|
--allow-edit Enable code modification capabilities
|
|
58423
60324
|
--enable-delegate Enable delegate tool for task distribution to subagents
|
|
60325
|
+
--allowed-tools <tools> Filter available tools (comma-separated list)
|
|
60326
|
+
Use '*' or 'all' for all tools (default)
|
|
60327
|
+
Use 'none' or '' for no tools (raw AI mode)
|
|
60328
|
+
Specific tools: search,query,extract,listFiles,searchFiles
|
|
60329
|
+
Supports exclusion: '*,!bash' (all except bash)
|
|
60330
|
+
--disable-tools Disable all tools (raw AI mode, no code analysis)
|
|
60331
|
+
Convenience flag equivalent to --allowed-tools none
|
|
58424
60332
|
--verbose Enable verbose output
|
|
58425
60333
|
--outline Use outline-xml format for code search results
|
|
58426
60334
|
--mcp Run as MCP server
|
|
@@ -58462,6 +60370,9 @@ Examples:
|
|
|
58462
60370
|
probe agent "Analyze codebase" --schema schema.json # Schema from file
|
|
58463
60371
|
probe agent "Debug issue" --trace-file ./debug.jsonl --verbose
|
|
58464
60372
|
probe agent "Analyze code" --trace-remote http://localhost:4318/v1/traces
|
|
60373
|
+
probe agent "Explain this code" --allowed-tools search,extract # Only search and extract
|
|
60374
|
+
probe agent "What is this project about?" --allowed-tools none # Raw AI mode (no tools)
|
|
60375
|
+
probe agent "Tell me about this project" --disable-tools # Raw AI mode (convenience flag)
|
|
58465
60376
|
probe agent --mcp # Start MCP server mode
|
|
58466
60377
|
probe agent --acp # Start ACP server mode
|
|
58467
60378
|
|
|
@@ -58588,7 +60499,9 @@ var ProbeAgentMcpServer = class {
|
|
|
58588
60499
|
allowEdit: !!args.allow_edit,
|
|
58589
60500
|
debug: process.env.DEBUG === "1",
|
|
58590
60501
|
maxResponseTokens: args.max_response_tokens,
|
|
58591
|
-
disableMermaidValidation: !!args.no_mermaid_validation
|
|
60502
|
+
disableMermaidValidation: !!args.no_mermaid_validation,
|
|
60503
|
+
allowedTools: args.allowed_tools,
|
|
60504
|
+
disableTools: args.disable_tools
|
|
58592
60505
|
};
|
|
58593
60506
|
this.agent = new ProbeAgent(agentConfig2);
|
|
58594
60507
|
await this.agent.initialize();
|
|
@@ -58804,7 +60717,7 @@ async function main() {
|
|
|
58804
60717
|
bashConfig.timeout = timeout;
|
|
58805
60718
|
}
|
|
58806
60719
|
if (config.bashWorkingDir) {
|
|
58807
|
-
if (!
|
|
60720
|
+
if (!existsSync6(config.bashWorkingDir)) {
|
|
58808
60721
|
console.error(`Error: Bash working directory does not exist: ${config.bashWorkingDir}`);
|
|
58809
60722
|
process.exit(1);
|
|
58810
60723
|
}
|
|
@@ -58826,6 +60739,8 @@ async function main() {
|
|
|
58826
60739
|
outline: config.outline,
|
|
58827
60740
|
maxResponseTokens: config.maxResponseTokens,
|
|
58828
60741
|
disableMermaidValidation: config.noMermaidValidation,
|
|
60742
|
+
allowedTools: config.allowedTools,
|
|
60743
|
+
disableTools: config.disableTools,
|
|
58829
60744
|
enableBash: config.enableBash,
|
|
58830
60745
|
bashConfig
|
|
58831
60746
|
};
|