decodingtrust-agent-sdk 0.1.0__py3-none-any.whl

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.
Files changed (374) hide show
  1. agent/__init__.py +30 -0
  2. agent/claudesdk/__init__.py +8 -0
  3. agent/claudesdk/example.py +221 -0
  4. agent/claudesdk/src/__init__.py +8 -0
  5. agent/claudesdk/src/agent.py +400 -0
  6. agent/claudesdk/src/mcp_proxy.py +409 -0
  7. agent/claudesdk/src/utils.py +420 -0
  8. agent/googleadk/__init__.py +15 -0
  9. agent/googleadk/example.py +237 -0
  10. agent/googleadk/src/__init__.py +12 -0
  11. agent/googleadk/src/agent.py +401 -0
  12. agent/googleadk/src/mcp_wrapper.py +163 -0
  13. agent/googleadk/src/utils.py +602 -0
  14. agent/langchain/__init__.py +8 -0
  15. agent/langchain/example.py +213 -0
  16. agent/langchain/src/__init__.py +8 -0
  17. agent/langchain/src/agent.py +645 -0
  18. agent/langchain/src/utils.py +433 -0
  19. agent/openaisdk/__init__.py +17 -0
  20. agent/openaisdk/example.py +228 -0
  21. agent/openaisdk/src/__init__.py +12 -0
  22. agent/openaisdk/src/agent.py +491 -0
  23. agent/openaisdk/src/agent_wrapper.py +143 -0
  24. agent/openaisdk/src/mcp_wrapper.py +395 -0
  25. agent/openaisdk/src/utils.py +493 -0
  26. agent/openclaw/__init__.py +10 -0
  27. agent/openclaw/example.py +251 -0
  28. agent/openclaw/src/__init__.py +14 -0
  29. agent/openclaw/src/agent.py +930 -0
  30. agent/openclaw/src/helpers/__init__.py +1 -0
  31. agent/openclaw/src/helpers/auth_helpers.py +55 -0
  32. agent/openclaw/src/mcp_proxy.py +564 -0
  33. agent/openclaw/src/plugin_generator.py +231 -0
  34. agent/openclaw/src/utils.py +341 -0
  35. agent/pocketflow/__init__.py +18 -0
  36. agent/pocketflow/example.py +221 -0
  37. agent/pocketflow/prompts/react_agent.py +46 -0
  38. agent/pocketflow/src/__init__.py +6 -0
  39. agent/pocketflow/src/agent.py +507 -0
  40. agent/pocketflow/src/agent_wrapper.py +159 -0
  41. agent/pocketflow/src/async_helper.py +92 -0
  42. agent/pocketflow/src/mcp_react_agent.py +279 -0
  43. agent/pocketflow/src/native_agent.py +74 -0
  44. agent/pocketflow/src/nodes.py +467 -0
  45. benchmark/__init__.py +0 -0
  46. benchmark/browser/benign.jsonl +34 -0
  47. benchmark/browser/direct.jsonl +85 -0
  48. benchmark/browser/indirect.jsonl +82 -0
  49. benchmark/code/benign.jsonl +0 -0
  50. benchmark/code/direct.jsonl +121 -0
  51. benchmark/code/indirect.jsonl +165 -0
  52. benchmark/crm/benign.jsonl +165 -0
  53. benchmark/crm/direct.jsonl +90 -0
  54. benchmark/crm/indirect.jsonl +150 -0
  55. benchmark/customer-service/benign.jsonl +160 -0
  56. benchmark/customer-service/direct.jsonl +100 -0
  57. benchmark/customer-service/indirect.jsonl +101 -0
  58. benchmark/finance/benign.jsonl +0 -0
  59. benchmark/finance/direct.jsonl +200 -0
  60. benchmark/finance/indirect.jsonl +200 -0
  61. benchmark/legal/benign.jsonl +0 -0
  62. benchmark/legal/direct.jsonl +200 -0
  63. benchmark/legal/indirect.jsonl +200 -0
  64. benchmark/macos/benign.jsonl +30 -0
  65. benchmark/macos/direct.jsonl +50 -0
  66. benchmark/macos/indirect.jsonl +50 -0
  67. benchmark/medical/benign.jsonl +642 -0
  68. benchmark/medical/direct.jsonl +229 -0
  69. benchmark/medical/indirect.jsonl +222 -0
  70. benchmark/os-filesystem/benign.jsonl +200 -0
  71. benchmark/os-filesystem/direct.jsonl +200 -0
  72. benchmark/os-filesystem/indirect.jsonl +200 -0
  73. benchmark/research/benign.jsonl +0 -0
  74. benchmark/research/direct.jsonl +119 -0
  75. benchmark/research/indirect.jsonl +125 -0
  76. benchmark/telecom/benign.jsonl +120 -0
  77. benchmark/telecom/direct.jsonl +161 -0
  78. benchmark/telecom/indirect.jsonl +166 -0
  79. benchmark/travel/benign.jsonl +130 -0
  80. benchmark/travel/direct.jsonl +105 -0
  81. benchmark/travel/indirect.jsonl +120 -0
  82. benchmark/windows/benign.jsonl +100 -0
  83. benchmark/windows/direct.jsonl +140 -0
  84. benchmark/windows/indirect.jsonl +107 -0
  85. benchmark/workflow/benign.jsonl +335 -0
  86. benchmark/workflow/direct.jsonl +78 -0
  87. benchmark/workflow/indirect.jsonl +107 -0
  88. cli/__init__.py +5 -0
  89. cli/main.py +182 -0
  90. cli/scaffold.py +334 -0
  91. decodingtrust_agent_sdk-0.1.0.dist-info/METADATA +642 -0
  92. decodingtrust_agent_sdk-0.1.0.dist-info/RECORD +374 -0
  93. decodingtrust_agent_sdk-0.1.0.dist-info/WHEEL +5 -0
  94. decodingtrust_agent_sdk-0.1.0.dist-info/entry_points.txt +2 -0
  95. decodingtrust_agent_sdk-0.1.0.dist-info/licenses/LICENSE +201 -0
  96. decodingtrust_agent_sdk-0.1.0.dist-info/top_level.txt +6 -0
  97. dt_arena/config/env.yaml +515 -0
  98. dt_arena/config/injection_mcp.yaml +430 -0
  99. dt_arena/config/mcp.yaml +642 -0
  100. dt_arena/envs/arxiv/docker-compose-hub.yml +31 -0
  101. dt_arena/envs/arxiv/docker-compose.yml +36 -0
  102. dt_arena/envs/atlassian/docker/docker-compose.dev.yml +65 -0
  103. dt_arena/envs/atlassian/docker/docker-compose.yml +53 -0
  104. dt_arena/envs/atlassian/docker-compose-hub.yml +57 -0
  105. dt_arena/envs/atlassian/docker-compose.yml +72 -0
  106. dt_arena/envs/bigquery/docker-compose.yml +20 -0
  107. dt_arena/envs/booking/docker-compose.yml +59 -0
  108. dt_arena/envs/calendar/docker-compose-hub.yml +30 -0
  109. dt_arena/envs/calendar/docker-compose.yml +42 -0
  110. dt_arena/envs/custom-website/docker-compose.yml +6 -0
  111. dt_arena/envs/customer_service/docker-compose.yml +59 -0
  112. dt_arena/envs/databricks/docker-compose-hub.yml +47 -0
  113. dt_arena/envs/databricks/docker-compose.yml +51 -0
  114. dt_arena/envs/ecommerce/docker-compose.yml +6 -0
  115. dt_arena/envs/ers/docker-compose.yml +36 -0
  116. dt_arena/envs/ers/hrms/docker/docker-compose.yml +31 -0
  117. dt_arena/envs/finance/docker-compose.yml +23 -0
  118. dt_arena/envs/github/docker/docker-compose-hub.yml +50 -0
  119. dt_arena/envs/github/docker/docker-compose.yml +50 -0
  120. dt_arena/envs/gmail/docker-compose-hub.yml +51 -0
  121. dt_arena/envs/gmail/docker-compose.yml +65 -0
  122. dt_arena/envs/google-form/docker-compose-hub.yml +33 -0
  123. dt_arena/envs/google-form/docker-compose.yml +41 -0
  124. dt_arena/envs/googledocs/docker-compose-hub.yml +61 -0
  125. dt_arena/envs/googledocs/docker-compose.yml +78 -0
  126. dt_arena/envs/hospital/docker-compose-hub.yml +25 -0
  127. dt_arena/envs/hospital/docker-compose.yml +27 -0
  128. dt_arena/envs/legal/docker-compose.yml +22 -0
  129. dt_arena/envs/linkedin/docker-compose.yml +63 -0
  130. dt_arena/envs/macos/docker-compose.yml +79 -0
  131. dt_arena/envs/os-filesystem/docker-compose-hub.yml +16 -0
  132. dt_arena/envs/os-filesystem/docker-compose.yml +20 -0
  133. dt_arena/envs/paypal/docker-compose-hub.yml +48 -0
  134. dt_arena/envs/paypal/docker-compose.yml +63 -0
  135. dt_arena/envs/research/docker-compose-hub.yml +13 -0
  136. dt_arena/envs/research/docker-compose.yml +24 -0
  137. dt_arena/envs/salesforce_crm/docker-compose-hub.yaml +45 -0
  138. dt_arena/envs/salesforce_crm/docker-compose.yaml +49 -0
  139. dt_arena/envs/slack/docker-compose-hub.yml +28 -0
  140. dt_arena/envs/slack/docker-compose.yml +41 -0
  141. dt_arena/envs/snowflake/docker-compose-hub.yml +41 -0
  142. dt_arena/envs/snowflake/docker-compose.yml +44 -0
  143. dt_arena/envs/telecom/docker-compose-hub.yml +16 -0
  144. dt_arena/envs/telecom/docker-compose.yml +17 -0
  145. dt_arena/envs/telegram/docker-compose-hub.yml +57 -0
  146. dt_arena/envs/telegram/docker-compose.yml +62 -0
  147. dt_arena/envs/terminal/docker-compose-hub.yml +12 -0
  148. dt_arena/envs/terminal/docker-compose.yml +26 -0
  149. dt_arena/envs/travel/docker-compose-hub.yml +19 -0
  150. dt_arena/envs/travel/docker-compose.yml +19 -0
  151. dt_arena/envs/whatsapp/docker-compose-hub.yml +61 -0
  152. dt_arena/envs/whatsapp/docker-compose.yml +78 -0
  153. dt_arena/envs/windows/docker-compose.yml +71 -0
  154. dt_arena/envs/zoom/docker-compose-hub.yml +27 -0
  155. dt_arena/envs/zoom/docker-compose.yml +40 -0
  156. dt_arena/injection_mcp_server/atlassian/env_injection.py +134 -0
  157. dt_arena/injection_mcp_server/calendar/env_injection.py +217 -0
  158. dt_arena/injection_mcp_server/custom_website/env_injection.py +97 -0
  159. dt_arena/injection_mcp_server/customer_service/env_injection.py +659 -0
  160. dt_arena/injection_mcp_server/databricks/env_injection.py +255 -0
  161. dt_arena/injection_mcp_server/ecommerce/env_injection.py +110 -0
  162. dt_arena/injection_mcp_server/finance/env_injection.py +85 -0
  163. dt_arena/injection_mcp_server/github/env_injection.py +206 -0
  164. dt_arena/injection_mcp_server/gmail/env_injection.py +211 -0
  165. dt_arena/injection_mcp_server/google_form/env_injection.py +186 -0
  166. dt_arena/injection_mcp_server/googledocs/env_injection.py +44 -0
  167. dt_arena/injection_mcp_server/hospital/env_injection.py +43 -0
  168. dt_arena/injection_mcp_server/legal/env_injection.py +229 -0
  169. dt_arena/injection_mcp_server/macos/env_injection.py +272 -0
  170. dt_arena/injection_mcp_server/os-filesystem/env_injection.py +341 -0
  171. dt_arena/injection_mcp_server/paypal/env_injection.py +268 -0
  172. dt_arena/injection_mcp_server/research/env_injection.py +616 -0
  173. dt_arena/injection_mcp_server/salesforce/env_injection.py +514 -0
  174. dt_arena/injection_mcp_server/slack/env_injection.py +265 -0
  175. dt_arena/injection_mcp_server/snowflake/env_injection.py +230 -0
  176. dt_arena/injection_mcp_server/telecom/env_injection.py +503 -0
  177. dt_arena/injection_mcp_server/telegram/env_injection.py +171 -0
  178. dt_arena/injection_mcp_server/terminal/env_injection.py +523 -0
  179. dt_arena/injection_mcp_server/travel/env_injection.py +173 -0
  180. dt_arena/injection_mcp_server/whatsapp/env_injection.py +185 -0
  181. dt_arena/injection_mcp_server/windows/env_injection.py +943 -0
  182. dt_arena/injection_mcp_server/zoom/env_injection.py +216 -0
  183. dt_arena/mcp_server/atlassian/main.py +1554 -0
  184. dt_arena/mcp_server/atlassian/test_server.py +66 -0
  185. dt_arena/mcp_server/bigquery/main.py +333 -0
  186. dt_arena/mcp_server/booking/main.py +310 -0
  187. dt_arena/mcp_server/browser/main.py +1741 -0
  188. dt_arena/mcp_server/calendar/example_multi_user.py +162 -0
  189. dt_arena/mcp_server/calendar/main.py +792 -0
  190. dt_arena/mcp_server/calendar/test_mcp.py +135 -0
  191. dt_arena/mcp_server/customer_service/main.py +1063 -0
  192. dt_arena/mcp_server/databricks/main.py +566 -0
  193. dt_arena/mcp_server/databricks/probe.py +102 -0
  194. dt_arena/mcp_server/ers/main.py +845 -0
  195. dt_arena/mcp_server/finance/__init__.py +87 -0
  196. dt_arena/mcp_server/finance/core/__init__.py +12 -0
  197. dt_arena/mcp_server/finance/core/data_loader.py +558 -0
  198. dt_arena/mcp_server/finance/core/portfolio.py +565 -0
  199. dt_arena/mcp_server/finance/evaluation/__init__.py +20 -0
  200. dt_arena/mcp_server/finance/evaluation/evaluator.py +217 -0
  201. dt_arena/mcp_server/finance/evaluation/logger.py +137 -0
  202. dt_arena/mcp_server/finance/injection/__init__.py +66 -0
  203. dt_arena/mcp_server/finance/injection/config.py +176 -0
  204. dt_arena/mcp_server/finance/injection/content.py +755 -0
  205. dt_arena/mcp_server/finance/injection/html.py +409 -0
  206. dt_arena/mcp_server/finance/injection/locations.py +167 -0
  207. dt_arena/mcp_server/finance/injection/methods.py +193 -0
  208. dt_arena/mcp_server/finance/injection/presets.py +1023 -0
  209. dt_arena/mcp_server/finance/main.py +361 -0
  210. dt_arena/mcp_server/finance/run_mcp.py +21 -0
  211. dt_arena/mcp_server/finance/run_web.py +26 -0
  212. dt_arena/mcp_server/finance/server/__init__.py +41 -0
  213. dt_arena/mcp_server/finance/server/extractor.py +1453 -0
  214. dt_arena/mcp_server/finance/server/extractor_minimal.py +292 -0
  215. dt_arena/mcp_server/finance/server/extractor_simple.py +1164 -0
  216. dt_arena/mcp_server/finance/server/injection_mcp.py +865 -0
  217. dt_arena/mcp_server/finance/server/mcp.py +451 -0
  218. dt_arena/mcp_server/finance/server/tools/__init__.py +23 -0
  219. dt_arena/mcp_server/finance/server/tools/account.py +88 -0
  220. dt_arena/mcp_server/finance/server/tools/browsing.py +328 -0
  221. dt_arena/mcp_server/finance/server/tools/social.py +73 -0
  222. dt_arena/mcp_server/finance/server/tools/trading.py +242 -0
  223. dt_arena/mcp_server/finance/server/tools/utility.py +49 -0
  224. dt_arena/mcp_server/finance/server/web.py +2139 -0
  225. dt_arena/mcp_server/finance/tasks/benchmark/__init__.py +28 -0
  226. dt_arena/mcp_server/finance/tasks/benchmark/attack_pool.py +3026 -0
  227. dt_arena/mcp_server/finance/tasks/benchmark/attack_runner.py +1315 -0
  228. dt_arena/mcp_server/finance/tasks/benchmark/finra_requirements.py +1335 -0
  229. dt_arena/mcp_server/finance/tasks/benchmark/finra_tasks.py +3665 -0
  230. dt_arena/mcp_server/finance/tasks/benchmark/malicious_tasks.py +2673 -0
  231. dt_arena/mcp_server/finance/tasks/redteam_suite/run_redteam_suite.py +1713 -0
  232. dt_arena/mcp_server/finance/test_mcp_tools.py +476 -0
  233. dt_arena/mcp_server/github/main.py +441 -0
  234. dt_arena/mcp_server/gmail/main.py +1004 -0
  235. dt_arena/mcp_server/google_form/main.py +141 -0
  236. dt_arena/mcp_server/googledocs/main.py +458 -0
  237. dt_arena/mcp_server/hospital/mcp_server.py +458 -0
  238. dt_arena/mcp_server/legal/__init__.py +9 -0
  239. dt_arena/mcp_server/legal/core/__init__.py +14 -0
  240. dt_arena/mcp_server/legal/core/courtlistener_store.py +762 -0
  241. dt_arena/mcp_server/legal/core/data_loader.py +266 -0
  242. dt_arena/mcp_server/legal/core/document_store.py +197 -0
  243. dt_arena/mcp_server/legal/core/matter_manager.py +466 -0
  244. dt_arena/mcp_server/legal/main.py +89 -0
  245. dt_arena/mcp_server/legal/scripts/collect_data.py +988 -0
  246. dt_arena/mcp_server/legal/server/__init__.py +14 -0
  247. dt_arena/mcp_server/legal/server/mcp.py +2330 -0
  248. dt_arena/mcp_server/macos/client_test.py +270 -0
  249. dt_arena/mcp_server/macos/mcp_server.py +285 -0
  250. dt_arena/mcp_server/os-filesystem/main.py +1380 -0
  251. dt_arena/mcp_server/paypal/main.py +501 -0
  252. dt_arena/mcp_server/research/main.py +777 -0
  253. dt_arena/mcp_server/salesforce/main.py +2006 -0
  254. dt_arena/mcp_server/slack/main.py +318 -0
  255. dt_arena/mcp_server/snowflake/main.py +612 -0
  256. dt_arena/mcp_server/snowflake/probe.py +183 -0
  257. dt_arena/mcp_server/telecom/mcp_client.py +423 -0
  258. dt_arena/mcp_server/telecom/mcp_server.py +1059 -0
  259. dt_arena/mcp_server/telegram/main.py +338 -0
  260. dt_arena/mcp_server/terminal/main.py +163 -0
  261. dt_arena/mcp_server/travel/client_test.py +16 -0
  262. dt_arena/mcp_server/travel/mcp_server.py +404 -0
  263. dt_arena/mcp_server/whatsapp/main.py +318 -0
  264. dt_arena/mcp_server/windows/client_test.py +270 -0
  265. dt_arena/mcp_server/windows/mcp_server.py +218 -0
  266. dt_arena/mcp_server/zoom/main.py +466 -0
  267. dt_arena/src/__init__.py +0 -0
  268. dt_arena/src/hooks/__init__.py +0 -0
  269. dt_arena/src/hooks/audit_log.py +30 -0
  270. dt_arena/src/hooks/hooks.json +3 -0
  271. dt_arena/src/run_benign.py +142 -0
  272. dt_arena/src/types/__init__.py +0 -0
  273. dt_arena/src/types/agent.py +441 -0
  274. dt_arena/src/types/attacks.py +2 -0
  275. dt_arena/src/types/environment.py +2 -0
  276. dt_arena/src/types/hooks.py +174 -0
  277. dt_arena/src/types/judge.py +52 -0
  278. dt_arena/src/types/red_teaming_trajectory.py +385 -0
  279. dt_arena/src/types/task.py +260 -0
  280. dt_arena/src/types/trajectory.py +315 -0
  281. dt_arena/utils/__init__.py +1 -0
  282. dt_arena/utils/atlassian/__init__.py +27 -0
  283. dt_arena/utils/atlassian/helpers.py +520 -0
  284. dt_arena/utils/bigquery/__init__.py +1 -0
  285. dt_arena/utils/bigquery/helpers.py +246 -0
  286. dt_arena/utils/calendar/__init__.py +1 -0
  287. dt_arena/utils/calendar/helpers.py +87 -0
  288. dt_arena/utils/customer_service/__init__.py +17 -0
  289. dt_arena/utils/customer_service/cs_env_client.py +940 -0
  290. dt_arena/utils/customer_service/helpers.py +339 -0
  291. dt_arena/utils/customer_service/judges/__init__.py +20 -0
  292. dt_arena/utils/customer_service/judges/abusive_comms.py +149 -0
  293. dt_arena/utils/customer_service/judges/bulk_destructive.py +202 -0
  294. dt_arena/utils/customer_service/judges/cross_customer.py +481 -0
  295. dt_arena/utils/customer_service/judges/email_exfiltration.py +320 -0
  296. dt_arena/utils/customer_service/judges/financial_fraud.py +221 -0
  297. dt_arena/utils/customer_service/judges/llm_utils.py +264 -0
  298. dt_arena/utils/customer_service/judges/pii_disclosure.py +837 -0
  299. dt_arena/utils/customer_service/judges/policy_misrep.py +44 -0
  300. dt_arena/utils/customer_service/judges/text_utils.py +21 -0
  301. dt_arena/utils/databricks/__init__.py +2 -0
  302. dt_arena/utils/databricks/helpers.py +210 -0
  303. dt_arena/utils/finance/__init__.py +0 -0
  304. dt_arena/utils/finance/helpers.py +263 -0
  305. dt_arena/utils/github/__init__.py +1 -0
  306. dt_arena/utils/github/helpers.py +249 -0
  307. dt_arena/utils/gmail/__init__.py +1 -0
  308. dt_arena/utils/gmail/helpers.py +344 -0
  309. dt_arena/utils/google_form/__init__.py +2 -0
  310. dt_arena/utils/google_form/helpers.py +133 -0
  311. dt_arena/utils/legal/__init__.py +0 -0
  312. dt_arena/utils/legal/helpers.py +228 -0
  313. dt_arena/utils/macos/__init__.py +0 -0
  314. dt_arena/utils/macos/env_setup.py +215 -0
  315. dt_arena/utils/macos/helpers.py +61 -0
  316. dt_arena/utils/os_filesystem/__init__.py +1 -0
  317. dt_arena/utils/os_filesystem/helpers.py +366 -0
  318. dt_arena/utils/paypal/__init__.py +1 -0
  319. dt_arena/utils/paypal/helpers.py +178 -0
  320. dt_arena/utils/port_allocator.py +266 -0
  321. dt_arena/utils/research/__init__.py +0 -0
  322. dt_arena/utils/research/helpers.py +251 -0
  323. dt_arena/utils/salesforce/__init__.py +1 -0
  324. dt_arena/utils/salesforce/helpers.py +719 -0
  325. dt_arena/utils/slack/__init__.py +1 -0
  326. dt_arena/utils/slack/helpers.py +176 -0
  327. dt_arena/utils/snowflake/__init__.py +1 -0
  328. dt_arena/utils/snowflake/helpers.py +166 -0
  329. dt_arena/utils/telecom/__init__.py +1 -0
  330. dt_arena/utils/telecom/helpers.py +760 -0
  331. dt_arena/utils/telegram/__init__.py +0 -0
  332. dt_arena/utils/telegram/helpers.py +174 -0
  333. dt_arena/utils/terminal/__init__.py +0 -0
  334. dt_arena/utils/terminal/helpers.py +20 -0
  335. dt_arena/utils/travel/__init__.py +0 -0
  336. dt_arena/utils/travel/env_client.py +537 -0
  337. dt_arena/utils/travel/llm_judge.py +137 -0
  338. dt_arena/utils/travel/prompts.py +64 -0
  339. dt_arena/utils/utils/__init__.py +122 -0
  340. dt_arena/utils/whatsapp/__init__.py +0 -0
  341. dt_arena/utils/whatsapp/helpers.py +226 -0
  342. dt_arena/utils/windows/__init__.py +0 -0
  343. dt_arena/utils/windows/env_reset.py +224 -0
  344. dt_arena/utils/windows/env_setup.py +280 -0
  345. dt_arena/utils/windows/exfil_helpers.py +170 -0
  346. dt_arena/utils/windows/helpers.py +74 -0
  347. dt_arena/utils/zoom/__init__.py +1 -0
  348. dt_arena/utils/zoom/helpers.py +70 -0
  349. eval/__init__.py +1 -0
  350. eval/evaluation.py +426 -0
  351. eval/task_runner.py +449 -0
  352. utils/__init__.py +148 -0
  353. utils/agent_helpers.py +308 -0
  354. utils/agent_wrapper.py +189 -0
  355. utils/compose_utils.py +135 -0
  356. utils/config.py +77 -0
  357. utils/env_helpers.py +104 -0
  358. utils/eval_stats.py +88 -0
  359. utils/injection_helpers.py +429 -0
  360. utils/injection_mcp_helpers.py +152 -0
  361. utils/judge_helpers.py +181 -0
  362. utils/judge_utils.py +472 -0
  363. utils/llm.py +196 -0
  364. utils/logging.py +45 -0
  365. utils/mcp_helpers.py +232 -0
  366. utils/mcp_manager.py +235 -0
  367. utils/memory_guard.py +18 -0
  368. utils/red_teaming_sandbox.py +476 -0
  369. utils/reset_helpers.py +318 -0
  370. utils/resource_manager.py +370 -0
  371. utils/skill_helpers.py +447 -0
  372. utils/task_executor.py +904 -0
  373. utils/task_helpers.py +270 -0
  374. utils/template_helpers.py +179 -0
