Uanderson Silva commited on
Commit
48a8015
Β·
1 Parent(s): b66ebf4

use different models and add winston logger

Browse files
package-lock.json CHANGED
@@ -16,6 +16,7 @@
16
  "@solidity-parser/parser": "^0.20.2",
17
  "dotenv": "^17.4.2",
18
  "langchain": "^1.4.0",
 
19
  "zod": "^4.4.3"
20
  },
21
  "devDependencies": {
@@ -223,6 +224,26 @@
223
  "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==",
224
  "license": "MIT"
225
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  "node_modules/@emnapi/core": {
227
  "version": "1.10.0",
228
  "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
@@ -756,6 +777,16 @@
756
  "dev": true,
757
  "license": "MIT"
758
  },
 
 
 
 
 
 
 
 
 
 
759
  "node_modules/@solidity-parser/parser": {
760
  "version": "0.20.2",
761
  "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.2.tgz",
@@ -820,6 +851,12 @@
820
  "undici-types": "~7.19.0"
821
  }
822
  },
 
 
 
 
 
 
823
  "node_modules/@vitest/expect": {
824
  "version": "4.1.5",
825
  "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz",
@@ -955,6 +992,12 @@
955
  "node": ">=12"
956
  }
957
  },
 
 
 
 
 
 
958
  "node_modules/base64-js": {
959
  "version": "1.5.1",
960
  "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -997,6 +1040,52 @@
997
  "node": ">=18"
998
  }
999
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1000
  "node_modules/convert-source-map": {
1001
  "version": "2.0.0",
1002
  "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -1035,6 +1124,12 @@
1035
  "url": "https://dotenvx.com"
1036
  }
1037
  },
 
 
 
 
 
 
1038
  "node_modules/es-module-lexer": {
1039
  "version": "2.1.0",
1040
  "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
@@ -1095,6 +1190,18 @@
1095
  }
1096
  }
1097
  },
 
 
 
 
 
 
 
 
 
 
 
 
1098
  "node_modules/fsevents": {
1099
  "version": "2.3.3",
1100
  "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -1110,6 +1217,12 @@
1110
  "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1111
  }
1112
  },
 
 
 
 
 
 
1113
  "node_modules/is-network-error": {
1114
  "version": "1.3.1",
1115
  "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.1.tgz",
@@ -1122,6 +1235,18 @@
1122
  "url": "https://github.com/sponsors/sindresorhus"
1123
  }
1124
  },
 
 
 
 
 
 
 
 
 
 
 
 
1125
  "node_modules/js-tiktoken": {
1126
  "version": "1.0.21",
1127
  "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz",
@@ -1144,6 +1269,12 @@
1144
  "node": ">=16"
1145
  }
1146
  },
 
 
 
 
 
 
1147
  "node_modules/langchain": {
1148
  "version": "1.4.0",
1149
  "resolved": "https://registry.npmjs.org/langchain/-/langchain-1.4.0.tgz",
@@ -1456,6 +1587,23 @@
1456
  "url": "https://opencollective.com/parcel"
1457
  }
1458
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1459
  "node_modules/magic-string": {
1460
  "version": "0.30.21",
1461
  "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -1466,6 +1614,12 @@
1466
  "@jridgewell/sourcemap-codec": "^1.5.5"
1467
  }
1468
  },
 
 
 
 
 
 
1469
  "node_modules/mustache": {
1470
  "version": "4.2.0",
1471
  "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
@@ -1505,6 +1659,15 @@
1505
  ],
1506
  "license": "MIT"
1507
  },
 
 
 
 
 
 
 
 
 
1508
  "node_modules/openai": {
1509
  "version": "6.36.0",
1510
  "resolved": "https://registry.npmjs.org/openai/-/openai-6.36.0.tgz",
@@ -1634,6 +1797,20 @@
1634
  "node": "^10 || ^12 || >=14"
1635
  }
1636
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1637
  "node_modules/rolldown": {
1638
  "version": "1.0.0-rc.18",
1639
  "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.18.tgz",
@@ -1668,6 +1845,35 @@
1668
  "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.18"
1669
  }
1670
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1671
  "node_modules/siginfo": {
1672
  "version": "2.0.0",
1673
  "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
@@ -1685,6 +1891,15 @@
1685
  "node": ">=0.10.0"
1686
  }
1687
  },
 
 
 
 
 
 
 
 
 
1688
  "node_modules/stackback": {
1689
  "version": "0.0.2",
1690
  "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
@@ -1699,6 +1914,21 @@
1699
  "dev": true,
1700
  "license": "MIT"
1701
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1702
  "node_modules/tinybench": {
1703
  "version": "2.9.0",
1704
  "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
@@ -1743,6 +1973,15 @@
1743
  "node": ">=14.0.0"
1744
  }
1745
  },
 
 
 
 
 
 
 
 
 
1746
  "node_modules/ts-algebra": {
1747
  "version": "2.0.0",
1748
  "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz",
@@ -1778,6 +2017,12 @@
1778
  "dev": true,
1779
  "license": "MIT"
1780
  },
 
 
 
 
 
 
1781
  "node_modules/uuid": {
1782
  "version": "10.0.0",
1783
  "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
@@ -1977,6 +2222,42 @@
1977
  "node": ">=8"
1978
  }
