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
@@ -0,0 +1,420 @@
1
+ import os
2
+ import json
3
+ import threading
4
+ from datetime import datetime, timezone
5
+ from typing import List, Dict, Any, Optional
6
+ from collections import defaultdict
7
+
8
+ from claude_code_sdk import (
9
+ Message,
10
+ UserMessage,
11
+ AssistantMessage,
12
+ ResultMessage,
13
+ SystemMessage,
14
+ TextBlock,
15
+ ToolUseBlock,
16
+ ToolResultBlock,
17
+ ThinkingBlock,
18
+ )
19
+
20
+ from dt_arena.src.types.trajectory import Trajectory
21
+
22
+
23
+ class ClaudeSDKTraceProcessor:
24
+ """
25
+ Local agent trace processor that captures Claude SDK messages and events.
26
+ """
27
+
28
+ def __init__(self, path: str):
29
+ self.path = path
30
+ self._lock = threading.Lock()
31
+
32
+ def _write(self, obj: Dict[str, Any]) -> None:
33
+ with self._lock:
34
+ try:
35
+ with open(self.path, "a", encoding="utf-8") as f:
36
+ f.write(json.dumps(obj, ensure_ascii=False, default=str) + "\n")
37
+ except Exception:
38
+ pass
39
+
40
+ def start_trace(self, trace_id: str, metadata: Dict[str, Any]) -> None:
41
+ """Start a new trace"""
42
+ self._write({
43
+ "record": "trace_start",
44
+ "trace_id": trace_id,
45
+ "metadata": metadata,
46
+ "ts": datetime.now(timezone.utc).isoformat(),
47
+ })
48
+
49
+ def record_user_input(self, trace_id: str, user_input: str) -> None:
50
+ """Record user input"""
51
+ self._write({
52
+ "record": "user_input",
53
+ "trace_id": trace_id,
54
+ "content": user_input,
55
+ "ts": datetime.now(timezone.utc).isoformat(),
56
+ })
57
+
58
+ def record_message(self, trace_id: str, message: Message) -> None:
59
+ """Record a Claude SDK message"""
60
+ message_data = self._serialize_message(message)
61
+ self._write({
62
+ "record": "message",
63
+ "trace_id": trace_id,
64
+ "message": message_data,
65
+ "ts": datetime.now(timezone.utc).isoformat(),
66
+ })
67
+
68
+ def _serialize_message(self, message: Message) -> Dict[str, Any]:
69
+ """Serialize a Claude SDK message to dict"""
70
+ if isinstance(message, UserMessage):
71
+ return {
72
+ "type": "user",
73
+ "content": self._serialize_content_blocks(message.content),
74
+ }
75
+ elif isinstance(message, AssistantMessage):
76
+ return {
77
+ "type": "assistant",
78
+ "content": self._serialize_content_blocks(message.content),
79
+ }
80
+ elif isinstance(message, SystemMessage):
81
+ return {
82
+ "type": "system",
83
+ "subtype": message.subtype if hasattr(message, 'subtype') else None,
84
+ "data": message.data if hasattr(message, 'data') else {},
85
+ }
86
+ elif isinstance(message, ResultMessage):
87
+ return {
88
+ "type": "result",
89
+ "subtype": message.subtype if hasattr(message, 'subtype') else None,
90
+ "cost_usd": message.cost_usd if hasattr(message, 'cost_usd') else None,
91
+ "duration_ms": message.duration_ms if hasattr(message, 'duration_ms') else None,
92
+ "duration_api_ms": message.duration_api_ms if hasattr(message, 'duration_api_ms') else None,
93
+ "is_error": message.is_error if hasattr(message, 'is_error') else False,
94
+ "total_cost_usd": message.total_cost_usd if hasattr(message, 'total_cost_usd') else None,
95
+ "result": message.result if hasattr(message, 'result') else None,
96
+ }
97
+ else:
98
+ # Handle unknown message types
99
+ return {
100
+ "type": "unknown",
101
+ "raw": str(message),
102
+ }
103
+
104
+ def _serialize_content_blocks(self, content: List[Any]) -> List[Dict[str, Any]]:
105
+ """Serialize content blocks to list of dicts"""
106
+ result = []
107
+ for block in content:
108
+ if isinstance(block, TextBlock):
109
+ result.append({
110
+ "type": "text",
111
+ "text": block.text,
112
+ })
113
+ elif isinstance(block, ToolUseBlock):
114
+ result.append({
115
+ "type": "tool_use",
116
+ "id": block.id if hasattr(block, 'id') else None,
117
+ "name": block.name, # Full name like mcp__salesforce__create_lead
118
+ "input": block.input if hasattr(block, 'input') else {},
119
+ })
120
+ elif isinstance(block, ToolResultBlock):
121
+ result.append({
122
+ "type": "tool_result",
123
+ "tool_use_id": block.tool_use_id if hasattr(block, 'tool_use_id') else None,
124
+ "content": block.content if hasattr(block, 'content') else None,
125
+ "is_error": block.is_error if hasattr(block, 'is_error') else False,
126
+ })
127
+ elif isinstance(block, ThinkingBlock):
128
+ result.append({
129
+ "type": "thinking",
130
+ "thinking": block.thinking if hasattr(block, 'thinking') else None,
131
+ })
132
+ else:
133
+ result.append({
134
+ "type": "unknown",
135
+ "raw": str(block),
136
+ })
137
+ return result
138
+
139
+ def record_error(self, trace_id: str, error: str) -> None:
140
+ """Record an error"""
141
+ self._write({
142
+ "record": "error",
143
+ "trace_id": trace_id,
144
+ "error": error,
145
+ "ts": datetime.now(timezone.utc).isoformat(),
146
+ })
147
+
148
+ def end_trace(self, trace_id: str) -> None:
149
+ """End a trace"""
150
+ self._write({
151
+ "record": "trace_end",
152
+ "trace_id": trace_id,
153
+ "ts": datetime.now(timezone.utc).isoformat(),
154
+ })
155
+
156
+
157
+ class ClaudeSDKTrajectoryConverter:
158
+ """Convert Claude SDK traces to standard trajectory format"""
159
+
160
+ def __init__(self, output_dir: str, timestamp: Optional[str] = None):
161
+ self.output_dir = output_dir
162
+ self.timestamp = timestamp
163
+ os.makedirs(self.output_dir, exist_ok=True)
164
+
165
+ def load_traces(self, trace_file: str) -> tuple:
166
+ """Load traces from file"""
167
+ if not os.path.exists(trace_file):
168
+ raise FileNotFoundError(f"Trace file not found: {trace_file}")
169
+
170
+ traces_by_id = defaultdict(list)
171
+ trace_metadata = {}
172
+ trace_timestamps = {}
173
+
174
+ with open(trace_file, 'r', encoding='utf-8') as f:
175
+ for line in f:
176
+ if not line.strip():
177
+ continue
178
+ data = json.loads(line)
179
+ trace_id = data.get("trace_id")
180
+
181
+ if data.get("record") == "trace_start":
182
+ trace_metadata[trace_id] = data.get("metadata", {})
183
+ trace_timestamps[trace_id] = {"start": data.get("ts")}
184
+
185
+ elif data.get("record") == "trace_end":
186
+ if trace_id in trace_timestamps:
187
+ trace_timestamps[trace_id]["end"] = data.get("ts")
188
+
189
+ elif data.get("record") in ("message", "user_input", "error"):
190
+ traces_by_id[trace_id].append(data)
191
+
192
+ return traces_by_id, trace_metadata, trace_timestamps
193
+
194
+ def _parse_tool_name(self, full_name: str) -> tuple:
195
+ """
196
+ Parse Claude SDK tool name format: mcp__server_name__tool_name
197
+
198
+ Returns:
199
+ tuple: (server_name, tool_name)
200
+ """
201
+ if full_name.startswith("mcp__"):
202
+ parts = full_name[5:].split("__", 1) # Remove "mcp__" prefix
203
+ if len(parts) == 2:
204
+ return parts[0], parts[1]
205
+ return "unknown", full_name
206
+
207
+ def _build_trajectory_steps(
208
+ self,
209
+ traj: Trajectory,
210
+ records: List[Dict],
211
+ ) -> None:
212
+ """Build trajectory steps from trace records"""
213
+
214
+ for record in records:
215
+ record_type = record.get("record")
216
+
217
+ if record_type == "user_input":
218
+ content = record.get("content", "")
219
+ traj.append_user_step(content)
220
+
221
+ elif record_type == "message":
222
+ message = record.get("message", {})
223
+ msg_type = message.get("type")
224
+
225
+ if msg_type == "assistant":
226
+ content_blocks = message.get("content", [])
227
+
228
+ for block in content_blocks:
229
+ block_type = block.get("type")
230
+
231
+ if block_type == "tool_use":
232
+ full_tool_name = block.get("name", "unknown")
233
+ tool_input = block.get("input", {})
234
+
235
+ # Parse server and tool name from full name
236
+ server_name, tool_name = self._parse_tool_name(full_tool_name)
237
+
238
+ # Build action string
239
+ action_str = f"{tool_name}("
240
+ params = []
241
+ for k, v in tool_input.items():
242
+ if isinstance(v, str):
243
+ params.append(f'{k}="{v}"')
244
+ else:
245
+ params.append(f'{k}={v}')
246
+ action_str += ", ".join(params) + ")"
247
+
248
+ traj.append_agent_step(
249
+ action=action_str,
250
+ tool_name=tool_name, # Store original tool name like create_lead
251
+ tool_params=tool_input,
252
+ server=server_name
253
+ )
254
+
255
+ elif block_type == "text":
256
+ text = block.get("text", "")
257
+ if text:
258
+ traj.append_agent_step(
259
+ action="send_message_to_user",
260
+ metadata={"message": text}
261
+ )
262
+ # Set final response in trajectory
263
+ traj.set_final_response(text)
264
+
265
+ elif msg_type == "user":
266
+ content_blocks = message.get("content", [])
267
+
268
+ for block in content_blocks:
269
+ block_type = block.get("type")
270
+
271
+ if block_type == "tool_result":
272
+ # Tool result follows tool use
273
+ content = block.get("content")
274
+ is_error = block.get("is_error", False)
275
+
276
+ # Parse the result content
277
+ result = self._parse_tool_result(content)
278
+
279
+ tool_name = "unknown"
280
+ server_name = "unknown"
281
+ if traj.data["trajectory"]:
282
+ last_step = traj.data["trajectory"][-1]
283
+ if last_step.get("role") == "agent":
284
+ tool_name = last_step.get("metadata", {}).get("tool_name", "unknown")
285
+ server_name = last_step.get("metadata", {}).get("server", "unknown")
286
+
287
+ traj.append_tool_return(
288
+ result=result if not is_error else {"error": result},
289
+ tool_name=tool_name,
290
+ server=server_name
291
+ )
292
+
293
+ def _parse_tool_result(self, content: Any) -> Any:
294
+ """Parse tool result content"""
295
+ if content is None:
296
+ return None
297
+
298
+ if isinstance(content, str):
299
+ try:
300
+ return json.loads(content)
301
+ except:
302
+ return content
303
+
304
+ if isinstance(content, list):
305
+ # Handle list of content blocks
306
+ texts = []
307
+ for item in content:
308
+ if isinstance(item, dict) and item.get("type") == "text":
309
+ text = item.get("text", "")
310
+ try:
311
+ texts.append(json.loads(text))
312
+ except:
313
+ texts.append(text)
314
+ else:
315
+ texts.append(item)
316
+ return texts[0] if len(texts) == 1 else texts
317
+
318
+ return content
319
+
320
+ def convert_trace_to_trajectory(
321
+ self,
322
+ trace_id: str,
323
+ records: List[Dict],
324
+ metadata: Dict,
325
+ timestamps: Dict,
326
+ task_id: Optional[str] = None,
327
+ ) -> Trajectory:
328
+ """Convert a single trace to trajectory format
329
+
330
+ Args:
331
+ trace_id: The trace ID
332
+ records: List of all records (user_input, message, error) in chronological order
333
+ metadata: Trace metadata from trace_start
334
+ timestamps: Dict with start and end timestamps
335
+ task_id: Optional task ID override
336
+
337
+ Returns:
338
+ Trajectory object
339
+ """
340
+ instruction = metadata.get("instruction", "No instruction provided")
341
+ malicious_instruction = metadata.get("malicious_goal", None)
342
+
343
+ # Create Trajectory instance
344
+ traj = Trajectory(
345
+ task_id=task_id or metadata.get("task_id", trace_id[:16]),
346
+ original_instruction=instruction,
347
+ malicious_instruction=malicious_instruction,
348
+ domain=metadata.get("domain"),
349
+ risk_category=metadata.get("category")
350
+ )
351
+
352
+ # Calculate duration
353
+ start_ts = timestamps.get("start")
354
+ end_ts = timestamps.get("end")
355
+ duration = 0.0
356
+
357
+ if start_ts and end_ts:
358
+ try:
359
+ start = datetime.fromisoformat(start_ts.replace('Z', '+00:00'))
360
+ end = datetime.fromisoformat(end_ts.replace('Z', '+00:00'))
361
+ duration = (end - start).total_seconds()
362
+ except:
363
+ pass
364
+
365
+ traj.data["traj_info"]["duration"] = round(duration, 3)
366
+
367
+ if end_ts:
368
+ traj.data["traj_info"]["timestamp"] = end_ts
369
+ elif start_ts:
370
+ traj.data["traj_info"]["timestamp"] = start_ts
371
+
372
+ traj.data["traj_info"]["metadata"] = {
373
+ "trace_id": trace_id
374
+ }
375
+
376
+ # Build trajectory steps
377
+ self._build_trajectory_steps(traj, records)
378
+
379
+ return traj
380
+
381
+ def process_trace_file(self, trace_file: str, output_name: Optional[str] = None) -> List[Trajectory]:
382
+ """Process trace file and generate trajectory files
383
+
384
+ Args:
385
+ trace_file: Path to the trace JSONL file
386
+ output_name: Optional name prefix for output files
387
+
388
+ Returns:
389
+ List of Trajectory objects
390
+ """
391
+ traces_by_id, trace_metadata, trace_timestamps = self.load_traces(trace_file)
392
+
393
+ trajectories = []
394
+
395
+ for i, (trace_id, records) in enumerate(traces_by_id.items()):
396
+ metadata = trace_metadata.get(trace_id, {})
397
+ timestamps = trace_timestamps.get(trace_id, {})
398
+ task_id = metadata.get("task_id")
399
+
400
+ traj = self.convert_trace_to_trajectory(
401
+ trace_id, records, metadata, timestamps, task_id
402
+ )
403
+
404
+ # Use timestamp for filename
405
+ if self.timestamp:
406
+ if len(traces_by_id) == 1:
407
+ filename = f"{self.timestamp}.json"
408
+ else:
409
+ filename = f"{self.timestamp}_{i}.json"
410
+ else:
411
+ filename = f"{task_id}_{trace_id}.json"
412
+
413
+ output_path = os.path.join(self.output_dir, filename)
414
+
415
+ with open(output_path, 'w', encoding='utf-8') as f:
416
+ json.dump(traj.to_dict(), f, indent=2, ensure_ascii=False)
417
+
418
+ trajectories.append(traj)
419
+
420
+ return trajectories
@@ -0,0 +1,15 @@
1
+ """
2
+ Google ADK Agent Implementation
3
+
4
+ This module provides an agent implementation using the Google ADK (Agent Development Kit)
5
+ with trajectory tracking and MCP server support.
6
+ """
7
+
8
+ from .src.agent import GoogleADKAgent
9
+ from .src.utils import GoogleADKTraceProcessor, GoogleADKTrajectoryConverter
10
+
11
+ __all__ = [
12
+ "GoogleADKAgent",
13
+ "GoogleADKTraceProcessor",
14
+ "GoogleADKTrajectoryConverter",
15
+ ]
@@ -0,0 +1,237 @@
1
+ import os
2
+ import sys
3
+ import asyncio
4
+ import argparse
5
+
6
+ from dt_arena.src.types.agent import AgentConfig, RuntimeConfig
7
+ from dt_arena.src.types.task import TaskConfig, AttackConfig
8
+
9
+ from agent.googleadk import GoogleADKAgent
10
+ from utils.injection_helpers import (
11
+ build_tool_injections_from_config,
12
+ build_skill_injections_from_config,
13
+ apply_prompt_injections,
14
+ )
15
+ from utils.task_helpers import extract_dataset_path
16
+
17
+
18
+ # ============================================================================
19
+ # Standalone Test Example for GoogleADKAgent
20
+ # ============================================================================
21
+
22
+
23
+ async def main():
24
+ """Example demonstrating Google ADK agent with MCP server and trajectory generation"""
25
+
26
+ parser = argparse.ArgumentParser(
27
+ description="Run Google ADK Agent with configuration file",
28
+ formatter_class=argparse.RawDescriptionHelpFormatter,
29
+ epilog="""
30
+ Examples:
31
+ # Run with default settings
32
+ python example.py --config path/to/config.yaml
33
+
34
+ # Run with custom model and temperature
35
+ python example.py --config path/to/config.yaml --model gemini-2.0-flash --temperature 0.5
36
+
37
+ # Run with custom max turns and output directory
38
+ python example.py --config path/to/config.yaml --max-turns 20 --output-dir ./custom_results
39
+
40
+ # Run with tool filter (only include specific tools)
41
+ python example.py --config path/to/config.yaml --tool-filter create_lead,search_leads,get_lead_status_options
42
+ """
43
+ )
44
+
45
+ parser.add_argument(
46
+ "--config",
47
+ type=str,
48
+ required=True,
49
+ help="Path to YAML configuration file (with Task, Agent, Attack sections)"
50
+ )
51
+ parser.add_argument(
52
+ "--model",
53
+ type=str,
54
+ default="gemini-2.0-flash",
55
+ help="Model to use (default: gemini-2.0-flash)"
56
+ )
57
+ parser.add_argument(
58
+ "--temperature",
59
+ type=float,
60
+ default=0.1,
61
+ help="Sampling temperature, 0.0-1.0 (default: 0.1)"
62
+ )
63
+ parser.add_argument(
64
+ "--max-turns",
65
+ type=int,
66
+ default=10,
67
+ help="Maximum conversation turns (default: 10)"
68
+ )
69
+ parser.add_argument(
70
+ "--output-dir",
71
+ type=str,
72
+ default=None,
73
+ help="Output directory for traces and trajectories (default: ./results)"
74
+ )
75
+ parser.add_argument(
76
+ "--tool-filter",
77
+ type=str,
78
+ default=None,
79
+ help="Comma-separated list of tool names to include (filter out others)"
80
+ )
81
+
82
+ args = parser.parse_args()
83
+
84
+ # Setup
85
+ config_path = args.config
86
+ if not os.path.exists(config_path):
87
+ print(f"[ERROR] Configuration file not found: {config_path}")
88
+ sys.exit(1)
89
+
90
+ # Extract dataset path structure
91
+ dataset_path = extract_dataset_path(config_path)
92
+
93
+ # Build output directory
94
+ base_output_dir = args.output_dir or os.path.join(os.getcwd(), "results")
95
+ output_dir = os.path.join(base_output_dir, "googleadk", dataset_path)
96
+ os.makedirs(output_dir, exist_ok=True)
97
+
98
+ # Parse tool filter
99
+ tool_filter = None
100
+ if args.tool_filter:
101
+ tool_filter = [t.strip() for t in args.tool_filter.split(",")]
102
+
103
+ print(f"[INFO] Loading configuration from: {config_path}")
104
+ print(f"[INFO] Model: {args.model}")
105
+ print(f"[INFO] Temperature: {args.temperature}")
106
+ print(f"[INFO] Max Turns: {args.max_turns}")
107
+ print(f"[INFO] Output Directory: {output_dir}")
108
+ if tool_filter:
109
+ print(f"[INFO] Tool Filter: {tool_filter}")
110
+ print("-" * 80)
111
+
112
+ try:
113
+ # Load configuration
114
+ task_config = TaskConfig.from_yaml(config_path)
115
+ agent_config = AgentConfig.from_yaml(config_path)
116
+ attack_config = AttackConfig.from_yaml(config_path)
117
+
118
+ # Build tool injections from attack config
119
+ mcp_injection = build_tool_injections_from_config(attack_config)
120
+
121
+ # Build skill injections from attack config
122
+ skill_injection = build_skill_injections_from_config(attack_config)
123
+
124
+ # Create runtime config (CLI args override YAML values)
125
+ runtime_config = RuntimeConfig(
126
+ model=args.model,
127
+ temperature=args.temperature,
128
+ max_turns=args.max_turns,
129
+ output_dir=output_dir,
130
+ mcp_injection=mcp_injection,
131
+ skill_injection=skill_injection,
132
+ )
133
+
134
+ # Create agent with configurations (task_config is passed to run() as metadata)
135
+ agent = GoogleADKAgent(
136
+ agent_config=agent_config,
137
+ runtime_config=runtime_config,
138
+ tool_filter=tool_filter
139
+ )
140
+
141
+ # Display loaded configuration
142
+ print(f"\n[TASK] Task ID: {task_config.task_id}")
143
+ print(f"[TASK] Domain: {task_config.domain}")
144
+
145
+ if attack_config:
146
+ print(f"\n[ATTACK] Risk Category: {attack_config.risk_category}")
147
+ print(f"[ATTACK] Threat Model: {attack_config.threat_model}")
148
+ if attack_config.malicious_goal:
149
+ print(f"[ATTACK] Malicious Goal: {attack_config.malicious_goal}")
150
+ if attack_config.attack_turns:
151
+ print(f"[ATTACK] Attack Turns: {len(attack_config.attack_turns)}")
152
+ for turn in attack_config.attack_turns:
153
+ print(f" Turn {turn.turn_id}: {len(turn.attack_steps)} attack step(s)")
154
+ for step in turn.attack_steps:
155
+ print(f" - {step.type} ({step.mode})")
156
+
157
+ # Handle prompt injections based on threat model
158
+ is_direct_attack = attack_config and attack_config.threat_model == "direct"
159
+
160
+ if is_direct_attack:
161
+ user_instruction = apply_prompt_injections(original_instruction=None, attack_config=attack_config)
162
+ if not user_instruction:
163
+ user_instruction = task_config.original_instruction
164
+ else:
165
+ user_instruction = task_config.original_instruction
166
+ user_instruction = apply_prompt_injections(user_instruction, attack_config)
167
+
168
+ # Normalize instruction
169
+ if isinstance(user_instruction, str):
170
+ user_instruction = user_instruction.strip()
171
+ else:
172
+ user_instruction = [instr.strip() for instr in user_instruction]
173
+
174
+ print("\n" + "=" * 80)
175
+ print("[INSTRUCTION (after injection)]")
176
+ print("=" * 80)
177
+ if isinstance(user_instruction, list):
178
+ print(f"Multi-turn task with {len(user_instruction)} queries:")
179
+ for i, instr in enumerate(user_instruction, 1):
180
+ print(f" {i}. {instr}")
181
+ else:
182
+ print(user_instruction)
183
+ print("=" * 80)
184
+
185
+ if attack_config and attack_config.malicious_goal:
186
+ print("\n[MALICIOUS GOAL] Testing Against:")
187
+ print("-" * 80)
188
+ print(attack_config.malicious_goal.strip())
189
+ print("-" * 80)
190
+
191
+ # Run agent with async context manager
192
+ async with agent:
193
+ print("\n[INFO] Running agent...")
194
+ if task_config.is_multi_turn:
195
+ print(f"[INFO] Processing {task_config.instruction_count} turns...")
196
+ # Pass task metadata via run() method
197
+ metadata = {
198
+ "task_id": task_config.task_id,
199
+ "domain": task_config.domain,
200
+ "category": attack_config.risk_category if attack_config else None,
201
+ "malicious_goal": attack_config.malicious_goal if attack_config else None,
202
+ }
203
+ result = await agent.run(user_instruction, metadata=metadata)
204
+
205
+ print("\n" + "=" * 80)
206
+ print("[AGENT RESPONSE]")
207
+ print("=" * 80)
208
+ print(result.final_output)
209
+ print("=" * 80)
210
+
211
+ print(f"\n[SUCCESS] Task completed")
212
+ print(f"[INFO] Turns: {result.turn_count}")
213
+ print(f"[INFO] Trace ID: {result.trace_id}")
214
+ print(f"[INFO] Traces saved to: {agent.traces_dir}")
215
+ print(f"[INFO] Trajectories saved to: {agent.trajectories_dir}")
216
+ if result.trajectory:
217
+ print(f"[INFO] Trajectory steps: {len(result.trajectory.data['trajectory'])}")
218
+
219
+ return result
220
+
221
+ except Exception as e:
222
+ print(f"\n[ERROR] {e}")
223
+ import traceback
224
+ traceback.print_exc()
225
+ sys.exit(1)
226
+
227
+
228
+ if __name__ == "__main__":
229
+ try:
230
+ result = asyncio.run(main())
231
+ if result:
232
+ print(f"\n[SUCCESS] Task completed")
233
+ except KeyboardInterrupt:
234
+ print("\n[INFO] Interrupted by user")
235
+ except Exception as e:
236
+ print(f"\n[ERROR] {e}")
237
+ sys.exit(1)
@@ -0,0 +1,12 @@
1
+ """
2
+ Google ADK Agent source modules
3
+ """
4
+
5
+ from .agent import GoogleADKAgent
6
+ from .utils import GoogleADKTraceProcessor, GoogleADKTrajectoryConverter
7
+
8
+ __all__ = [
9
+ "GoogleADKAgent",
10
+ "GoogleADKTraceProcessor",
11
+ "GoogleADKTrajectoryConverter",
12
+ ]