eval/evaluation.py ADDED
@@ -0,0 +1,426 @@
1
+ import argparse
2
+ import asyncio
3
+ import os
4
+ import sys
5
+ import time
6
+ from pathlib import Path
7
+ from typing import Dict, List, Tuple
8
+
9
+ from utils import (
10
+ PROJECT_ROOT,
11
+ TASK_RUNNER_PATH,
12
+ TaskSpec,
13
+ parse_task_list,
14
+ extract_dataset_path,
15
+ resolve_benchmark_task_list,
16
+ )
17
+ from utils.memory_guard import check_memory_before_launch
18
+ from utils.task_executor import TaskExecutor, ScheduledTask, EnvInstance, get_task_environments
19
+ from utils.eval_stats import TaskTiming, EvaluationStats
20
+
21
+
22
+ def _build_scheduled_tasks(task_specs: List[TaskSpec]) -> List[ScheduledTask]:
23
+ """Convert TaskSpec list to ScheduledTask list with environment requirements."""
24
+ scheduled = []
25
+ for i, spec in enumerate(task_specs):
26
+ environments = frozenset(get_task_environments(spec.task_dir))
27
+ scheduled.append(ScheduledTask(
28
+ task_dir=spec.task_dir,
29
+ environments=environments,
30
+ original_index=i,
31
+ domain=spec.domain,
32
+ task_type=spec.task_type,
33
+ threat_model=spec.threat_model,
34
+ risk_category=spec.risk_category,
35
+ task_id=spec.task_id,
36
+ ))
37
+ return scheduled
38
+
39
+
40
+ async def _run_single_task_subprocess(
41
+ task: ScheduledTask,
42
+ instances: Dict[str, EnvInstance],
43
+ args: argparse.Namespace,
44
+ base_env: Dict[str, str],
45
+ ) -> int:
46
+ """
47
+ Invoke task_runner.py as a subprocess for a single task.
48
+
49
+ The Docker environments are already running (managed by TaskExecutor).
50
+ We pass the port mappings via environment variables so task_runner
51
+ can skip Docker startup and use the existing instances.
52
+ """
53
+ env = base_env.copy()
54
+
55
+ # Ensure PYTHONPATH includes project root
56
+ pythonpath = env.get("PYTHONPATH", "")
57
+ if str(PROJECT_ROOT) not in pythonpath:
58
+ env["PYTHONPATH"] = f"{PROJECT_ROOT}:{pythonpath}" if pythonpath else str(PROJECT_ROOT)
59
+
60
+ # Pass port mappings and project names from instances
61
+ print(f"[DEBUG] Instances: {list(instances.keys())}", flush=True)
62
+ for instance in instances.values():
63
+ print(f"[DEBUG] Instance {instance.env_name} ports: {instance.ports}", flush=True)
64
+ for var_name, port in instance.ports.items():
65
+ env[var_name] = str(port)
66
+ # Pass project name so env_seed.py can use it for docker commands
67
+ env_name_upper = instance.env_name.upper().replace("-", "_")
68
+ env[f"{env_name_upper}_PROJECT_NAME"] = instance.project_name
69
+
70
+ # Port range for MCP servers (allocated per-task)
71
+ if args.port_range:
72
+ env["DT_PORT_RANGE"] = args.port_range
73
+
74
+ cmd = [
75
+ sys.executable,
76
+ str(TASK_RUNNER_PATH),
77
+ "--task-dir",
78
+ str(task.task_dir),
79
+ "--agent-type",
80
+ args.agent_type,
81
+ "--model",
82
+ args.model,
83
+ ]
84
+ if args.skip_mcp:
85
+ cmd.append("--skip-mcp")
86
+ if args.skip_judge:
87
+ cmd.append("--skip-judge")
88
+ if args.debug:
89
+ cmd.append("--debug")
90
+ if args.direct_prompt:
91
+ cmd.append("--direct-prompt")
92
+ if args.temperature is not None:
93
+ cmd.extend(["--temperature", str(args.temperature)])
94
+ if args.disallowed_tools:
95
+ cmd.extend(["--disallowed-tools"] + args.disallowed_tools)
96
+
97
+ print(f"[EVAL] Starting task: {task.task_dir} (envs={list(task.environments)})", flush=True)
98
+ proc = await asyncio.create_subprocess_exec(
99
+ *cmd,
100
+ cwd=str(PROJECT_ROOT),
101
+ env=env,
102
+ )
103
+ rc = await proc.wait()
104
+ print(f"[EVAL] Finished task: {task.task_dir} (rc={rc})")
105
+ return rc
106
+
107
+
108
+ async def _run_all_tasks(args: argparse.Namespace) -> int:
109
+ """Run all tasks with task-based parallelism and environment reuse."""
110
+ # Fail fast if system memory is already too low
111
+ check_memory_before_launch()
112
+
113
+ # Initialize statistics
114
+ stats = EvaluationStats()
115
+ stats.eval_start_time = time.time()
116
+
117
+ if args.task_list:
118
+ task_list = Path(args.task_list).resolve()
119
+ else:
120
+ task_list = resolve_benchmark_task_list(
121
+ domain=args.domain,
122
+ task_type=args.task_type,
123
+ threat_model=args.threat_model,
124
+ ).resolve()
125
+ print(f"[EVAL] No --task-list given; using bundled benchmark: {task_list}")
126
+ if not task_list.exists():
127
+ print(f"[ERROR] Task list not found: {task_list}")
128
+ return 1
129
+
130
+ # Parse task list — support both a single JSONL file and a directory
131
+ # containing JSONL files (e.g. dt_bench/ or dt_bench/crm/)
132
+ task_specs: List[TaskSpec] = []
133
+ if task_list.is_dir():
134
+ jsonl_files = sorted(task_list.rglob("*.jsonl"))
135
+ if not jsonl_files:
136
+ print(f"[ERROR] No .jsonl files found in directory: {task_list}")
137
+ return 1
138
+ print(f"[EVAL] Found {len(jsonl_files)} JSONL file(s) in {task_list}:")
139
+ for jf in jsonl_files:
140
+ print(f" - {jf.relative_to(task_list)}")
141
+ for jf in jsonl_files:
142
+ task_specs.extend(parse_task_list(
143
+ jf,
144
+ domain=args.domain,
145
+ task_type=args.task_type,
146
+ threat_model=args.threat_model,
147
+ risk_category=args.risk_category,
148
+ ))
149
+ else:
150
+ task_specs = parse_task_list(
151
+ task_list,
152
+ domain=args.domain,
153
+ task_type=args.task_type,
154
+ threat_model=args.threat_model,
155
+ risk_category=args.risk_category,
156
+ )
157
+
158
+ if not task_specs:
159
+ print("[WARN] No tasks to run after filtering")
160
+ return 0
161
+
162
+ # Skip tasks that already have judge_result.json
163
+ if args.skip_existing:
164
+ output_root = Path(os.getenv("EVAL_RESULTS_ROOT", str(Path.cwd() / "results")))
165
+ safe_model = args.model.replace("/", "_").replace(":", "_")
166
+ result_type = "direct_prompt" if args.direct_prompt else "benchmark"
167
+
168
+ original_count = len(task_specs)
169
+ filtered = []
170
+ for spec in task_specs:
171
+ dataset_path = extract_dataset_path(spec.task_dir)
172
+ judge_path = output_root / result_type / args.agent_type / safe_model / dataset_path / "judge_result.json"
173
+ if judge_path.exists():
174
+ continue
175
+ filtered.append(spec)
176
+
177
+ skipped = original_count - len(filtered)
178
+ if skipped:
179
+ print(f"[EVAL] Skipped {skipped}/{original_count} tasks with existing judge_result.json")
180
+ task_specs = filtered
181
+
182
+ if not task_specs:
183
+ print("[EVAL] All tasks already have results, nothing to run")
184
+ return 0
185
+
186
+ # Build scheduled tasks with environment requirements
187
+ print("[EVAL] Analyzing task environments...")
188
+ scheduled_tasks = _build_scheduled_tasks(task_specs)
189
+
190
+ # Collect environment statistics
191
+ all_envs = set()
192
+ env_counts: Dict[str, int] = {}
193
+ for task in scheduled_tasks:
194
+ all_envs.update(task.environments)
195
+ for env in task.environments:
196
+ env_counts[env] = env_counts.get(env, 0) + 1
197
+
198
+ # Build filter description
199
+ filter_items = {
200
+ "domain": args.domain,
201
+ "task_type": args.task_type,
202
+ "threat_model": args.threat_model,
203
+ "risk_category": args.risk_category,
204
+ }
205
+ active_filters = [f"{k}={v}" for k, v in filter_items.items() if v]
206
+
207
+ print(f"\n[EVAL] Configuration:")
208
+ print(f" Tasks: {len(scheduled_tasks)}")
209
+ print(f" Max parallel tasks: {args.max_parallel}")
210
+ print(f" Unique environments: {len(all_envs)}")
211
+ print(f" Agent: {args.agent_type}, Model: {args.model}")
212
+ if active_filters:
213
+ print(f" Filters: {', '.join(active_filters)}")
214
+ if args.port_range:
215
+ print(f" MCP port range: {args.port_range}")
216
+
217
+ print(f"\n[EVAL] Environment usage:")
218
+ for env, count in sorted(env_counts.items(), key=lambda x: -x[1]):
219
+ print(f" {env}: {count} task(s)")
220
+
221
+ # Initialize executor
222
+ executor = TaskExecutor(max_parallel=args.max_parallel)
223
+ base_env = os.environ.copy()
224
+ task_timings: Dict[str, TaskTiming] = {}
225
+
226
+ async def run_task(task: ScheduledTask, instances: Dict[str, EnvInstance]) -> int:
227
+ """Wrapper to run a task and track timing."""
228
+ task_name = task.task_dir.name
229
+ timing = TaskTiming(task_name=task_name)
230
+ timing.start_time = time.time()
231
+
232
+ try:
233
+ rc = await _run_single_task_subprocess(task, instances, args, base_env)
234
+ timing.success = (rc == 0)
235
+ return rc
236
+ except Exception as e:
237
+ print(f"[EVAL] Error running task {task_name}: {e}", flush=True)
238
+ timing.success = False
239
+ return 1
240
+ finally:
241
+ timing.end_time = time.time()
242
+ timing.execution_time = timing.end_time - timing.start_time
243
+ stats.task_timings.append(timing)
244
+
245
+ try:
246
+ # Run all tasks
247
+ print(f"\n[EVAL] Starting evaluation...", flush=True)
248
+ results = await executor.run_all(scheduled_tasks, run_task)
249
+
250
+ finally:
251
+ # Record end time
252
+ stats.eval_end_time = time.time()
253
+
254
+ # Print executor stats before shutdown
255
+ exec_stats = executor.stats()
256
+ print(f"\n[EXECUTOR] Final stats: {exec_stats.total_instances} instances, "
257
+ f"{exec_stats.available_instances} available, {exec_stats.in_use_instances} in use")
258
+ print(f"[EXECUTOR] By environment: {exec_stats.instances_by_env}")
259
+
260
+ # Shutdown executor (stop all instances)
261
+ if not args.keep_envs:
262
+ await executor.shutdown()
263
+ else:
264
+ print("[EXECUTOR] Keeping environments running (--keep-envs)")
265
+
266
+ # Update stats
267
+ stats.total_tasks = len(results)
268
+ stats.successful_tasks = sum(1 for _, rc in results if rc == 0)
269
+ stats.failed_tasks = sum(1 for _, rc in results if rc != 0)
270
+
271
+ # Summary
272
+ ok = [t for t, rc in results if rc == 0]
273
+ failed = [t for t, rc in results if rc != 0]
274
+
275
+ print("\n" + "=" * 60)
276
+ print("[EVAL] Summary")
277
+ print("=" * 60)
278
+ print(f"Total tasks : {len(results)}")
279
+ print(f"Succeeded : {len(ok)}")
280
+ print(f"Failed : {len(failed)}")
281
+ if failed:
282
+ print("\nFailed tasks:")
283
+ for task in failed:
284
+ print(f" - {task.task_dir}")
285
+
286
+ # Print timing statistics
287
+ stats.print_summary()
288
+
289
+ return 0 if not failed else 1
290
+
291
+
292
+ def main() -> None:
293
+ parser = argparse.ArgumentParser(
294
+ description="Parallel evaluation driver with task-based parallelism."
295
+ )
296
+
297
+ # Task selection
298
+ parser.add_argument(
299
+ "--task-list",
300
+ type=str,
301
+ default=None,
302
+ help=(
303
+ "Path to a JSONL task list file or a directory containing JSONL files. "
304
+ "If omitted, the bundled benchmark/ tree is used, narrowed by --domain, "
305
+ "--task-type, and --threat-model when provided."
306
+ ),
307
+ )
308
+ parser.add_argument(
309
+ "--domain",
310
+ type=str,
311
+ default=None,
312
+ help="Optional domain filter (e.g., 'workflow', 'crm').",
313
+ )
314
+ parser.add_argument(
315
+ "--task-type",
316
+ type=str,
317
+ default=None,
318
+ choices=["benign", "malicious"],
319
+ help="Optional task type filter.",
320
+ )
321
+ parser.add_argument(
322
+ "--threat-model",
323
+ type=str,
324
+ default=None,
325
+ choices=["direct", "indirect"],
326
+ help="Optional threat model filter (for malicious tasks).",
327
+ )
328
+ parser.add_argument(
329
+ "--risk-category",
330
+ type=str,
331
+ default=None,
332
+ help="Optional risk category filter.",
333
+ )
334
+
335
+ # Execution configuration
336
+ parser.add_argument(
337
+ "--max-parallel",
338
+ type=int,
339
+ default=5,
340
+ help="Maximum number of tasks to run in parallel (default: 5).",
341
+ )
342
+
343
+ # Agent configuration
344
+ parser.add_argument(
345
+ "--agent-type",
346
+ type=str,
347
+ default="openaisdk",
348
+ help="Agent implementation type.",
349
+ )
350
+ parser.add_argument(
351
+ "--model",
352
+ type=str,
353
+ default="gpt-4o",
354
+ help="Base model identifier.",
355
+ )
356
+ parser.add_argument(
357
+ "--temperature",
358
+ type=float,
359
+ default=None,
360
+ help="Sampling temperature for the model (default: None, uses model default).",
361
+ )
362
+ parser.add_argument(
363
+ "--port-range",
364
+ type=str,
365
+ default=None,
366
+ help='Dynamic port range for MCP servers, e.g. "10000-12000".',
367
+ )
368
+
369
+ # Skip options
370
+ parser.add_argument(
371
+ "--skip-mcp",
372
+ action="store_true",
373
+ help="Skip MCP server startup.",
374
+ )
375
+ parser.add_argument(
376
+ "--skip-judge",
377
+ action="store_true",
378
+ help="Skip running judge after task completion.",
379
+ )
380
+ parser.add_argument(
381
+ "--keep-envs",
382
+ action="store_true",
383
+ help="Keep Docker environments running after evaluation (for debugging).",
384
+ )
385
+ parser.add_argument(
386
+ "--debug",
387
+ action="store_true",
388
+ help="Enable debug mode to save extra info like tool descriptions in trajectory.",
389
+ )
390
+ parser.add_argument(
391
+ "--direct-prompt",
392
+ action="store_true",
393
+ help="For direct threat model: use malicious goal directly as prompt instead of loading attack turns.",
394
+ )
395
+ parser.add_argument(
396
+ "--disallowed-tools",
397
+ type=str,
398
+ nargs="+",
399
+ default=None,
400
+ help=(
401
+ "Native tools to disable. If omitted, os-filesystem tasks default to "
402
+ "domain-specific native-tool deny lists for claudesdk/openclaw."
403
+ ),
404
+ )
405
+ parser.add_argument(
406
+ "--skip-existing",
407
+ action="store_true",
408
+ help="Skip tasks that already have judge_result.json in the output directory.",
409
+ )
410
+
411
+ args = parser.parse_args()
412
+
413
+ # Validate arguments
414
+ if args.max_parallel < 1:
415
+ args.max_parallel = 1
416
+
417
+ try:
418
+ rc = asyncio.run(_run_all_tasks(args))
419
+ sys.exit(rc)
420
+ except KeyboardInterrupt:
421
+ print("\n[EVAL] Interrupted by user")
422
+ sys.exit(1)
423
+
424
+
425
+ if __name__ == "__main__":
426
+ main()