1979
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1980
  "node_modules/zod": {
1981
  "version": "4.4.3",
1982
  "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
 
16
  "@solidity-parser/parser": "^0.20.2",
17
  "dotenv": "^17.4.2",
18
  "langchain": "^1.4.0",
19
+ "winston": "^3.19.0",
20
  "zod": "^4.4.3"
21
  },
22
  "devDependencies": {
 
224
  "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==",
225
  "license": "MIT"
226
  },
227
+ "node_modules/@colors/colors": {
228
+ "version": "1.6.0",
229
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
230
+ "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
231
+ "license": "MIT",
232
+ "engines": {
233
+ "node": ">=0.1.90"
234
+ }
235
+ },
236
+ "node_modules/@dabh/diagnostics": {
237
+ "version": "2.0.8",
238
+ "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz",
239
+ "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==",
240
+ "license": "MIT",
241
+ "dependencies": {
242
+ "@so-ric/colorspace": "^1.1.6",
243
+ "enabled": "2.0.x",
244
+ "kuler": "^2.0.0"
245
+ }
246
+ },
247
  "node_modules/@emnapi/core": {
248
  "version": "1.10.0",
249
  "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
 
777
  "dev": true,
778
  "license": "MIT"
779
  },
780
+ "node_modules/@so-ric/colorspace": {
781
+ "version": "1.1.6",
782
+ "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz",
783
+ "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==",
784
+ "license": "MIT",
785
+ "dependencies": {
786
+ "color": "^5.0.2",
787
+ "text-hex": "1.0.x"
788
+ }
789
+ },
790
  "node_modules/@solidity-parser/parser": {
791
  "version": "0.20.2",
792
  "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.2.tgz",
 
851
  "undici-types": "~7.19.0"
852
  }
853
  },
854
+ "node_modules/@types/triple-beam": {
855
+ "version": "1.3.5",
856
+ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
857
+ "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
858
+ "license": "MIT"
859
+ },
860
  "node_modules/@vitest/expect": {
861
  "version": "4.1.5",
862
  "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz",
 
992
  "node": ">=12"
993
  }
994
  },
995
+ "node_modules/async": {
996
+ "version": "3.2.6",
997
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
998
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
999
+ "license": "MIT"
1000
+ },
1001
  "node_modules/base64-js": {
1002
  "version": "1.5.1",
1003
  "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
 
1040
  "node": ">=18"
1041
  }
1042
  },
1043
+ "node_modules/color": {
1044
+ "version": "5.0.3",
1045
+ "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz",
1046
+ "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==",
1047
+ "license": "MIT",
1048
+ "dependencies": {
1049
+ "color-convert": "^3.1.3",
1050
+ "color-string": "^2.1.3"
1051
+ },
1052
+ "engines": {
1053
+ "node": ">=18"
1054
+ }
1055
+ },
1056
+ "node_modules/color-convert": {
1057
+ "version": "3.1.3",
1058
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz",
1059
+ "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==",
1060
+ "license": "MIT",
1061
+ "dependencies": {
1062
+ "color-name": "^2.0.0"
1063
+ },
1064
+ "engines": {
1065
+ "node": ">=14.6"
1066
+ }
1067
+ },
1068
+ "node_modules/color-name": {
1069
+ "version": "2.1.0",
1070
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz",
1071
+ "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==",
1072
+ "license": "MIT",
1073
+ "engines": {
1074
+ "node": ">=12.20"
1075
+ }
1076
+ },
1077
+ "node_modules/color-string": {
1078
+ "version": "2.1.4",
1079
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz",
1080
+ "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==",
1081
+ "license": "MIT",
1082
+ "dependencies": {
1083
+ "color-name": "^2.0.0"
1084
+ },
1085
+ "engines": {
1086
+ "node": ">=18"
1087
+ }
1088
+ },
1089
  "node_modules/convert-source-map": {
1090
  "version": "2.0.0",
1091
  "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
 
1124
  "url": "https://dotenvx.com"
1125
  }
1126
  },
1127
+ "node_modules/enabled": {
1128
+ "version": "2.0.0",
1129
+ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
1130
+ "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
1131
+ "license": "MIT"
1132
+ },
1133
  "node_modules/es-module-lexer": {
1134
  "version": "2.1.0",
1135
  "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
 
1190
  }
1191
  }
1192
  },
1193
+ "node_modules/fecha": {
1194
+ "version": "4.2.3",
1195
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
1196
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
1197
+ "license": "MIT"
1198
+ },
1199
+ "node_modules/fn.name": {
1200
+ "version": "1.1.0",
1201
+ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
1202
+ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
1203
+ "license": "MIT"
1204
+ },
1205
  "node_modules/fsevents": {
1206
  "version": "2.3.3",
1207
  "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
 
1217
  "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1218
  }
1219
  },
1220
+ "node_modules/inherits": {
1221
+ "version": "2.0.4",
1222
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1223
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1224
+ "license": "ISC"
1225
+ },
1226
  "node_modules/is-network-error": {
1227
  "version": "1.3.1",
1228
  "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.1.tgz",
 
1235
  "url": "https://github.com/sponsors/sindresorhus"
1236
  }
1237
  },
1238
+ "node_modules/is-stream": {
1239
+ "version": "2.0.1",
1240
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
1241
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
1242
+ "license": "MIT",
1243
+ "engines": {
1244
+ "node": ">=8"
1245
+ },
1246
+ "funding": {
1247
+ "url": "https://github.com/sponsors/sindresorhus"
1248
+ }
1249
+ },
1250
  "node_modules/js-tiktoken": {
1251
  "version": "1.0.21",
1252
  "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz",
 
1269
  "node": ">=16"
1270
  }
