google-adk 0.0.1__py3-none-any.whl → 0.0.2__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 (312) hide show
  1. google/adk/__init__.py +20 -0
  2. google/adk/agents/__init__.py +32 -0
  3. google/adk/agents/active_streaming_tool.py +38 -0
  4. google/adk/agents/base_agent.py +345 -0
  5. google/adk/agents/callback_context.py +112 -0
  6. google/adk/agents/invocation_context.py +181 -0
  7. google/adk/agents/langgraph_agent.py +140 -0
  8. google/adk/agents/live_request_queue.py +64 -0
  9. google/adk/agents/llm_agent.py +376 -0
  10. google/adk/agents/loop_agent.py +62 -0
  11. google/adk/agents/parallel_agent.py +96 -0
  12. google/adk/agents/readonly_context.py +46 -0
  13. google/adk/agents/remote_agent.py +50 -0
  14. google/adk/agents/run_config.py +87 -0
  15. google/adk/agents/sequential_agent.py +45 -0
  16. google/adk/agents/transcription_entry.py +34 -0
  17. google/adk/artifacts/__init__.py +23 -0
  18. google/adk/artifacts/base_artifact_service.py +128 -0
  19. google/adk/artifacts/gcs_artifact_service.py +195 -0
  20. google/adk/artifacts/in_memory_artifact_service.py +133 -0
  21. google/adk/auth/__init__.py +22 -0
  22. google/adk/auth/auth_credential.py +220 -0
  23. google/adk/auth/auth_handler.py +268 -0
  24. google/adk/auth/auth_preprocessor.py +116 -0
  25. google/adk/auth/auth_schemes.py +67 -0
  26. google/adk/auth/auth_tool.py +55 -0
  27. google/adk/cli/__init__.py +15 -0
  28. google/adk/cli/__main__.py +18 -0
  29. google/adk/cli/agent_graph.py +122 -0
  30. google/adk/cli/browser/adk_favicon.svg +17 -0
  31. google/adk/cli/browser/assets/audio-processor.js +51 -0
  32. google/adk/cli/browser/assets/config/runtime-config.json +3 -0
  33. google/adk/cli/browser/index.html +33 -0
  34. google/adk/cli/browser/main-XUU6OGCC.js +75 -0
  35. google/adk/cli/browser/polyfills-FFHMD2TL.js +18 -0
  36. google/adk/cli/browser/styles-4VDSPQ37.css +17 -0
  37. google/adk/cli/cli.py +181 -0
  38. google/adk/cli/cli_deploy.py +181 -0
  39. google/adk/cli/cli_eval.py +282 -0
  40. google/adk/cli/cli_tools_click.py +479 -0
  41. google/adk/cli/fast_api.py +774 -0
  42. google/adk/cli/media_streamer/__init__.py +19 -0
  43. google/adk/cli/media_streamer/index.html +228 -0
  44. google/adk/cli/utils/__init__.py +49 -0
  45. google/adk/cli/utils/envs.py +57 -0
  46. google/adk/cli/utils/evals.py +93 -0
  47. google/adk/cli/utils/logs.py +72 -0
  48. google/adk/code_executors/__init__.py +49 -0
  49. google/adk/code_executors/base_code_executor.py +97 -0
  50. google/adk/code_executors/code_execution_utils.py +256 -0
  51. google/adk/code_executors/code_executor_context.py +202 -0
  52. google/adk/code_executors/container_code_executor.py +196 -0
  53. google/adk/code_executors/unsafe_local_code_executor.py +71 -0
  54. google/adk/code_executors/vertex_ai_code_executor.py +234 -0
  55. google/adk/evaluation/__init__.py +31 -0
  56. google/adk/evaluation/agent_evaluator.py +329 -0
  57. google/adk/evaluation/evaluation_constants.py +24 -0
  58. google/adk/evaluation/evaluation_generator.py +270 -0
  59. google/adk/evaluation/response_evaluator.py +135 -0
  60. google/adk/evaluation/trajectory_evaluator.py +184 -0
  61. google/adk/events/__init__.py +21 -0
  62. google/adk/events/event.py +130 -0
  63. google/adk/events/event_actions.py +55 -0
  64. google/adk/examples/__init__.py +28 -0
  65. google/adk/examples/base_example_provider.py +35 -0
  66. google/adk/examples/example.py +27 -0
  67. google/adk/examples/example_util.py +123 -0
  68. google/adk/examples/vertex_ai_example_store.py +104 -0
  69. google/adk/flows/__init__.py +14 -0
  70. google/adk/flows/llm_flows/__init__.py +20 -0
  71. google/adk/flows/llm_flows/_base_llm_processor.py +52 -0
  72. google/adk/flows/llm_flows/_code_execution.py +458 -0
  73. google/adk/flows/llm_flows/_nl_planning.py +129 -0
  74. google/adk/flows/llm_flows/agent_transfer.py +132 -0
  75. google/adk/flows/llm_flows/audio_transcriber.py +109 -0
  76. google/adk/flows/llm_flows/auto_flow.py +49 -0
  77. google/adk/flows/llm_flows/base_llm_flow.py +559 -0
  78. google/adk/flows/llm_flows/basic.py +72 -0
  79. google/adk/flows/llm_flows/contents.py +370 -0
  80. google/adk/flows/llm_flows/functions.py +486 -0
  81. google/adk/flows/llm_flows/identity.py +47 -0
  82. google/adk/flows/llm_flows/instructions.py +137 -0
  83. google/adk/flows/llm_flows/single_flow.py +57 -0
  84. google/adk/memory/__init__.py +35 -0
  85. google/adk/memory/base_memory_service.py +74 -0
  86. google/adk/memory/in_memory_memory_service.py +62 -0
  87. google/adk/memory/vertex_ai_rag_memory_service.py +177 -0
  88. google/adk/models/__init__.py +31 -0
  89. google/adk/models/anthropic_llm.py +243 -0
  90. google/adk/models/base_llm.py +87 -0
  91. google/adk/models/base_llm_connection.py +76 -0
  92. google/adk/models/gemini_llm_connection.py +200 -0
  93. google/adk/models/google_llm.py +331 -0
  94. google/adk/models/lite_llm.py +673 -0
  95. google/adk/models/llm_request.py +98 -0
  96. google/adk/models/llm_response.py +111 -0
  97. google/adk/models/registry.py +102 -0
  98. google/adk/planners/__init__.py +23 -0
  99. google/adk/planners/base_planner.py +66 -0
  100. google/adk/planners/built_in_planner.py +75 -0
  101. google/adk/planners/plan_re_act_planner.py +208 -0
  102. google/adk/runners.py +456 -0
  103. google/adk/sessions/__init__.py +41 -0
  104. google/adk/sessions/base_session_service.py +133 -0
  105. google/adk/sessions/database_session_service.py +522 -0
  106. google/adk/sessions/in_memory_session_service.py +206 -0
  107. google/adk/sessions/session.py +54 -0
  108. google/adk/sessions/state.py +71 -0
  109. google/adk/sessions/vertex_ai_session_service.py +356 -0
  110. google/adk/telemetry.py +189 -0
  111. google/adk/tests/__init__.py +14 -0
  112. google/adk/tests/integration/.env.example +10 -0
  113. google/adk/tests/integration/__init__.py +18 -0
  114. google/adk/tests/integration/conftest.py +119 -0
  115. google/adk/tests/integration/fixture/__init__.py +14 -0
  116. google/adk/tests/integration/fixture/agent_with_config/__init__.py +15 -0
  117. google/adk/tests/integration/fixture/agent_with_config/agent.py +88 -0
  118. google/adk/tests/integration/fixture/callback_agent/__init__.py +15 -0
  119. google/adk/tests/integration/fixture/callback_agent/agent.py +105 -0
  120. google/adk/tests/integration/fixture/context_update_test/OWNERS +1 -0
  121. google/adk/tests/integration/fixture/context_update_test/__init__.py +15 -0
  122. google/adk/tests/integration/fixture/context_update_test/agent.py +43 -0
  123. google/adk/tests/integration/fixture/context_update_test/successful_test.session.json +582 -0
  124. google/adk/tests/integration/fixture/context_variable_agent/__init__.py +15 -0
  125. google/adk/tests/integration/fixture/context_variable_agent/agent.py +115 -0
  126. google/adk/tests/integration/fixture/customer_support_ma/__init__.py +15 -0
  127. google/adk/tests/integration/fixture/customer_support_ma/agent.py +172 -0
  128. google/adk/tests/integration/fixture/ecommerce_customer_service_agent/__init__.py +15 -0
  129. google/adk/tests/integration/fixture/ecommerce_customer_service_agent/agent.py +338 -0
  130. google/adk/tests/integration/fixture/ecommerce_customer_service_agent/order_query.test.json +69 -0
  131. google/adk/tests/integration/fixture/ecommerce_customer_service_agent/test_config.json +6 -0
  132. google/adk/tests/integration/fixture/flow_complex_spark/__init__.py +15 -0
  133. google/adk/tests/integration/fixture/flow_complex_spark/agent.py +182 -0
  134. google/adk/tests/integration/fixture/flow_complex_spark/sample.debug.log +243 -0
  135. google/adk/tests/integration/fixture/flow_complex_spark/sample.session.json +190 -0
  136. google/adk/tests/integration/fixture/hello_world_agent/__init__.py +15 -0
  137. google/adk/tests/integration/fixture/hello_world_agent/agent.py +95 -0
  138. google/adk/tests/integration/fixture/hello_world_agent/roll_die.test.json +24 -0
  139. google/adk/tests/integration/fixture/hello_world_agent/test_config.json +6 -0
  140. google/adk/tests/integration/fixture/home_automation_agent/__init__.py +15 -0
  141. google/adk/tests/integration/fixture/home_automation_agent/agent.py +304 -0
  142. google/adk/tests/integration/fixture/home_automation_agent/simple_test.test.json +5 -0
  143. google/adk/tests/integration/fixture/home_automation_agent/simple_test2.test.json +5 -0
  144. google/adk/tests/integration/fixture/home_automation_agent/test_config.json +5 -0
  145. google/adk/tests/integration/fixture/home_automation_agent/test_files/dependent_tool_calls.test.json +18 -0
  146. google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/eval_data.test.json +17 -0
  147. google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/test_config.json +6 -0
  148. google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_multi_turn_conversation.test.json +18 -0
  149. google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test.test.json +17 -0
  150. google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test2.test.json +5 -0
  151. google/adk/tests/integration/fixture/home_automation_agent/test_files/test_config.json +5 -0
  152. google/adk/tests/integration/fixture/tool_agent/__init__.py +15 -0
  153. google/adk/tests/integration/fixture/tool_agent/agent.py +218 -0
  154. google/adk/tests/integration/fixture/tool_agent/files/Agent_test_plan.pdf +0 -0
  155. google/adk/tests/integration/fixture/trip_planner_agent/__init__.py +15 -0
  156. google/adk/tests/integration/fixture/trip_planner_agent/agent.py +110 -0
  157. google/adk/tests/integration/fixture/trip_planner_agent/initial.session.json +13 -0
  158. google/adk/tests/integration/fixture/trip_planner_agent/test_config.json +5 -0
  159. google/adk/tests/integration/fixture/trip_planner_agent/test_files/initial.session.json +13 -0
  160. google/adk/tests/integration/fixture/trip_planner_agent/test_files/test_config.json +5 -0
  161. google/adk/tests/integration/fixture/trip_planner_agent/test_files/trip_inquiry_sub_agent.test.json +7 -0
  162. google/adk/tests/integration/fixture/trip_planner_agent/trip_inquiry.test.json +19 -0
  163. google/adk/tests/integration/models/__init__.py +14 -0
  164. google/adk/tests/integration/models/test_google_llm.py +65 -0
  165. google/adk/tests/integration/test_callback.py +70 -0
  166. google/adk/tests/integration/test_context_variable.py +67 -0
  167. google/adk/tests/integration/test_evalute_agent_in_fixture.py +76 -0
  168. google/adk/tests/integration/test_multi_agent.py +28 -0
  169. google/adk/tests/integration/test_multi_turn.py +42 -0
  170. google/adk/tests/integration/test_single_agent.py +23 -0
  171. google/adk/tests/integration/test_sub_agent.py +26 -0
  172. google/adk/tests/integration/test_system_instruction.py +177 -0
  173. google/adk/tests/integration/test_tools.py +287 -0
  174. google/adk/tests/integration/test_with_test_file.py +34 -0
  175. google/adk/tests/integration/tools/__init__.py +14 -0
  176. google/adk/tests/integration/utils/__init__.py +16 -0
  177. google/adk/tests/integration/utils/asserts.py +75 -0
  178. google/adk/tests/integration/utils/test_runner.py +97 -0
  179. google/adk/tests/unittests/__init__.py +14 -0
  180. google/adk/tests/unittests/agents/__init__.py +14 -0
  181. google/adk/tests/unittests/agents/test_base_agent.py +407 -0
  182. google/adk/tests/unittests/agents/test_langgraph_agent.py +191 -0
  183. google/adk/tests/unittests/agents/test_llm_agent_callbacks.py +138 -0
  184. google/adk/tests/unittests/agents/test_llm_agent_fields.py +231 -0
  185. google/adk/tests/unittests/agents/test_loop_agent.py +136 -0
  186. google/adk/tests/unittests/agents/test_parallel_agent.py +92 -0
  187. google/adk/tests/unittests/agents/test_sequential_agent.py +114 -0
  188. google/adk/tests/unittests/artifacts/__init__.py +14 -0
  189. google/adk/tests/unittests/artifacts/test_artifact_service.py +276 -0
  190. google/adk/tests/unittests/auth/test_auth_handler.py +575 -0
  191. google/adk/tests/unittests/conftest.py +73 -0
  192. google/adk/tests/unittests/fast_api/__init__.py +14 -0
  193. google/adk/tests/unittests/fast_api/test_fast_api.py +269 -0
  194. google/adk/tests/unittests/flows/__init__.py +14 -0
  195. google/adk/tests/unittests/flows/llm_flows/__init__.py +14 -0
  196. google/adk/tests/unittests/flows/llm_flows/_test_examples.py +142 -0
  197. google/adk/tests/unittests/flows/llm_flows/test_agent_transfer.py +311 -0
  198. google/adk/tests/unittests/flows/llm_flows/test_functions_long_running.py +244 -0
  199. google/adk/tests/unittests/flows/llm_flows/test_functions_request_euc.py +346 -0
  200. google/adk/tests/unittests/flows/llm_flows/test_functions_sequential.py +93 -0
  201. google/adk/tests/unittests/flows/llm_flows/test_functions_simple.py +258 -0
  202. google/adk/tests/unittests/flows/llm_flows/test_identity.py +66 -0
  203. google/adk/tests/unittests/flows/llm_flows/test_instructions.py +164 -0
  204. google/adk/tests/unittests/flows/llm_flows/test_model_callbacks.py +142 -0
  205. google/adk/tests/unittests/flows/llm_flows/test_other_configs.py +46 -0
  206. google/adk/tests/unittests/flows/llm_flows/test_tool_callbacks.py +269 -0
  207. google/adk/tests/unittests/models/__init__.py +14 -0
  208. google/adk/tests/unittests/models/test_google_llm.py +224 -0
  209. google/adk/tests/unittests/models/test_litellm.py +804 -0
  210. google/adk/tests/unittests/models/test_models.py +60 -0
  211. google/adk/tests/unittests/sessions/__init__.py +14 -0
  212. google/adk/tests/unittests/sessions/test_session_service.py +227 -0
  213. google/adk/tests/unittests/sessions/test_vertex_ai_session_service.py +246 -0
  214. google/adk/tests/unittests/streaming/__init__.py +14 -0
  215. google/adk/tests/unittests/streaming/test_streaming.py +50 -0
  216. google/adk/tests/unittests/tools/__init__.py +14 -0
  217. google/adk/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py +499 -0
  218. google/adk/tests/unittests/tools/apihub_tool/test_apihub_toolset.py +204 -0
  219. google/adk/tests/unittests/tools/application_integration_tool/clients/test_connections_client.py +600 -0
  220. google/adk/tests/unittests/tools/application_integration_tool/clients/test_integration_client.py +630 -0
  221. google/adk/tests/unittests/tools/application_integration_tool/test_application_integration_toolset.py +345 -0
  222. google/adk/tests/unittests/tools/google_api_tool/__init__.py +13 -0
  223. google/adk/tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py +657 -0
  224. google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_auto_auth_credential_exchanger.py +145 -0
  225. google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_base_auth_credential_exchanger.py +68 -0
  226. google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_oauth2_exchanger.py +153 -0
  227. google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_service_account_exchanger.py +196 -0
  228. google/adk/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py +573 -0
  229. google/adk/tests/unittests/tools/openapi_tool/common/test_common.py +436 -0
  230. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test.yaml +1367 -0
  231. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py +628 -0
  232. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py +139 -0
  233. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_operation_parser.py +406 -0
  234. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py +966 -0
  235. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_tool_auth_handler.py +201 -0
  236. google/adk/tests/unittests/tools/retrieval/__init__.py +14 -0
  237. google/adk/tests/unittests/tools/retrieval/test_vertex_ai_rag_retrieval.py +147 -0
  238. google/adk/tests/unittests/tools/test_agent_tool.py +167 -0
  239. google/adk/tests/unittests/tools/test_base_tool.py +141 -0
  240. google/adk/tests/unittests/tools/test_build_function_declaration.py +277 -0
  241. google/adk/tests/unittests/utils.py +304 -0
  242. google/adk/tools/__init__.py +51 -0
  243. google/adk/tools/_automatic_function_calling_util.py +346 -0
  244. google/adk/tools/agent_tool.py +176 -0
  245. google/adk/tools/apihub_tool/__init__.py +19 -0
  246. google/adk/tools/apihub_tool/apihub_toolset.py +209 -0
  247. google/adk/tools/apihub_tool/clients/__init__.py +13 -0
  248. google/adk/tools/apihub_tool/clients/apihub_client.py +332 -0
  249. google/adk/tools/apihub_tool/clients/secret_client.py +115 -0
  250. google/adk/tools/application_integration_tool/__init__.py +19 -0
  251. google/adk/tools/application_integration_tool/application_integration_toolset.py +230 -0
  252. google/adk/tools/application_integration_tool/clients/connections_client.py +903 -0
  253. google/adk/tools/application_integration_tool/clients/integration_client.py +253 -0
  254. google/adk/tools/base_tool.py +144 -0
  255. google/adk/tools/built_in_code_execution_tool.py +59 -0
  256. google/adk/tools/crewai_tool.py +72 -0
  257. google/adk/tools/example_tool.py +62 -0
  258. google/adk/tools/exit_loop_tool.py +23 -0
  259. google/adk/tools/function_parameter_parse_util.py +307 -0
  260. google/adk/tools/function_tool.py +87 -0
  261. google/adk/tools/get_user_choice_tool.py +28 -0
  262. google/adk/tools/google_api_tool/__init__.py +14 -0
  263. google/adk/tools/google_api_tool/google_api_tool.py +59 -0
  264. google/adk/tools/google_api_tool/google_api_tool_set.py +107 -0
  265. google/adk/tools/google_api_tool/google_api_tool_sets.py +55 -0
  266. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +521 -0
  267. google/adk/tools/google_search_tool.py +68 -0
  268. google/adk/tools/langchain_tool.py +86 -0
  269. google/adk/tools/load_artifacts_tool.py +113 -0
  270. google/adk/tools/load_memory_tool.py +58 -0
  271. google/adk/tools/load_web_page.py +41 -0
  272. google/adk/tools/long_running_tool.py +39 -0
  273. google/adk/tools/mcp_tool/__init__.py +42 -0
  274. google/adk/tools/mcp_tool/conversion_utils.py +161 -0
  275. google/adk/tools/mcp_tool/mcp_tool.py +113 -0
  276. google/adk/tools/mcp_tool/mcp_toolset.py +272 -0
  277. google/adk/tools/openapi_tool/__init__.py +21 -0
  278. google/adk/tools/openapi_tool/auth/__init__.py +19 -0
  279. google/adk/tools/openapi_tool/auth/auth_helpers.py +498 -0
  280. google/adk/tools/openapi_tool/auth/credential_exchangers/__init__.py +25 -0
  281. google/adk/tools/openapi_tool/auth/credential_exchangers/auto_auth_credential_exchanger.py +105 -0
  282. google/adk/tools/openapi_tool/auth/credential_exchangers/base_credential_exchanger.py +55 -0
  283. google/adk/tools/openapi_tool/auth/credential_exchangers/oauth2_exchanger.py +117 -0
  284. google/adk/tools/openapi_tool/auth/credential_exchangers/service_account_exchanger.py +97 -0
  285. google/adk/tools/openapi_tool/common/__init__.py +19 -0
  286. google/adk/tools/openapi_tool/common/common.py +300 -0
  287. google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +32 -0
  288. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py +231 -0
  289. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +144 -0
  290. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +260 -0
  291. google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +496 -0
  292. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +268 -0
  293. google/adk/tools/preload_memory_tool.py +72 -0
  294. google/adk/tools/retrieval/__init__.py +36 -0
  295. google/adk/tools/retrieval/base_retrieval_tool.py +37 -0
  296. google/adk/tools/retrieval/files_retrieval.py +33 -0
  297. google/adk/tools/retrieval/llama_index_retrieval.py +41 -0
  298. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +107 -0
  299. google/adk/tools/tool_context.py +90 -0
  300. google/adk/tools/toolbox_tool.py +46 -0
  301. google/adk/tools/transfer_to_agent_tool.py +21 -0
  302. google/adk/tools/vertex_ai_search_tool.py +96 -0
  303. google/adk/version.py +16 -0
  304. google_adk-0.0.1.dist-info/LICENSE.txt → google_adk-0.0.2.dist-info/LICENSE +32 -0
  305. google_adk-0.0.2.dist-info/METADATA +73 -0
  306. google_adk-0.0.2.dist-info/RECORD +308 -0
  307. {google_adk-0.0.1.dist-info → google_adk-0.0.2.dist-info}/WHEEL +1 -2
  308. google_adk-0.0.2.dist-info/entry_points.txt +3 -0
  309. agent_kit/__init__.py +0 -0
  310. google_adk-0.0.1.dist-info/METADATA +0 -15
  311. google_adk-0.0.1.dist-info/RECORD +0 -6
  312. google_adk-0.0.1.dist-info/top_level.txt +0 -1