1271
  },
1272
+ "node_modules/kuler": {
1273
+ "version": "2.0.0",
1274
+ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
1275
+ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
1276
+ "license": "MIT"
1277
+ },
1278
  "node_modules/langchain": {
1279
  "version": "1.4.0",
1280
  "resolved": "https://registry.npmjs.org/langchain/-/langchain-1.4.0.tgz",
 
1587
  "url": "https://opencollective.com/parcel"
1588
  }
1589
  },
1590
+ "node_modules/logform": {
1591
+ "version": "2.7.0",
1592
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
1593
+ "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
1594
+ "license": "MIT",
1595
+ "dependencies": {
1596
+ "@colors/colors": "1.6.0",
1597
+ "@types/triple-beam": "^1.3.2",
1598
+ "fecha": "^4.2.0",
1599
+ "ms": "^2.1.1",
1600
+ "safe-stable-stringify": "^2.3.1",
1601
+ "triple-beam": "^1.3.0"
1602
+ },
1603
+ "engines": {
1604
+ "node": ">= 12.0.0"
1605
+ }
1606
+ },
1607
  "node_modules/magic-string": {
1608
  "version": "0.30.21",
1609
  "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
 
1614
  "@jridgewell/sourcemap-codec": "^1.5.5"
1615
  }
1616
  },
1617
+ "node_modules/ms": {
1618
+ "version": "2.1.3",
1619
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1620
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1621
+ "license": "MIT"
1622
+ },
1623
  "node_modules/mustache": {
1624
  "version": "4.2.0",
1625
  "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
 
1659
  ],
1660
  "license": "MIT"
1661
  },
1662
+ "node_modules/one-time": {
1663
+ "version": "1.0.0",
1664
+ "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
1665
+ "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
1666
+ "license": "MIT",
1667
+ "dependencies": {
1668
+ "fn.name": "1.x.x"
1669
+ }
1670
+ },
1671
  "node_modules/openai": {
1672
  "version": "6.36.0",
1673
  "resolved": "https://registry.npmjs.org/openai/-/openai-6.36.0.tgz",
 
1797
  "node": "^10 || ^12 || >=14"
1798
  }
1799
  },
1800
+ "node_modules/readable-stream": {
1801
+ "version": "3.6.2",
1802
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
1803
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
1804
+ "license": "MIT",
1805
+ "dependencies": {
1806
+ "inherits": "^2.0.3",
1807
+ "string_decoder": "^1.1.1",
1808
+ "util-deprecate": "^1.0.1"
1809
+ },
1810
+ "engines": {
1811
+ "node": ">= 6"
1812
+ }
1813
+ },
1814
  "node_modules/rolldown": {
1815
  "version": "1.0.0-rc.18",
1816
  "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.18.tgz",
 
1845
  "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.18"
1846
  }
1847
  },
1848
+ "node_modules/safe-buffer": {
1849
+ "version": "5.2.1",
1850
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1851
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1852
+ "funding": [
1853
+ {
1854
+ "type": "github",
1855
+ "url": "https://github.com/sponsors/feross"
1856
+ },
1857
+ {
1858
+ "type": "patreon",
1859
+ "url": "https://www.patreon.com/feross"
1860
+ },
1861
+ {
1862
+ "type": "consulting",
1863
+ "url": "https://feross.org/support"
1864
+ }
1865
+ ],
1866
+ "license": "MIT"
1867
+ },
1868
+ "node_modules/safe-stable-stringify": {
1869
+ "version": "2.5.0",
1870
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
1871
+ "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
1872
+ "license": "MIT",
1873
+ "engines": {
1874
+ "node": ">=10"
1875
+ }
1876
+ },
1877
  "node_modules/siginfo": {
1878
  "version": "2.0.0",
1879
  "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
 
1891
  "node": ">=0.10.0"
1892
  }
1893
  },
1894
+ "node_modules/stack-trace": {
1895
+ "version": "0.0.10",
1896
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
1897
+ "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
1898
+ "license": "MIT",
1899
+ "engines": {
1900
+ "node": "*"
1901
+ }
1902
+ },
1903
  "node_modules/stackback": {
1904
  "version": "0.0.2",
1905
  "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
 
1914
  "dev": true,
1915
  "license": "MIT"
1916
  },
1917
+ "node_modules/string_decoder": {
1918
+ "version": "1.3.0",
1919
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
1920
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
1921
+ "license": "MIT",
1922
+ "dependencies": {
1923
+ "safe-buffer": "~5.2.0"
1924
+ }
1925
+ },
1926
+ "node_modules/text-hex": {
1927
+ "version": "1.0.0",
1928
+ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
1929
+ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
1930
+ "license": "MIT"
1931
+ },
1932
  "node_modules/tinybench": {
1933
  "version": "2.9.0",
1934
  "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
 
1973
  "node": ">=14.0.0"
1974
  }
1975
  },
1976
+ "node_modules/triple-beam": {
1977
+ "version": "1.4.1",
1978
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
1979
+ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
1980
+ "license": "MIT",
1981
+ "engines": {
1982
+ "node": ">= 14.0.0"
1983
+ }
1984
+ },
1985
  "node_modules/ts-algebra": {
1986
  "version": "2.0.0",
1987
  "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz",
 
2017
  "dev": true,
2018
  "license": "MIT"
2019
  },
2020
+ "node_modules/util-deprecate": {
2021
+ "version": "1.0.2",
2022
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
2023
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
2024
+ "license": "MIT"
2025
+ },
2026
  "node_modules/uuid": {
2027
  "version": "10.0.0",
2028
  "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
 
2222
  "node": ">=8"
2223
  }
2224
  },
2225
+ "node_modules/winston": {
2226
+ "version": "3.19.0",
2227
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz",
2228
+ "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==",
2229
+ "license": "MIT",
2230
+ "dependencies": {
2231
+ "@colors/colors": "^1.6.0",
2232
+ "@dabh/diagnostics": "^2.0.8",
2233
+ "async": "^3.2.3",
2234
+ "is-stream": "^2.0.0",
2235
+ "logform": "^2.7.0",
2236
+ "one-time": "^1.0.0",
2237
+ "readable-stream": "^3.4.0",
2238
+ "safe-stable-stringify": "^2.3.1",
2239
+ "stack-trace": "0.0.x",
2240
+ "triple-beam": "^1.3.0",
2241
+ "winston-transport": "^4.9.0"
2242
+ },
2243
+ "engines": {
2244
+ "node": ">= 12.0.0"
2245
+ }
2246
+ },
2247
+ "node_modules/winston-transport": {
2248
+ "version": "4.9.0",
2249
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
2250
+ "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
2251
+ "license": "MIT",
2252
+ "dependencies": {
2253
+ "logform": "^2.7.0",
2254
+ "readable-stream": "^3.6.2",
2255
+ "triple-beam": "^1.3.0"
2256
+ },
2257
+ "engines": {
2258
+ "node": ">= 12.0.0"
2259
+ }
2260
+ },
2261
  "node_modules/zod": {
2262
  "version": "4.4.3",
2263
  "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
package.json CHANGED
@@ -34,6 +34,7 @@
34
  "@solidity-parser/parser": "^0.20.2",
35
  "dotenv": "^17.4.2",
36
  "langchain": "^1.4.0",
 
37
  "zod": "^4.4.3"
38
  }
39
  }
 
34
  "@solidity-parser/parser": "^0.20.2",
35
  "dotenv": "^17.4.2",
36
  "langchain": "^1.4.0",
37
+ "winston": "^3.19.0",
38
  "zod": "^4.4.3"
39
  }
40
  }
src/agents/auditor/agent.ts CHANGED
@@ -5,9 +5,10 @@ import { HumanMessage, SystemMessage } from "@langchain/core/messages";
5
  import { END, type GraphNode, START, StateGraph } from "@langchain/langgraph";
6
  import { z } from "zod";
7
 
8
- import { auditorModel } from "./model.ts";
9
- import { CRITIC_FINDINGS_PROMPT, FIND_VULNERABILITIES_PROMPT, GATHER_CONTEXT_PROMPT } from "./prompts.ts";
10
- import { AuditorState, CriticSchema, FindingSchema } from "./state.ts";
 
11
  import { analyzeSolidityFile } from "./tools/solidity-analyzer-tool.ts";