@@ -0,0 +1,231 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import copy
16
+ from typing import Any
17
+ from typing import Dict
18
+ from typing import List
19
+ from typing import Optional
20
+
21
+ from fastapi.openapi.models import Operation
22
+ from pydantic import BaseModel
23
+
24
+ from ....auth.auth_credential import AuthCredential
25
+ from ....auth.auth_schemes import AuthScheme
26
+ from ..common.common import ApiParameter
27
+ from ..common.common import to_snake_case
28
+ from .operation_parser import OperationParser
29
+
30
+
31
+ class OperationEndpoint(BaseModel):
32
+ base_url: str
33
+ path: str
34
+ method: str
35
+
36
+
37
+ class ParsedOperation(BaseModel):
38
+ name: str
39
+ description: str
40
+ endpoint: OperationEndpoint
41
+ operation: Operation
42
+ parameters: List[ApiParameter]
43
+ return_value: ApiParameter
44
+ auth_scheme: Optional[AuthScheme] = None
45
+ auth_credential: Optional[AuthCredential] = None
46
+ additional_context: Optional[Any] = None
47
+
48
+
49
+ class OpenApiSpecParser:
50
+ """Generates Python code, JSON schema, and callables for an OpenAPI operation.
51
+
52
+ This class takes an OpenApiOperation object and provides methods to generate:
53
+ 1. A string representation of a Python function that handles the operation.
54
+ 2. A JSON schema representing the input parameters of the operation.
55
+ 3. A callable Python object (a function) that can execute the operation.
56
+ """
57
+
58
+ def parse(self, openapi_spec_dict: Dict[str, Any]) -> List[ParsedOperation]:
59
+ """Extracts an OpenAPI spec dict into a list of ParsedOperation objects.
60
+
61
+ ParsedOperation objects are further used for generating RestApiTool.
62
+
63
+ Args:
64
+ openapi_spec_dict: A dictionary representing the OpenAPI specification.
65
+
66
+ Returns:
67
+ A list of ParsedOperation objects.
68
+ """
69
+
70
+ openapi_spec_dict = self._resolve_references(openapi_spec_dict)
71
+ operations = self._collect_operations(openapi_spec_dict)
72
+ return operations
73
+
74
+ def _collect_operations(
75
+ self, openapi_spec: Dict[str, Any]
76
+ ) -> List[ParsedOperation]:
77
+ """Collects operations from an OpenAPI spec."""
78
+ operations = []
79
+
80
+ # Taking first server url, or default to empty string if not present
81
+ base_url = ""
82
+ if openapi_spec.get("servers"):
83
+ base_url = openapi_spec["servers"][0].get("url", "")
84
+
85
+ # Get global security scheme (if any)
86
+ global_scheme_name = None
87
+ if openapi_spec.get("security"):
88
+ # Use first scheme by default.
89
+ scheme_names = list(openapi_spec["security"][0].keys())
90
+ global_scheme_name = scheme_names[0] if scheme_names else None
91
+
92
+ auth_schemes = openapi_spec.get("components", {}).get("securitySchemes", {})
93
+
94
+ for path, path_item in openapi_spec.get("paths", {}).items():
95
+ if path_item is None:
96
+ continue
97
+
98
+ for method in (
99
+ "get",
100
+ "post",
101
+ "put",
102
+ "delete",
103
+ "patch",
104
+ "head",
105
+ "options",
106
+ "trace",
107
+ ):
108
+ operation_dict = path_item.get(method)
109
+ if operation_dict is None:
110
+ continue
111
+
112
+ # If operation ID is missing, assign an operation id based on path
113
+ # and method
114
+ if "operationId" not in operation_dict:
115
+ temp_id = to_snake_case(f"{path}_{method}")
116
+ operation_dict["operationId"] = temp_id
117
+
118
+ url = OperationEndpoint(base_url=base_url, path=path, method=method)
119
+ operation = Operation.model_validate(operation_dict)
120
+ operation_parser = OperationParser(operation)
121
+
122
+ # Check for operation-specific auth scheme
123
+ auth_scheme_name = operation_parser.get_auth_scheme_name()
124
+ auth_scheme_name = (
125
+ auth_scheme_name if auth_scheme_name else global_scheme_name
126
+ )
127
+ auth_scheme = (
128
+ auth_schemes.get(auth_scheme_name) if auth_scheme_name else None
129
+ )
130
+
131
+ parsed_op = ParsedOperation(
132
+ name=operation_parser.get_function_name(),
133
+ description=operation.description or operation.summary or "",
134
+ endpoint=url,
135
+ operation=operation,
136
+ parameters=operation_parser.get_parameters(),
137
+ return_value=operation_parser.get_return_value(),
138
+ auth_scheme=auth_scheme,
139
+ auth_credential=None, # Placeholder
140
+ additional_context={},
141
+ )
142
+ operations.append(parsed_op)
143
+
144
+ return operations
145
+
146
+ def _resolve_references(self, openapi_spec: Dict[str, Any]) -> Dict[str, Any]:
147
+ """Recursively resolves all $ref references in an OpenAPI specification.
148
+
149
+ Handles circular references correctly.
150
+
151
+ Args:
152
+ openapi_spec: A dictionary representing the OpenAPI specification.
153
+
154
+ Returns:
155
+ A dictionary representing the OpenAPI specification with all references
156
+ resolved.
157
+ """
158
+
159
+ openapi_spec = copy.deepcopy(openapi_spec) # Work on a copy
160
+ resolved_cache = {} # Cache resolved references
161
+
162
+ def resolve_ref(ref_string, current_doc):
163
+ """Resolves a single $ref string."""
164
+ parts = ref_string.split("/")
165
+ if parts[0] != "#":
166
+ raise ValueError(f"External references not supported: {ref_string}")
167
+
168
+ current = current_doc
169
+ for part in parts[1:]:
170
+ if part in current:
171
+ current = current[part]
172
+ else:
173
+ return None # Reference not found
174
+ return current
175
+
176
+ def recursive_resolve(obj, current_doc, seen_refs=None):
177
+ """Recursively resolves references, handling circularity.
178
+
179
+ Args:
180
+ obj: The object to traverse.
181
+ current_doc: Document to search for refs.
182
+ seen_refs: A set to track already-visited references (for circularity
183
+ detection).
184
+
185
+ Returns:
186
+ The resolved object.
187
+ """
188
+ if seen_refs is None:
189
+ seen_refs = set() # Initialize the set if it's the first call
190
+
191
+ if isinstance(obj, dict):
192
+ if "$ref" in obj and isinstance(obj["$ref"], str):
193
+ ref_string = obj["$ref"]
194
+
195
+ # Check for circularity
196
+ if ref_string in seen_refs and ref_string not in resolved_cache:
197
+ # Circular reference detected! Return a *copy* of the object,
198
+ # but *without* the $ref. This breaks the cycle while
199
+ # still maintaining the overall structure.
200
+ return {k: v for k, v in obj.items() if k != "$ref"}
201
+
202
+ seen_refs.add(ref_string) # Add the reference to the set
203
+
204
+ # Check if we have a cached resolved value
205
+ if ref_string in resolved_cache:
206
+ return copy.deepcopy(resolved_cache[ref_string])
207
+
208
+ resolved_value = resolve_ref(ref_string, current_doc)
209
+ if resolved_value is not None:
210
+ # Recursively resolve the *resolved* value,
211
+ # passing along the 'seen_refs' set
212
+ resolved_value = recursive_resolve(
213
+ resolved_value, current_doc, seen_refs
214
+ )
215
+ resolved_cache[ref_string] = resolved_value
216
+ return copy.deepcopy(resolved_value) # return the cached result
217
+ else:
218
+ return obj # return original if no resolved value.
219
+
220
+ else:
221
+ new_dict = {}
222
+ for key, value in obj.items():
223
+ new_dict[key] = recursive_resolve(value, current_doc, seen_refs)
224
+ return new_dict
225
+
226
+ elif isinstance(obj, list):
227
+ return [recursive_resolve(item, current_doc, seen_refs) for item in obj]
228
+ else:
229
+ return obj
230
+
231
+ return recursive_resolve(openapi_spec, openapi_spec)
@@ -0,0 +1,144 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import json
16
+ import logging
17
+ from typing import Any
18
+ from typing import Dict
19
+ from typing import Final
20
+ from typing import List
21
+ from typing import Literal
22
+ from typing import Optional
23
+
24
+ import yaml
25
+
26
+ from ....auth.auth_credential import AuthCredential
27
+ from ....auth.auth_schemes import AuthScheme
28
+ from .openapi_spec_parser import OpenApiSpecParser
29
+ from .rest_api_tool import RestApiTool
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ class OpenAPIToolset:
35
+ """Class for parsing OpenAPI spec into a list of RestApiTool.
36
+
37
+ Usage:
38
+ ```
39
+ # Initialize OpenAPI toolset from a spec string.
40
+ openapi_toolset = OpenAPIToolset(spec_str=openapi_spec_str,
41
+ spec_str_type="json")
42
+ # Or, initialize OpenAPI toolset from a spec dictionary.
43
+ openapi_toolset = OpenAPIToolset(spec_dict=openapi_spec_dict)
44
+
45
+ # Add all tools to an agent.
46
+ agent = Agent(
47
+ tools=[*openapi_toolset.get_tools()]
48
+ )
49
+ # Or, add a single tool to an agent.
50
+ agent = Agent(
51
+ tools=[openapi_toolset.get_tool('tool_name')]
52
+ )
53
+ ```
54
+ """
55
+
56
+ def __init__(
57
+ self,
58
+ *,
59
+ spec_dict: Optional[Dict[str, Any]] = None,
60
+ spec_str: Optional[str] = None,
61
+ spec_str_type: Literal["json", "yaml"] = "json",
62
+ auth_scheme: Optional[AuthScheme] = None,
63
+ auth_credential: Optional[AuthCredential] = None,
64
+ ):
65
+ """Initializes the OpenAPIToolset.
66
+
67
+ Usage:
68
+ ```
69
+ # Initialize OpenAPI toolset from a spec string.
70
+ openapi_toolset = OpenAPIToolset(spec_str=openapi_spec_str,
71
+ spec_str_type="json")
72
+ # Or, initialize OpenAPI toolset from a spec dictionary.
73
+ openapi_toolset = OpenAPIToolset(spec_dict=openapi_spec_dict)
74
+
75
+ # Add all tools to an agent.
76
+ agent = Agent(
77
+ tools=[*openapi_toolset.get_tools()]
78
+ )
79
+ # Or, add a single tool to an agent.
80
+ agent = Agent(
81
+ tools=[openapi_toolset.get_tool('tool_name')]
82
+ )
83
+ ```
84
+
85
+ Args:
86
+ spec_dict: The OpenAPI spec dictionary. If provided, it will be used
87
+ instead of loading the spec from a string.
88
+ spec_str: The OpenAPI spec string in JSON or YAML format. It will be used
89
+ when spec_dict is not provided.
90
+ spec_str_type: The type of the OpenAPI spec string. Can be "json" or
91
+ "yaml".
92
+ auth_scheme: The auth scheme to use for all tools. Use AuthScheme or use
93
+ helpers in `google.adk.tools.openapi_tool.auth.auth_helpers`
94
+ auth_credential: The auth credential to use for all tools. Use
95
+ AuthCredential or use helpers in
96
+ `google.adk.tools.openapi_tool.auth.auth_helpers`
97
+ """
98
+ if not spec_dict:
99
+ spec_dict = self._load_spec(spec_str, spec_str_type)
100
+ self.tools: Final[List[RestApiTool]] = list(self._parse(spec_dict))
101
+ if auth_scheme or auth_credential:
102
+ self._configure_auth_all(auth_scheme, auth_credential)
103
+
104
+ def _configure_auth_all(
105
+ self, auth_scheme: AuthScheme, auth_credential: AuthCredential
106
+ ):
107
+ """Configure auth scheme and credential for all tools."""
108
+
109
+ for tool in self.tools:
110
+ if auth_scheme:
111
+ tool.configure_auth_scheme(auth_scheme)
112
+ if auth_credential:
113
+ tool.configure_auth_credential(auth_credential)
114
+
115
+ def get_tools(self) -> List[RestApiTool]:
116
+ """Get all tools in the toolset."""
117
+ return self.tools
118
+
119
+ def get_tool(self, tool_name: str) -> Optional[RestApiTool]:
120
+ """Get a tool by name."""
121
+ matching_tool = filter(lambda t: t.name == tool_name, self.tools)
122
+ return next(matching_tool, None)
123
+
124
+ def _load_spec(
125
+ self, spec_str: str, spec_type: Literal["json", "yaml"]
126
+ ) -> Dict[str, Any]:
127
+ """Loads the OpenAPI spec string into adictionary."""
128
+ if spec_type == "json":
129
+ return json.loads(spec_str)
130
+ elif spec_type == "yaml":
131
+ return yaml.safe_load(spec_str)
132
+ else:
133
+ raise ValueError(f"Unsupported spec type: {spec_type}")
134
+
135
+ def _parse(self, openapi_spec_dict: Dict[str, Any]) -> List[RestApiTool]:
136
+ """Parse OpenAPI spec into a list of RestApiTool."""
137
+ operations = OpenApiSpecParser().parse(openapi_spec_dict)
138
+
139
+ tools = []
140
+ for o in operations:
141
+ tool = RestApiTool.from_parsed_operation(o)
142
+ logger.info("Parsed tool: %s", tool.name)
143
+ tools.append(tool)
144
+ return tools
@@ -0,0 +1,260 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import inspect
16
+ from textwrap import dedent
17
+ from typing import Any
18
+ from typing import Dict
19
+ from typing import List
20
+ from typing import Optional
21
+ from typing import Union
22
+
23
+ from fastapi.encoders import jsonable_encoder
24
+ from fastapi.openapi.models import Operation
25
+ from fastapi.openapi.models import Parameter
26
+ from fastapi.openapi.models import Schema
27
+
28
+ from ..common.common import ApiParameter
29
+ from ..common.common import PydocHelper
30
+ from ..common.common import to_snake_case
31
+
32
+
33
+ class OperationParser:
34
+ """Generates parameters for Python functions from an OpenAPI operation.
35
+
36
+ This class processes an OpenApiOperation object and provides helper methods
37
+ to extract information needed to generate Python function declarations,
38
+ docstrings, signatures, and JSON schemas. It handles parameter processing,
39
+ name deduplication, and type hint generation.
40
+ """
41
+
42
+ def __init__(
43
+ self, operation: Union[Operation, Dict[str, Any], str], should_parse=True
44
+ ):
45
+ """Initializes the OperationParser with an OpenApiOperation.
46
+
47
+ Args:
48
+ operation: The OpenApiOperation object or a dictionary to process.
49
+ should_parse: Whether to parse the operation during initialization.
50
+ """
51
+ if isinstance(operation, dict):
52
+ self.operation = Operation.model_validate(operation)
53
+ elif isinstance(operation, str):
54
+ self.operation = Operation.model_validate_json(operation)
55
+ else:
56
+ self.operation = operation
57
+
58
+ self.params: List[ApiParameter] = []
59
+ self.return_value: Optional[ApiParameter] = None
60
+ if should_parse:
61
+ self._process_operation_parameters()
62
+ self._process_request_body()
63
+ self._process_return_value()
64
+ self._dedupe_param_names()
65
+
66
+ @classmethod
67
+ def load(
68
+ cls,
69
+ operation: Union[Operation, Dict[str, Any]],
70
+ params: List[ApiParameter],
71
+ return_value: Optional[ApiParameter] = None,
72
+ ) -> 'OperationParser':
73
+ parser = cls(operation, should_parse=False)
74
+ parser.params = params
75
+ parser.return_value = return_value
76
+ return parser
77
+
78
+ def _process_operation_parameters(self):
79
+ """Processes parameters from the OpenAPI operation."""
80
+ parameters = self.operation.parameters or []
81
+ for param in parameters:
82
+ if isinstance(param, Parameter):
83
+ original_name = param.name
84
+ description = param.description or ''
85
+ location = param.in_ or ''
86
+ schema = param.schema_ or {} # Use schema_ instead of .schema
87
+
88
+ self.params.append(
89
+ ApiParameter(
90
+ original_name=original_name,
91
+ param_location=location,
92
+ param_schema=schema,
93
+ description=description,
94
+ )
95
+ )
96
+
97
+ def _process_request_body(self):
98
+ """Processes the request body from the OpenAPI operation."""
99
+ request_body = self.operation.requestBody
100
+ if not request_body:
101
+ return
102
+
103
+ content = request_body.content or {}
104
+ if not content:
105
+ return
106
+
107
+ # If request body is an object, expand the properties as parameters
108
+ for _, media_type_object in content.items():
109
+ schema = media_type_object.schema_ or {}
110
+ description = request_body.description or ''
111
+
112
+ if schema and schema.type == 'object':
113
+ for prop_name, prop_details in schema.properties.items():
114
+ self.params.append(
115
+ ApiParameter(
116
+ original_name=prop_name,
117
+ param_location='body',
118
+ param_schema=prop_details,
119
+ description=prop_details.description,
120
+ )
121
+ )
122
+
123
+ elif schema and schema.type == 'array':
124
+ self.params.append(
125
+ ApiParameter(
126
+ original_name='array',
127
+ param_location='body',
128
+ param_schema=schema,
129
+ description=description,
130
+ )
131
+ )
132
+ else:
133
+ self.params.append(
134
+ # Empty name for unnamed body param
135
+ ApiParameter(
136
+ original_name='',
137
+ param_location='body',
138
+ param_schema=schema,
139
+ description=description,
140
+ )
141
+ )
142
+ break # Process first mime type only
143
+
144
+ def _dedupe_param_names(self):
145
+ """Deduplicates parameter names to avoid conflicts."""
146
+ params_cnt = {}
147
+ for param in self.params:
148
+ name = param.py_name
149
+ if name not in params_cnt:
150
+ params_cnt[name] = 0
151
+ else:
152
+ params_cnt[name] += 1
153
+ param.py_name = f'{name}_{params_cnt[name] -1}'
154
+
155
+ def _process_return_value(self) -> Parameter:
156
+ """Returns a Parameter object representing the return type."""
157
+ responses = self.operation.responses or {}
158
+ # Default to Any if no 2xx response or if schema is missing
159
+ return_schema = Schema(type='Any')
160
+
161
+ # Take the 20x response with the smallest response code.
162
+ valid_codes = list(
163
+ filter(lambda k: k.startswith('2'), list(responses.keys()))
164
+ )
165
+ min_20x_status_code = min(valid_codes) if valid_codes else None
166
+
167
+ if min_20x_status_code and responses[min_20x_status_code].content:
168
+ content = responses[min_20x_status_code].content
169
+ for mime_type in content:
170
+ if content[mime_type].schema_:
171
+ return_schema = content[mime_type].schema_
172
+ break
173
+
174
+ self.return_value = ApiParameter(
175
+ original_name='',
176
+ param_location='',
177
+ param_schema=return_schema,
178
+ )
179
+
180
+ def get_function_name(self) -> str:
181
+ """Returns the generated function name."""
182
+ operation_id = self.operation.operationId
183
+ if not operation_id:
184
+ raise ValueError('Operation ID is missing')
185
+ return to_snake_case(operation_id)[:60]
186
+
187
+ def get_return_type_hint(self) -> str:
188
+ """Returns the return type hint string (like 'str', 'int', etc.)."""
189
+ return self.return_value.type_hint
190
+
191
+ def get_return_type_value(self) -> Any:
192
+ """Returns the return type value (like str, int, List[str], etc.)."""
193
+ return self.return_value.type_value
194
+
195
+ def get_parameters(self) -> List[ApiParameter]:
196
+ """Returns the list of Parameter objects."""
197
+ return self.params
198
+
199
+ def get_return_value(self) -> ApiParameter:
200
+ """Returns the list of Parameter objects."""
201
+ return self.return_value
202
+
203
+ def get_auth_scheme_name(self) -> str:
204
+ """Returns the name of the auth scheme for this operation from the spec."""
205
+ if self.operation.security:
206
+ scheme_name = list(self.operation.security[0].keys())[0]
207
+ return scheme_name
208
+ return ''
209
+
210
+ def get_pydoc_string(self) -> str:
211
+ """Returns the generated PyDoc string."""
212
+ pydoc_params = [param.to_pydoc_string() for param in self.params]
213
+ pydoc_description = (
214
+ self.operation.summary or self.operation.description or ''
215
+ )
216
+ pydoc_return = PydocHelper.generate_return_doc(
217
+ self.operation.responses or {}
218
+ )
219
+ pydoc_arg_list = chr(10).join(
220
+ f' {param_doc}' for param_doc in pydoc_params
221
+ )
222
+ return dedent(f"""
223
+ \"\"\"{pydoc_description}
224
+
225
+ Args:
226
+ {pydoc_arg_list}
227
+
228
+ {pydoc_return}
229
+ \"\"\"
230
+ """).strip()
231
+
232
+ def get_json_schema(self) -> Dict[str, Any]:
233
+ """Returns the JSON schema for the function arguments."""
234
+ properties = {
235
+ p.py_name: jsonable_encoder(p.param_schema, exclude_none=True)
236
+ for p in self.params
237
+ }
238
+ return {
239
+ 'properties': properties,
240
+ 'required': [p.py_name for p in self.params],
241
+ 'title': f"{self.operation.operationId or 'unnamed'}_Arguments",
242
+ 'type': 'object',
243
+ }
244
+
245
+ def get_signature_parameters(self) -> List[inspect.Parameter]:
246
+ """Returns a list of inspect.Parameter objects for the function."""
247
+ return [
248
+ inspect.Parameter(
249
+ param.py_name,
250
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
251
+ annotation=param.type_value,
252
+ )
253
+ for param in self.params
254
+ ]
255
+
256
+ def get_annotations(self) -> Dict[str, Any]:
257
+ """Returns a dictionary of parameter annotations for the function."""
258
+ annotations = {p.py_name: p.type_value for p in self.params}
259
+ annotations['return'] = self.get_return_type_value()
260
+ return annotations