12
  import {
13
  DOC_BASENAMES,
@@ -52,15 +53,23 @@ const walkDirectory = (dir: string, depth: number, solFiles: string[], docFiles:
52
  };
53
 
54
  const defineScope: GraphNode<typeof AuditorState> = async (state) => {
 
 
55
  const solFiles: string[] = [];
56
  const docFiles: string[] = [];
57
 
58
  walkDirectory(state.repoPath, 0, solFiles, docFiles);
59
 
 
 
 
 
60
  return { scope: solFiles, docs: docFiles };
61
  };
62
 
63
  const gatherContext: GraphNode<typeof AuditorState> = async (state) => {
 
 
64
  const readFile = (filePath: string): string => {
65
  try {
66
  return fs.readFileSync(filePath, "utf-8");
@@ -74,7 +83,7 @@ const gatherContext: GraphNode<typeof AuditorState> = async (state) => {
74
  for (const filePath of state.scope) {
75
  const source = readFile(filePath).slice(0, MAX_SOL_CHARS);
76
  if (!source) continue;
77
- const analysis = await analyzeSolidityFile(source, "short");
78
  solidityEntries.push({ filePath, source, analysis });
79
  }
80
 
@@ -110,66 +119,82 @@ const gatherContext: GraphNode<typeof AuditorState> = async (state) => {
110
  parts.push(`### ${filePath}\n\`\`\`solidity\n${source}\n\`\`\``);
111
  }
112
 
113
- const model = auditorModel.withStructuredOutput(z.object({ context: z.string() }));
114
- const result = await model.invoke([new SystemMessage(GATHER_CONTEXT_PROMPT), new HumanMessage(parts.join("\n\n"))]);
 
 
 
115
 
116
- return { solidityFile, repoContext: result.context };
117
  };
118
 
119
  const findVulnerabilities: GraphNode<typeof AuditorState> = async (state) => {
120
- const model = auditorModel.withStructuredOutput(z.object({ findings: z.array(FindingSchema) }));
121
 
122
  let userMessage = `Contract:\n\n${state.solidityFile}\n\nProtocol Context:\n${state.repoContext}`;
123
 
124
- if (state.criticReviews.length > 0) {
125
- const feedback = state.criticReviews
126
  .map(
127
- (r) =>
128
- `- "${r.findingTitle}": ${r.isFalsePositive ? "FALSE POSITIVE" : "TRUE POSITIVE"}\n Critic: ${r.review}`,
129
  )
130
  .join("\n");
131
- userMessage += `\n\nCritic feedback from previous iteration (iteration ${state.reflectionCount}):\n${feedback}\n\nRevise your findings accordingly.`;
132
  }
133
 
 
 
 
134
  const result = await model.invoke([new SystemMessage(FIND_VULNERABILITIES_PROMPT), new HumanMessage(userMessage)]);
135
 
136
- return { candidateFindings: result.findings };
 
 
 
137
  };
138
 
139
- const criticFindings: GraphNode<typeof AuditorState> = async (state) => {
140
  if (state.candidateFindings.length === 0) {
 
141
  return {
142
- criticReviews: [],
143
  findings: [],
144
  reflectionCount: state.reflectionCount + 1,
145
  };
146
  }
147
 
148
- const model = auditorModel.withStructuredOutput(z.object({ reviews: z.array(CriticSchema) }));
149
 
150
  const findingsText = state.candidateFindings
151
  .map(
152
  (f, i) =>
153
- `[Finding ${i + 1}] ${f.title}\nSeverity: ${f.severity} | Auditor confidence: ${f.confidence}/100\nDescription: ${f.description}\nLocation: ${f.path} lines ${f.location}\nCode:\n\`\`\`solidity\n${f.codeSnippet}\n\`\`\`\nExploit paths:\n${f.exploitablePaths.map((p) => ` - ${p}`).join("\n")}`,
154
  )
155
  .join("\n\n---\n\n");
156
 
 
 
 
157
  const result = await model.invoke([
158
- new SystemMessage(CRITIC_FINDINGS_PROMPT),
159
  new HumanMessage(
160
  `Contract:\n\n${state.solidityFile}\n\nProtocol Context:\n${state.repoContext}\n\nCandidate Findings to Review:\n\n${findingsText}`,
161
  ),
162
  ]);
163
 
164
- const reviewsByTitle = new Map(result.reviews.map((r) => [r.findingTitle.toLowerCase(), r]));
165
 
166
  const confirmedFindings = state.candidateFindings.filter((f, i) => {
167
  const review = reviewsByTitle.get(f.title.toLowerCase()) ?? result.reviews[i];
168
  return review ? !review.isFalsePositive : true;
169
  });
170
 
 
 
 
 
171
  return {
172
- criticReviews: result.reviews,
173
  findings: confirmedFindings,
174
  reflectionCount: state.reflectionCount + 1,
175
  };
@@ -179,16 +204,24 @@ export const auditorAgent = new StateGraph(AuditorState)
179
  .addNode("defineScope", defineScope)
180
  .addNode("gatherContext", gatherContext)
181
  .addNode("findVulnerabilities", findVulnerabilities)
182
- .addNode("criticFindings", criticFindings)
183
  .addEdge(START, "defineScope")
184
  .addEdge("defineScope", "gatherContext")
185
  .addEdge("gatherContext", "findVulnerabilities")
186
- .addEdge("findVulnerabilities", "criticFindings")
187
- .addConditionalEdges("criticFindings", (state) => {
188
- const hasFalsePositives = state.criticReviews.some((r) => r.isFalsePositive);
189
  if (hasFalsePositives && state.reflectionCount < MAX_REFLECTIONS) {
190
  return "findVulnerabilities";
191
  }
192
  return END;
193
  })
194
  .compile();
 
 
 
 
 
 
 
 
 
5
  import { END, type GraphNode, START, StateGraph } from "@langchain/langgraph";
6
  import { z } from "zod";
7
 
8
+ import { logger } from "../../logger.ts";
9
+ import { judgeFindingsModel, findVulnerabilitiesModel, gatherContextModel } from "./model.ts";
10
+ import { JUDGE_FINDINGS_PROMPT, FIND_VULNERABILITIES_PROMPT, GATHER_CONTEXT_PROMPT } from "./prompts.ts";
11
+ import { AuditorState, ReviewSchema, PartialFindingSchema } from "./state.ts";
12
  import { analyzeSolidityFile } from "./tools/solidity-analyzer-tool.ts";
13
  import {
14
  DOC_BASENAMES,
 
53
  };
54
 
55
  const defineScope: GraphNode<typeof AuditorState> = async (state) => {
56
+ logger.info(`defineScope: walking repo at ${state.repoPath}`);
57
+
58
  const solFiles: string[] = [];
59
  const docFiles: string[] = [];
60
 
61
  walkDirectory(state.repoPath, 0, solFiles, docFiles);
62
 
63
+ logger.info(`defineScope: found ${solFiles.length} Solidity file(s), ${docFiles.length} doc file(s)`);
64
+ logger.debug(`defineScope: Solidity files: ${JSON.stringify(solFiles)}`);
65
+ logger.debug(`defineScope: doc files: ${JSON.stringify(docFiles)}`);
66
+
67
  return { scope: solFiles, docs: docFiles };
68
  };
69
 
70
  const gatherContext: GraphNode<typeof AuditorState> = async (state) => {
71
+ logger.info(`gatherContext: processing ${state.scope.length} Solidity file(s) and ${state.docs.length} doc file(s)`);
72
+
73
  const readFile = (filePath: string): string => {
74
  try {
75
  return fs.readFileSync(filePath, "utf-8");
 
83
  for (const filePath of state.scope) {
84
  const source = readFile(filePath).slice(0, MAX_SOL_CHARS);
85
  if (!source) continue;
86
+ const analysis = await analyzeSolidityFile(source, "full");
87
  solidityEntries.push({ filePath, source, analysis });
88
  }
89
 
 
119
  parts.push(`### ${filePath}\n\`\`\`solidity\n${source}\n\`\`\``);
120
  }
121
 
122
+ // const model = gatherContextModel.withStructuredOutput(z.object({ context: z.string() }));
123
+ // const result = await model.invoke([new SystemMessage(GATHER_CONTEXT_PROMPT), new HumanMessage(parts.join("\n\n"))]);
124
+
125
+ logger.info(`gatherContext: context built (${parts.join("\n\n").length} chars)`);
126
+ logger.debug(`gatherContext: full context:\n${parts.join("\n\n")}`);
127
 
128
+ return { solidityFile, repoContext: parts.join("\n\n") };
129
  };
130
 
131
  const findVulnerabilities: GraphNode<typeof AuditorState> = async (state) => {
132
+ const model = findVulnerabilitiesModel.withStructuredOutput(z.object({ findings: z.array(PartialFindingSchema) }));
133
 
134
  let userMessage = `Contract:\n\n${state.solidityFile}\n\nProtocol Context:\n${state.repoContext}`;
135
 
136
+ if (state.judgeReviews.length > 0) {
137
+ const feedback = state.judgeReviews
138
  .map(
139
+ (r) => `- "${r /*.title*/}": ${r.isFalsePositive ? "FALSE POSITIVE" : "TRUE POSITIVE"}\n Judge: ${r.review}`,
 
140
  )
141
  .join("\n");
142
+ userMessage += `\n\nJudge feedback from previous iteration (iteration ${state.reflectionCount}):\n${feedback}\n\nRevise your findings accordingly.`;
143
  }
144
 
145
+ logger.info(`findVulnerabilities: invoking LLM (iteration ${state.reflectionCount + 1})`);
146
+ logger.debug(`findVulnerabilities: user message:\n${userMessage}`);
147
+
148
  const result = await model.invoke([new SystemMessage(FIND_VULNERABILITIES_PROMPT), new HumanMessage(userMessage)]);
149
 
150
+ logger.info(`findVulnerabilities: LLM returned ${result.findings.length} candidate finding(s)`);
151
+ logger.debug(`findVulnerabilities: findings:\n${JSON.stringify(result.findings, null, 2)}`);
152
+
153
+ return { candidateFindings: result.findings.map((finding: any) => ({ ...finding, path: "/", location: "1-14" })) };
154
  };
155
 
156
+ const judgeFindings: GraphNode<typeof AuditorState> = async (state) => {
157
  if (state.candidateFindings.length === 0) {
158
+ logger.info("judgeFindings: no candidate findings to review, skipping LLM call");
159
  return {
160
+ judgeReviews: [],
161
  findings: [],
162
  reflectionCount: state.reflectionCount + 1,
163
  };
164
  }
165
 
166
+ const model = findVulnerabilitiesModel.withStructuredOutput(z.object({ reviews: z.array(ReviewSchema) }));
167
 
168
  const findingsText = state.candidateFindings
169
  .map(
170
  (f, i) =>
171
+ `[Finding ${i + 1}] ${f.title}\nSeverity: ${f.severity}\nDescription: ${f.description}\nLocation: ${f.path} lines ${f.location}\nCode:\n\`\`\`solidity\n${f.codeSnippet}\n\`\`\``,
172
  )
173
  .join("\n\n---\n\n");
174
 
175
+ logger.info(`judgeFindings: reviewing ${state.candidateFindings.length} candidate finding(s)`);
176
+ logger.debug(`judgeFindings: findings text:\n${findingsText}`);
177
+
178
  const result = await model.invoke([
179
+ new SystemMessage(JUDGE_FINDINGS_PROMPT),
180
  new HumanMessage(
181
  `Contract:\n\n${state.solidityFile}\n\nProtocol Context:\n${state.repoContext}\n\nCandidate Findings to Review:\n\n${findingsText}`,
182
  ),
183
  ]);
184
 
185
+ const reviewsByTitle = new Map(result.reviews.map((r: any) => [r.findingTitle.toLowerCase(), r]));
186
 
187
  const confirmedFindings = state.candidateFindings.filter((f, i) => {
188
  const review = reviewsByTitle.get(f.title.toLowerCase()) ?? result.reviews[i];
189
  return review ? !review.isFalsePositive : true;
190
  });
191
 
192
+ const falsePositiveCount = state.candidateFindings.length - confirmedFindings.length;
193
+ logger.info(`judgeFindings: ${confirmedFindings.length} confirmed, ${falsePositiveCount} false positive(s)`);
194
+ logger.debug(`judgeFindings: reviews:\n${JSON.stringify(result.reviews, null, 2)}`);
195
+
196
  return {
197
+ judgeReviews: result.reviews,
198
  findings: confirmedFindings,
199
  reflectionCount: state.reflectionCount + 1,
200
  };
 
204
  .addNode("defineScope", defineScope)
205
  .addNode("gatherContext", gatherContext)
206
  .addNode("findVulnerabilities", findVulnerabilities)
207
+ .addNode("judgeFindings", judgeFindings)
208
  .addEdge(START, "defineScope")
209
  .addEdge("defineScope", "gatherContext")
210
  .addEdge("gatherContext", "findVulnerabilities")
211
+ .addEdge("findVulnerabilities", "judgeFindings")
212
+ .addConditionalEdges("judgeFindings", (state) => {
213
+ const hasFalsePositives = state.judgeReviews.some((r) => r.isFalsePositive);
214
  if (hasFalsePositives && state.reflectionCount < MAX_REFLECTIONS) {
215
  return "findVulnerabilities";
216
  }
217
  return END;
218
  })
219
  .compile();
220
+
221
+ export const testAgent = new StateGraph(AuditorState)
222
+ .addNode("defineScope", defineScope)
223
+ .addNode("gatherContext", gatherContext)
224
+ .addEdge(START, "defineScope")
225
+ .addEdge("defineScope", "gatherContext")
226
+ .addEdge("gatherContext", END)
227
+ .compile();
src/agents/auditor/model.ts CHANGED
@@ -1,5 +1,13 @@
1
  import { ChatAnthropic } from "@langchain/anthropic";
2
 
3
- export const auditorModel = new ChatAnthropic({
 
 
 
 
 
 
 
 
4
  model: "claude-sonnet-4-6",
5
  });
 
1
  import { ChatAnthropic } from "@langchain/anthropic";
2
 
3
+ export const gatherContextModel = new ChatAnthropic({
4
+ model: "claude-haiku-4-5",
5
+ });
6
+
7
+ export const findVulnerabilitiesModel = new ChatAnthropic({
8
+ model: "claude-sonnet-4-6",
9
+ });
10
+
11
+ export const judgeFindingsModel = new ChatAnthropic({
12
  model: "claude-sonnet-4-6",
13
  });
src/agents/auditor/prompts.ts CHANGED
@@ -1,3 +1,4 @@
 
1
  export const GATHER_CONTEXT_PROMPT = `You are a smart contract security expert. You will receive documentation, a structural analysis, and the full source of all in-scope Solidity contracts. Produce a thorough protocol context that will guide vulnerability discovery.
2
 
3
  Structure your output in the following sections:
@@ -30,25 +31,20 @@ For each vulnerability provide ALL of the following fields:
30
  - **description**: Explain the EXPECTED behavior vs the OBSERVED (vulnerable) behavior in 2–4 sentences.
31
  - **recommendation**: Specific, actionable remediation (e.g., "Apply checks-effects-interactions pattern", "Add onlyOwner modifier").
32
  - **severity**: One of "high" (direct fund loss or contract takeover), "medium" (indirect or conditional risk), "low" (best-practice issue, no immediate financial risk).
33
- - **confidence**: Integer 0–100 reflecting your confidence this is a real, exploitable vulnerability.
34
  - **codeSnippet**: The exact vulnerable code block as it appears in the source.
35
- - **location**: Line range as "start-end" (e.g., "42-58"). Use "unknown" if lines are not determinable.
36
- - **path**: File path of the vulnerable contract. Use the contract name if a single inline source is provided.
37
- - **exploitablePaths**: Array of one or more concrete exploit traces. Each trace must describe the attacker steps with realistic inputs/values (e.g., "1. Attacker calls deposit(100 ETH) 2. Attacker contract fallback re-enters withdraw() before balance update 3. Attacker drains 100 ETH twice").
38
 
39
  Vulnerability categories to systematically check: reentrancy (single- and cross-function), access control, integer overflow/underflow, oracle manipulation, flash loan attacks, front-running/MEV, signature replay, storage collisions, uninitialized proxies, unsafe delegatecall, gas griefing, denial of service, precision loss, and logic/business rule violations.
40
 
41
- If critic feedback is provided from a previous iteration, remove confirmed false positives from your list and refine or expand remaining findings based on the critique.`;
42
 
43
- export const CRITIC_FINDINGS_PROMPT = `You are a rigorous smart contract security reviewer. Evaluate each candidate vulnerability submitted by the auditor and determine whether it is a true positive or a false positive.
44
 
45
  For each finding provide ALL of the following fields:
46
 
47
- - **findingTitle**: Must match exactly the title of the finding you are reviewing.
48
  - **review**: Detailed analysis (3–6 sentences) explaining why the vulnerability is or isn't real. Reference specific code, protocol invariants, preconditions, and mitigating controls.
49
  - **isFalsePositive**: true if the finding is NOT exploitable in practice; false if it IS a real vulnerability.
50
  - **confidence**: Integer 0–100 reflecting your confidence in this verdict.
51
- - **exploitablePaths**: If a true positive, provide concrete paths confirming exploitability with real values. If a false positive, provide the reasoning that blocks the exploit.
52
 
53
  A finding is a false positive if and only if: the exploit path is unreachable given access controls or preconditions, it is already fully mitigated by the code, it requires impossible or economically infeasible conditions, or it is explicitly documented as by-design behavior in the protocol assumptions.
54
 
 
1
+ // TODO: Compact the entire full context (parts: docs + static analysis) and infer the sections conciselly
2
  export const GATHER_CONTEXT_PROMPT = `You are a smart contract security expert. You will receive documentation, a structural analysis, and the full source of all in-scope Solidity contracts. Produce a thorough protocol context that will guide vulnerability discovery.
3
 
4
  Structure your output in the following sections:
 
31
  - **description**: Explain the EXPECTED behavior vs the OBSERVED (vulnerable) behavior in 2–4 sentences.
32
  - **recommendation**: Specific, actionable remediation (e.g., "Apply checks-effects-interactions pattern", "Add onlyOwner modifier").
33
  - **severity**: One of "high" (direct fund loss or contract takeover), "medium" (indirect or conditional risk), "low" (best-practice issue, no immediate financial risk).
 
34
  - **codeSnippet**: The exact vulnerable code block as it appears in the source.
 
 
 
35
 
36
  Vulnerability categories to systematically check: reentrancy (single- and cross-function), access control, integer overflow/underflow, oracle manipulation, flash loan attacks, front-running/MEV, signature replay, storage collisions, uninitialized proxies, unsafe delegatecall, gas griefing, denial of service, precision loss, and logic/business rule violations.
37
 
38
+ If judge feedback is provided from a previous iteration, remove confirmed false positives from your list and refine or expand remaining findings based on the critique.`;
39
 
40
+ export const JUDGE_FINDINGS_PROMPT = `You are a rigorous smart contract security reviewer. Evaluate each candidate vulnerability submitted by the auditor and determine whether it is a true positive or a false positive.
41
 
42
  For each finding provide ALL of the following fields:
43
 
 
44
  - **review**: Detailed analysis (3–6 sentences) explaining why the vulnerability is or isn't real. Reference specific code, protocol invariants, preconditions, and mitigating controls.
45
  - **isFalsePositive**: true if the finding is NOT exploitable in practice; false if it IS a real vulnerability.
46
  - **confidence**: Integer 0–100 reflecting your confidence in this verdict.
47
+ - **exploitablePaths**: If a true positive, provide concrete paths confirming exploitability with real values. Each trace must describe the attacker steps with realistic inputs/values (e.g., "1. Attacker calls deposit(100 ETH) 2. Attacker contract fallback re-enters withdraw() before balance update 3. Attacker drains 100 ETH twice"). If a false positive, provide the reasoning that blocks the exploit.
48
 
49
  A finding is a false positive if and only if: the exploit path is unreachable given access controls or preconditions, it is already fully mitigated by the code, it requires impossible or economically infeasible conditions, or it is explicitly documented as by-design behavior in the protocol assumptions.
50
 
src/agents/auditor/state.ts CHANGED
@@ -1,20 +1,25 @@
1
  import { StateSchema } from "@langchain/langgraph";
2
  import { z } from "zod";
3
 
 
 
 
 
 
 
 
 
4
  export const FindingSchema = z.object({
5
  title: z.string(),
6
  description: z.string(),
7
  recommendation: z.string(),
8
  severity: z.enum(["high", "medium", "low"]),
9
- confidence: z.number(),
10
  codeSnippet: z.string(),
11
  location: z.string(),
12
  path: z.string(),
13
- exploitablePaths: z.array(z.string()),
14
  });
15
 
16
- export const CriticSchema = z.object({
17
- findingTitle: z.string(),
18
  review: z.string(),
19
  isFalsePositive: z.boolean(),
20
  confidence: z.number(),
@@ -28,7 +33,7 @@ export const AuditorState = new StateSchema({
28
  docs: z.array(z.string()).default([]),
29
  repoContext: z.string().default(""),
30
  candidateFindings: z.array(FindingSchema).default([]),
31
- criticReviews: z.array(CriticSchema).default([]),
32
  findings: z.array(FindingSchema).default([]),
33
  reflectionCount: z.number().default(0),
34
  });
 
1
  import { StateSchema } from "@langchain/langgraph";
2
  import { z } from "zod";
3
 
4
+ export const PartialFindingSchema = z.object({
5
+ title: z.string(),
6
+ description: z.string(),
7
+ recommendation: z.string(),
8
+ severity: z.enum(["high", "medium", "low"]),
9
+ codeSnippet: z.string(),
10
+ });
11
+
12
  export const FindingSchema = z.object({
13
  title: z.string(),
14
  description: z.string(),
15
  recommendation: z.string(),
16
  severity: z.enum(["high", "medium", "low"]),
 
17
  codeSnippet: z.string(),
18
  location: z.string(),
19
  path: z.string(),
 
20
  });
21
 
22
+ export const ReviewSchema = z.object({
 
23
  review: z.string(),
24
  isFalsePositive: z.boolean(),
25
  confidence: z.number(),
 
33
  docs: z.array(z.string()).default([]),
34
  repoContext: z.string().default(""),
35
  candidateFindings: z.array(FindingSchema).default([]),
36
+ judgeReviews: z.array(ReviewSchema).default([]),
37
  findings: z.array(FindingSchema).default([]),
38
  reflectionCount: z.number().default(0),
39
  });
src/logger.ts ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import winston from "winston";
5
+
6
+ const logsDir = path.join(process.cwd(), "logs");
7
+ fs.mkdirSync(logsDir, { recursive: true });
8
+
9
+ const runTimestamp = new Date().toISOString().replace(/[:.]/g, "-");
10
+
11
+ const { combine, colorize, errors, printf, timestamp } = winston.format;
12
+
13
+ const lineFormat = printf(({ level, message, timestamp: ts, stack }) => {
14
+ const base = `${ts} [${level}] ${message}`;
15
+ return stack ? `${base}\n${stack}` : base;
16
+ });
17
+
18
+ export const logger = winston.createLogger({
19
+ level: "debug",
20
+ transports: [
21
+ new winston.transports.Console({
22
+ format: combine(colorize({ all: true }), timestamp({ format: "HH:mm:ss" }), errors({ stack: true }), lineFormat),
23
+ }),
24
+ new winston.transports.File({
25
+ filename: path.join(logsDir, `app-${runTimestamp}.log`),
26
+ format: combine(timestamp(), errors({ stack: true }), lineFormat),
27
+ }),
28
+ ],
29
+ });