google-adk 0.0.1__py3-none-any.whl → 0.0.3__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.
- google/adk/._version.py +0 -0
- google/adk/__init__.py +20 -0
- google/adk/agents/__init__.py +32 -0
- google/adk/agents/active_streaming_tool.py +38 -0
- google/adk/agents/base_agent.py +345 -0
- google/adk/agents/callback_context.py +112 -0
- google/adk/agents/invocation_context.py +181 -0
- google/adk/agents/langgraph_agent.py +140 -0
- google/adk/agents/live_request_queue.py +64 -0
- google/adk/agents/llm_agent.py +376 -0
- google/adk/agents/loop_agent.py +62 -0
- google/adk/agents/parallel_agent.py +96 -0
- google/adk/agents/readonly_context.py +46 -0
- google/adk/agents/remote_agent.py +50 -0
- google/adk/agents/run_config.py +87 -0
- google/adk/agents/sequential_agent.py +45 -0
- google/adk/agents/transcription_entry.py +34 -0
- google/adk/artifacts/__init__.py +23 -0
- google/adk/artifacts/base_artifact_service.py +128 -0
- google/adk/artifacts/gcs_artifact_service.py +195 -0
- google/adk/artifacts/in_memory_artifact_service.py +133 -0
- google/adk/auth/__init__.py +22 -0
- google/adk/auth/auth_credential.py +220 -0
- google/adk/auth/auth_handler.py +268 -0
- google/adk/auth/auth_preprocessor.py +116 -0
- google/adk/auth/auth_schemes.py +67 -0
- google/adk/auth/auth_tool.py +55 -0
- google/adk/cli/__init__.py +15 -0
- google/adk/cli/__main__.py +18 -0
- google/adk/cli/agent_graph.py +148 -0
- google/adk/cli/browser/adk_favicon.svg +17 -0
- google/adk/cli/browser/assets/audio-processor.js +51 -0
- google/adk/cli/browser/assets/config/runtime-config.json +3 -0
- google/adk/cli/browser/index.html +33 -0
- google/adk/cli/browser/main-SY2WYYGV.js +75 -0
- google/adk/cli/browser/polyfills-FFHMD2TL.js +18 -0
- google/adk/cli/browser/styles-4VDSPQ37.css +17 -0
- google/adk/cli/cli.py +181 -0
- google/adk/cli/cli_deploy.py +181 -0
- google/adk/cli/cli_eval.py +282 -0
- google/adk/cli/cli_tools_click.py +524 -0
- google/adk/cli/fast_api.py +784 -0
- google/adk/cli/utils/__init__.py +49 -0
- google/adk/cli/utils/envs.py +57 -0
- google/adk/cli/utils/evals.py +93 -0
- google/adk/cli/utils/logs.py +72 -0
- google/adk/code_executors/__init__.py +49 -0
- google/adk/code_executors/base_code_executor.py +97 -0
- google/adk/code_executors/code_execution_utils.py +256 -0
- google/adk/code_executors/code_executor_context.py +202 -0
- google/adk/code_executors/container_code_executor.py +196 -0
- google/adk/code_executors/unsafe_local_code_executor.py +71 -0
- google/adk/code_executors/vertex_ai_code_executor.py +234 -0
- google/adk/docs/Makefile +20 -0
- google/adk/docs/build/doctrees/google-adk.doctree +0 -0
- google/adk/docs/build/html/_sources/google-adk.rst.txt +98 -0
- google/adk/docs/build/html/_sources/index.rst.txt +7 -0
- google/adk/docs/build/html/_static/autodoc_pydantic.css +27 -0
- google/adk/docs/build/html/_static/basic.css +925 -0
- google/adk/docs/build/html/_static/debug.css +85 -0
- google/adk/docs/build/html/_static/doctools.js +156 -0
- google/adk/docs/build/html/_static/documentation_options.js +29 -0
- google/adk/docs/build/html/_static/file.png +0 -0
- google/adk/docs/build/html/_static/language_data.js +199 -0
- google/adk/docs/build/html/_static/minus.png +0 -0
- google/adk/docs/build/html/_static/plus.png +0 -0
- google/adk/docs/build/html/_static/pygments.css +274 -0
- google/adk/docs/build/html/_static/scripts/furo-extensions.js +16 -0
- google/adk/docs/build/html/_static/scripts/furo.js +19 -0
- google/adk/docs/build/html/_static/scripts/furo.js.LICENSE.txt +7 -0
- google/adk/docs/build/html/_static/scripts/furo.js.map +1 -0
- google/adk/docs/build/html/_static/searchtools.js +620 -0
- google/adk/docs/build/html/_static/skeleton.css +312 -0
- google/adk/docs/build/html/_static/sphinx_highlight.js +170 -0
- google/adk/docs/build/html/_static/styles/furo-extensions.css +18 -0
- google/adk/docs/build/html/_static/styles/furo-extensions.css.map +1 -0
- google/adk/docs/build/html/_static/styles/furo.css +18 -0
- google/adk/docs/build/html/_static/styles/furo.css.map +1 -0
- google/adk/docs/build/html/genindex.html +861 -0
- google/adk/docs/build/html/google-adk.html +5461 -0
- google/adk/docs/build/html/index.html +567 -0
- google/adk/docs/build/html/objects.inv +0 -0
- google/adk/docs/build/html/py-modindex.html +373 -0
- google/adk/docs/build/html/search.html +333 -0
- google/adk/docs/build/html/searchindex.js +17 -0
- google/adk/docs/source/conf.py +133 -0
- google/adk/docs/source/google-adk.rst +98 -0
- google/adk/docs/source/index.rst +7 -0
- google/adk/evaluation/__init__.py +31 -0
- google/adk/evaluation/agent_evaluator.py +329 -0
- google/adk/evaluation/evaluation_constants.py +24 -0
- google/adk/evaluation/evaluation_generator.py +270 -0
- google/adk/evaluation/response_evaluator.py +135 -0
- google/adk/evaluation/trajectory_evaluator.py +184 -0
- google/adk/events/__init__.py +21 -0
- google/adk/events/event.py +130 -0
- google/adk/events/event_actions.py +55 -0
- google/adk/examples/__init__.py +28 -0
- google/adk/examples/base_example_provider.py +35 -0
- google/adk/examples/example.py +27 -0
- google/adk/examples/example_util.py +123 -0
- google/adk/examples/vertex_ai_example_store.py +104 -0
- google/adk/flows/__init__.py +14 -0
- google/adk/flows/llm_flows/__init__.py +20 -0
- google/adk/flows/llm_flows/_base_llm_processor.py +52 -0
- google/adk/flows/llm_flows/_code_execution.py +458 -0
- google/adk/flows/llm_flows/_nl_planning.py +129 -0
- google/adk/flows/llm_flows/agent_transfer.py +132 -0
- google/adk/flows/llm_flows/audio_transcriber.py +109 -0
- google/adk/flows/llm_flows/auto_flow.py +49 -0
- google/adk/flows/llm_flows/base_llm_flow.py +559 -0
- google/adk/flows/llm_flows/basic.py +72 -0
- google/adk/flows/llm_flows/contents.py +370 -0
- google/adk/flows/llm_flows/functions.py +486 -0
- google/adk/flows/llm_flows/identity.py +47 -0
- google/adk/flows/llm_flows/instructions.py +137 -0
- google/adk/flows/llm_flows/single_flow.py +57 -0
- google/adk/memory/__init__.py +35 -0
- google/adk/memory/base_memory_service.py +74 -0
- google/adk/memory/in_memory_memory_service.py +62 -0
- google/adk/memory/vertex_ai_rag_memory_service.py +177 -0
- google/adk/models/__init__.py +31 -0
- google/adk/models/anthropic_llm.py +243 -0
- google/adk/models/base_llm.py +87 -0
- google/adk/models/base_llm_connection.py +76 -0
- google/adk/models/gemini_llm_connection.py +200 -0
- google/adk/models/google_llm.py +331 -0
- google/adk/models/lite_llm.py +673 -0
- google/adk/models/llm_request.py +98 -0
- google/adk/models/llm_response.py +111 -0
- google/adk/models/registry.py +102 -0
- google/adk/planners/__init__.py +23 -0
- google/adk/planners/base_planner.py +66 -0
- google/adk/planners/built_in_planner.py +75 -0
- google/adk/planners/plan_re_act_planner.py +208 -0
- google/adk/runners.py +456 -0
- google/adk/sessions/__init__.py +41 -0
- google/adk/sessions/base_session_service.py +133 -0
- google/adk/sessions/database_session_service.py +522 -0
- google/adk/sessions/in_memory_session_service.py +206 -0
- google/adk/sessions/session.py +54 -0
- google/adk/sessions/state.py +71 -0
- google/adk/sessions/vertex_ai_session_service.py +356 -0
- google/adk/telemetry.py +189 -0
- google/adk/tests/__init__.py +14 -0
- google/adk/tests/integration/.env.example +10 -0
- google/adk/tests/integration/__init__.py +18 -0
- google/adk/tests/integration/conftest.py +119 -0
- google/adk/tests/integration/fixture/__init__.py +14 -0
- google/adk/tests/integration/fixture/agent_with_config/__init__.py +15 -0
- google/adk/tests/integration/fixture/agent_with_config/agent.py +88 -0
- google/adk/tests/integration/fixture/callback_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/callback_agent/agent.py +105 -0
- google/adk/tests/integration/fixture/context_update_test/OWNERS +1 -0
- google/adk/tests/integration/fixture/context_update_test/__init__.py +15 -0
- google/adk/tests/integration/fixture/context_update_test/agent.py +43 -0
- google/adk/tests/integration/fixture/context_update_test/successful_test.session.json +582 -0
- google/adk/tests/integration/fixture/context_variable_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/context_variable_agent/agent.py +115 -0
- google/adk/tests/integration/fixture/customer_support_ma/__init__.py +15 -0
- google/adk/tests/integration/fixture/customer_support_ma/agent.py +172 -0
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/agent.py +338 -0
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/order_query.test.json +69 -0
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/test_config.json +6 -0
- google/adk/tests/integration/fixture/flow_complex_spark/__init__.py +15 -0
- google/adk/tests/integration/fixture/flow_complex_spark/agent.py +182 -0
- google/adk/tests/integration/fixture/flow_complex_spark/sample.session.json +190 -0
- google/adk/tests/integration/fixture/hello_world_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/hello_world_agent/agent.py +95 -0
- google/adk/tests/integration/fixture/hello_world_agent/roll_die.test.json +24 -0
- google/adk/tests/integration/fixture/hello_world_agent/test_config.json +6 -0
- google/adk/tests/integration/fixture/home_automation_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/home_automation_agent/agent.py +304 -0
- google/adk/tests/integration/fixture/home_automation_agent/simple_test.test.json +5 -0
- google/adk/tests/integration/fixture/home_automation_agent/simple_test2.test.json +5 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_config.json +5 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/dependent_tool_calls.test.json +18 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/eval_data.test.json +17 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/test_config.json +6 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_multi_turn_conversation.test.json +18 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test.test.json +17 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test2.test.json +5 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/test_config.json +5 -0
- google/adk/tests/integration/fixture/tool_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/tool_agent/agent.py +218 -0
- google/adk/tests/integration/fixture/tool_agent/files/Agent_test_plan.pdf +0 -0
- google/adk/tests/integration/fixture/trip_planner_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/trip_planner_agent/agent.py +110 -0
- google/adk/tests/integration/fixture/trip_planner_agent/initial.session.json +13 -0
- google/adk/tests/integration/fixture/trip_planner_agent/test_config.json +5 -0
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/initial.session.json +13 -0
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/test_config.json +5 -0
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/trip_inquiry_sub_agent.test.json +7 -0
- google/adk/tests/integration/fixture/trip_planner_agent/trip_inquiry.test.json +19 -0
- google/adk/tests/integration/models/__init__.py +14 -0
- google/adk/tests/integration/models/test_google_llm.py +65 -0
- google/adk/tests/integration/test_callback.py +70 -0
- google/adk/tests/integration/test_context_variable.py +67 -0
- google/adk/tests/integration/test_evalute_agent_in_fixture.py +76 -0
- google/adk/tests/integration/test_multi_agent.py +28 -0
- google/adk/tests/integration/test_multi_turn.py +42 -0
- google/adk/tests/integration/test_single_agent.py +23 -0
- google/adk/tests/integration/test_sub_agent.py +26 -0
- google/adk/tests/integration/test_system_instruction.py +177 -0
- google/adk/tests/integration/test_tools.py +287 -0
- google/adk/tests/integration/test_with_test_file.py +34 -0
- google/adk/tests/integration/tools/__init__.py +14 -0
- google/adk/tests/integration/utils/__init__.py +16 -0
- google/adk/tests/integration/utils/asserts.py +75 -0
- google/adk/tests/integration/utils/test_runner.py +97 -0
- google/adk/tests/unittests/__init__.py +14 -0
- google/adk/tests/unittests/agents/__init__.py +14 -0
- google/adk/tests/unittests/agents/test_base_agent.py +407 -0
- google/adk/tests/unittests/agents/test_langgraph_agent.py +191 -0
- google/adk/tests/unittests/agents/test_llm_agent_callbacks.py +138 -0
- google/adk/tests/unittests/agents/test_llm_agent_fields.py +231 -0
- google/adk/tests/unittests/agents/test_loop_agent.py +136 -0
- google/adk/tests/unittests/agents/test_parallel_agent.py +92 -0
- google/adk/tests/unittests/agents/test_sequential_agent.py +114 -0
- google/adk/tests/unittests/artifacts/__init__.py +14 -0
- google/adk/tests/unittests/artifacts/test_artifact_service.py +276 -0
- google/adk/tests/unittests/auth/test_auth_handler.py +575 -0
- google/adk/tests/unittests/conftest.py +73 -0
- google/adk/tests/unittests/fast_api/__init__.py +14 -0
- google/adk/tests/unittests/fast_api/test_fast_api.py +269 -0
- google/adk/tests/unittests/flows/__init__.py +14 -0
- google/adk/tests/unittests/flows/llm_flows/__init__.py +14 -0
- google/adk/tests/unittests/flows/llm_flows/_test_examples.py +142 -0
- google/adk/tests/unittests/flows/llm_flows/test_agent_transfer.py +311 -0
- google/adk/tests/unittests/flows/llm_flows/test_functions_long_running.py +244 -0
- google/adk/tests/unittests/flows/llm_flows/test_functions_request_euc.py +346 -0
- google/adk/tests/unittests/flows/llm_flows/test_functions_sequential.py +93 -0
- google/adk/tests/unittests/flows/llm_flows/test_functions_simple.py +258 -0
- google/adk/tests/unittests/flows/llm_flows/test_identity.py +66 -0
- google/adk/tests/unittests/flows/llm_flows/test_instructions.py +164 -0
- google/adk/tests/unittests/flows/llm_flows/test_model_callbacks.py +142 -0
- google/adk/tests/unittests/flows/llm_flows/test_other_configs.py +46 -0
- google/adk/tests/unittests/flows/llm_flows/test_tool_callbacks.py +269 -0
- google/adk/tests/unittests/models/__init__.py +14 -0
- google/adk/tests/unittests/models/test_google_llm.py +224 -0
- google/adk/tests/unittests/models/test_litellm.py +804 -0
- google/adk/tests/unittests/models/test_models.py +60 -0
- google/adk/tests/unittests/sessions/__init__.py +14 -0
- google/adk/tests/unittests/sessions/test_session_service.py +227 -0
- google/adk/tests/unittests/sessions/test_vertex_ai_session_service.py +246 -0
- google/adk/tests/unittests/streaming/__init__.py +14 -0
- google/adk/tests/unittests/streaming/test_streaming.py +50 -0
- google/adk/tests/unittests/tools/__init__.py +14 -0
- google/adk/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py +499 -0
- google/adk/tests/unittests/tools/apihub_tool/test_apihub_toolset.py +204 -0
- google/adk/tests/unittests/tools/application_integration_tool/clients/test_connections_client.py +600 -0
- google/adk/tests/unittests/tools/application_integration_tool/clients/test_integration_client.py +630 -0
- google/adk/tests/unittests/tools/application_integration_tool/test_application_integration_toolset.py +345 -0
- google/adk/tests/unittests/tools/google_api_tool/__init__.py +13 -0
- google/adk/tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py +657 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_auto_auth_credential_exchanger.py +145 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_base_auth_credential_exchanger.py +68 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_oauth2_exchanger.py +153 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_service_account_exchanger.py +196 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py +573 -0
- google/adk/tests/unittests/tools/openapi_tool/common/test_common.py +436 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test.yaml +1367 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py +628 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py +139 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_operation_parser.py +406 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py +966 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_tool_auth_handler.py +201 -0
- google/adk/tests/unittests/tools/retrieval/__init__.py +14 -0
- google/adk/tests/unittests/tools/retrieval/test_vertex_ai_rag_retrieval.py +147 -0
- google/adk/tests/unittests/tools/test_agent_tool.py +167 -0
- google/adk/tests/unittests/tools/test_base_tool.py +141 -0
- google/adk/tests/unittests/tools/test_build_function_declaration.py +277 -0
- google/adk/tests/unittests/utils.py +304 -0
- google/adk/tools/__init__.py +51 -0
- google/adk/tools/_automatic_function_calling_util.py +346 -0
- google/adk/tools/agent_tool.py +176 -0
- google/adk/tools/apihub_tool/__init__.py +19 -0
- google/adk/tools/apihub_tool/apihub_toolset.py +209 -0
- google/adk/tools/apihub_tool/clients/__init__.py +13 -0
- google/adk/tools/apihub_tool/clients/apihub_client.py +332 -0
- google/adk/tools/apihub_tool/clients/secret_client.py +115 -0
- google/adk/tools/application_integration_tool/__init__.py +19 -0
- google/adk/tools/application_integration_tool/application_integration_toolset.py +230 -0
- google/adk/tools/application_integration_tool/clients/connections_client.py +903 -0
- google/adk/tools/application_integration_tool/clients/integration_client.py +253 -0
- google/adk/tools/base_tool.py +144 -0
- google/adk/tools/built_in_code_execution_tool.py +59 -0
- google/adk/tools/crewai_tool.py +72 -0
- google/adk/tools/example_tool.py +62 -0
- google/adk/tools/exit_loop_tool.py +23 -0
- google/adk/tools/function_parameter_parse_util.py +307 -0
- google/adk/tools/function_tool.py +87 -0
- google/adk/tools/get_user_choice_tool.py +28 -0
- google/adk/tools/google_api_tool/__init__.py +14 -0
- google/adk/tools/google_api_tool/google_api_tool.py +59 -0
- google/adk/tools/google_api_tool/google_api_tool_set.py +107 -0
- google/adk/tools/google_api_tool/google_api_tool_sets.py +55 -0
- google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +521 -0
- google/adk/tools/google_search_tool.py +68 -0
- google/adk/tools/langchain_tool.py +86 -0
- google/adk/tools/load_artifacts_tool.py +113 -0
- google/adk/tools/load_memory_tool.py +58 -0
- google/adk/tools/load_web_page.py +41 -0
- google/adk/tools/long_running_tool.py +39 -0
- google/adk/tools/mcp_tool/__init__.py +42 -0
- google/adk/tools/mcp_tool/conversion_utils.py +161 -0
- google/adk/tools/mcp_tool/mcp_tool.py +113 -0
- google/adk/tools/mcp_tool/mcp_toolset.py +272 -0
- google/adk/tools/openapi_tool/__init__.py +21 -0
- google/adk/tools/openapi_tool/auth/__init__.py +19 -0
- google/adk/tools/openapi_tool/auth/auth_helpers.py +498 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/__init__.py +25 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/auto_auth_credential_exchanger.py +105 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/base_credential_exchanger.py +55 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/oauth2_exchanger.py +117 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/service_account_exchanger.py +97 -0
- google/adk/tools/openapi_tool/common/__init__.py +19 -0
- google/adk/tools/openapi_tool/common/common.py +300 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +32 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py +231 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +144 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +260 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +496 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +268 -0
- google/adk/tools/preload_memory_tool.py +72 -0
- google/adk/tools/retrieval/__init__.py +36 -0
- google/adk/tools/retrieval/base_retrieval_tool.py +37 -0
- google/adk/tools/retrieval/files_retrieval.py +33 -0
- google/adk/tools/retrieval/llama_index_retrieval.py +41 -0
- google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +107 -0
- google/adk/tools/tool_context.py +90 -0
- google/adk/tools/toolbox_tool.py +46 -0
- google/adk/tools/transfer_to_agent_tool.py +21 -0
- google/adk/tools/vertex_ai_search_tool.py +96 -0
- google/adk/version.py +16 -0
- google_adk-0.0.3.dist-info/METADATA +73 -0
- google_adk-0.0.3.dist-info/RECORD +340 -0
- {google_adk-0.0.1.dist-info → google_adk-0.0.3.dist-info}/WHEEL +1 -2
- google_adk-0.0.3.dist-info/entry_points.txt +3 -0
- agent_kit/__init__.py +0 -0
- google_adk-0.0.1.dist-info/LICENSE.txt +0 -170
- google_adk-0.0.1.dist-info/METADATA +0 -15
- google_adk-0.0.1.dist-info/RECORD +0 -6
- google_adk-0.0.1.dist-info/top_level.txt +0 -1
@@ -0,0 +1,202 @@
|
|
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
|
+
"""The persistent context used to configure the code executor."""
|
16
|
+
|
17
|
+
import copy
|
18
|
+
import dataclasses
|
19
|
+
import datetime
|
20
|
+
from typing import Any
|
21
|
+
from typing import Optional
|
22
|
+
|
23
|
+
from ..sessions.state import State
|
24
|
+
from .code_execution_utils import File
|
25
|
+
|
26
|
+
_CONTEXT_KEY = '_code_execution_context'
|
27
|
+
_SESSION_ID_KEY = 'execution_session_id'
|
28
|
+
_PROCESSED_FILE_NAMES_KEY = 'processed_input_files'
|
29
|
+
_INPUT_FILE_KEY = '_code_executor_input_files'
|
30
|
+
_ERROR_COUNT_KEY = '_code_executor_error_counts'
|
31
|
+
|
32
|
+
_CODE_EXECUTION_RESULTS_KEY = '_code_execution_results'
|
33
|
+
|
34
|
+
|
35
|
+
class CodeExecutorContext:
|
36
|
+
"""The persistent context used to configure the code executor."""
|
37
|
+
|
38
|
+
_context: dict[str, Any]
|
39
|
+
|
40
|
+
def __init__(self, session_state: State):
|
41
|
+
"""Initializes the code executor context.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
session_state: The session state to get the code executor context from.
|
45
|
+
"""
|
46
|
+
self._context = self._get_code_executor_context(session_state)
|
47
|
+
self._session_state = session_state
|
48
|
+
|
49
|
+
def get_state_delta(self) -> dict[str, Any]:
|
50
|
+
"""Gets the state delta to update in the persistent session state.
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
The state delta to update in the persistent session state.
|
54
|
+
"""
|
55
|
+
context_to_update = copy.deepcopy(self._context)
|
56
|
+
return {_CONTEXT_KEY: context_to_update}
|
57
|
+
|
58
|
+
def get_execution_id(self) -> Optional[str]:
|
59
|
+
"""Gets the session ID for the code executor.
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
The session ID for the code executor context.
|
63
|
+
"""
|
64
|
+
if _SESSION_ID_KEY not in self._context:
|
65
|
+
return None
|
66
|
+
return self._context[_SESSION_ID_KEY]
|
67
|
+
|
68
|
+
def set_execution_id(self, session_id: str):
|
69
|
+
"""Sets the session ID for the code executor.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
session_id: The session ID for the code executor.
|
73
|
+
"""
|
74
|
+
self._context[_SESSION_ID_KEY] = session_id
|
75
|
+
|
76
|
+
def get_processed_file_names(self) -> list[str]:
|
77
|
+
"""Gets the processed file names from the session state.
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
A list of processed file names in the code executor context.
|
81
|
+
"""
|
82
|
+
if _PROCESSED_FILE_NAMES_KEY not in self._context:
|
83
|
+
return []
|
84
|
+
return self._context[_PROCESSED_FILE_NAMES_KEY]
|
85
|
+
|
86
|
+
def add_processed_file_names(self, file_names: [str]):
|
87
|
+
"""Adds the processed file name to the session state.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
file_names: The processed file names to add to the session state.
|
91
|
+
"""
|
92
|
+
if _PROCESSED_FILE_NAMES_KEY not in self._context:
|
93
|
+
self._context[_PROCESSED_FILE_NAMES_KEY] = []
|
94
|
+
self._context[_PROCESSED_FILE_NAMES_KEY].extend(file_names)
|
95
|
+
|
96
|
+
def get_input_files(self) -> list[File]:
|
97
|
+
"""Gets the code executor input file names from the session state.
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
A list of input files in the code executor context.
|
101
|
+
"""
|
102
|
+
if _INPUT_FILE_KEY not in self._session_state:
|
103
|
+
return []
|
104
|
+
return [File(**file) for file in self._session_state[_INPUT_FILE_KEY]]
|
105
|
+
|
106
|
+
def add_input_files(
|
107
|
+
self,
|
108
|
+
input_files: list[File],
|
109
|
+
):
|
110
|
+
"""Adds the input files to the code executor context.
|
111
|
+
|
112
|
+
Args:
|
113
|
+
input_files: The input files to add to the code executor context.
|
114
|
+
"""
|
115
|
+
if _INPUT_FILE_KEY not in self._session_state:
|
116
|
+
self._session_state[_INPUT_FILE_KEY] = []
|
117
|
+
for input_file in input_files:
|
118
|
+
self._session_state[_INPUT_FILE_KEY].append(
|
119
|
+
dataclasses.asdict(input_file)
|
120
|
+
)
|
121
|
+
|
122
|
+
def clear_input_files(self):
|
123
|
+
"""Removes the input files and processed file names to the code executor context."""
|
124
|
+
if _INPUT_FILE_KEY in self._session_state:
|
125
|
+
self._session_state[_INPUT_FILE_KEY] = []
|
126
|
+
if _PROCESSED_FILE_NAMES_KEY in self._context:
|
127
|
+
self._context[_PROCESSED_FILE_NAMES_KEY] = []
|
128
|
+
|
129
|
+
def get_error_count(self, invocation_id: str) -> int:
|
130
|
+
"""Gets the error count from the session state.
|
131
|
+
|
132
|
+
Args:
|
133
|
+
invocation_id: The invocation ID to get the error count for.
|
134
|
+
|
135
|
+
Returns:
|
136
|
+
The error count for the given invocation ID.
|
137
|
+
"""
|
138
|
+
if _ERROR_COUNT_KEY not in self._session_state:
|
139
|
+
return 0
|
140
|
+
return self._session_state[_ERROR_COUNT_KEY].get(invocation_id, 0)
|
141
|
+
|
142
|
+
def increment_error_count(self, invocation_id: str):
|
143
|
+
"""Increments the error count from the session state.
|
144
|
+
|
145
|
+
Args:
|
146
|
+
invocation_id: The invocation ID to increment the error count for.
|
147
|
+
"""
|
148
|
+
if _ERROR_COUNT_KEY not in self._session_state:
|
149
|
+
self._session_state[_ERROR_COUNT_KEY] = {}
|
150
|
+
self._session_state[_ERROR_COUNT_KEY][invocation_id] = (
|
151
|
+
self.get_error_count(invocation_id) + 1
|
152
|
+
)
|
153
|
+
|
154
|
+
def reset_error_count(self, invocation_id: str):
|
155
|
+
"""Resets the error count from the session state.
|
156
|
+
|
157
|
+
Args:
|
158
|
+
invocation_id: The invocation ID to reset the error count for.
|
159
|
+
"""
|
160
|
+
if _ERROR_COUNT_KEY not in self._session_state:
|
161
|
+
return
|
162
|
+
if invocation_id in self._session_state[_ERROR_COUNT_KEY]:
|
163
|
+
del self._session_state[_ERROR_COUNT_KEY][invocation_id]
|
164
|
+
|
165
|
+
def update_code_execution_result(
|
166
|
+
self,
|
167
|
+
invocation_id: str,
|
168
|
+
code: str,
|
169
|
+
result_stdout: str,
|
170
|
+
result_stderr: str,
|
171
|
+
):
|
172
|
+
"""Updates the code execution result.
|
173
|
+
|
174
|
+
Args:
|
175
|
+
invocation_id: The invocation ID to update the code execution result for.
|
176
|
+
code: The code to execute.
|
177
|
+
result_stdout: The standard output of the code execution.
|
178
|
+
result_stderr: The standard error of the code execution.
|
179
|
+
"""
|
180
|
+
if _CODE_EXECUTION_RESULTS_KEY not in self._session_state:
|
181
|
+
self._session_state[_CODE_EXECUTION_RESULTS_KEY] = {}
|
182
|
+
if invocation_id not in self._session_state[_CODE_EXECUTION_RESULTS_KEY]:
|
183
|
+
self._session_state[_CODE_EXECUTION_RESULTS_KEY][invocation_id] = []
|
184
|
+
self._session_state[_CODE_EXECUTION_RESULTS_KEY][invocation_id].append({
|
185
|
+
'code': code,
|
186
|
+
'result_stdout': result_stdout,
|
187
|
+
'result_stderr': result_stderr,
|
188
|
+
'timestamp': int(datetime.datetime.now().timestamp()),
|
189
|
+
})
|
190
|
+
|
191
|
+
def _get_code_executor_context(self, session_state: State) -> dict[str, Any]:
|
192
|
+
"""Gets the code executor context from the session state.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
session_state: The session state to get the code executor context from.
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
A dict of code executor context.
|
199
|
+
"""
|
200
|
+
if _CONTEXT_KEY not in session_state:
|
201
|
+
session_state[_CONTEXT_KEY] = {}
|
202
|
+
return session_state[_CONTEXT_KEY]
|
@@ -0,0 +1,196 @@
|
|
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 atexit
|
16
|
+
import os
|
17
|
+
from typing import Optional
|
18
|
+
|
19
|
+
import docker
|
20
|
+
from docker.client import DockerClient
|
21
|
+
from docker.models.containers import Container
|
22
|
+
from pydantic import Field
|
23
|
+
from typing_extensions import override
|
24
|
+
|
25
|
+
from ..agents.invocation_context import InvocationContext
|
26
|
+
from .base_code_executor import BaseCodeExecutor
|
27
|
+
from .code_execution_utils import CodeExecutionInput
|
28
|
+
from .code_execution_utils import CodeExecutionResult
|
29
|
+
|
30
|
+
|
31
|
+
DEFAULT_IMAGE_TAG = 'adk-code-executor:latest'
|
32
|
+
|
33
|
+
|
34
|
+
class ContainerCodeExecutor(BaseCodeExecutor):
|
35
|
+
"""A code executor that uses a custom container to execute code.
|
36
|
+
|
37
|
+
Attributes:
|
38
|
+
base_url: Optional. The base url of the user hosted Docker client.
|
39
|
+
image: The tag of the predefined image or custom image to run on the
|
40
|
+
container. Either docker_path or image must be set.
|
41
|
+
docker_path: The path to the directory containing the Dockerfile. If set,
|
42
|
+
build the image from the dockerfile path instead of using the predefined
|
43
|
+
image. Either docker_path or image must be set.
|
44
|
+
"""
|
45
|
+
|
46
|
+
base_url: Optional[str] = None
|
47
|
+
"""
|
48
|
+
Optional. The base url of the user hosted Docker client.
|
49
|
+
"""
|
50
|
+
|
51
|
+
image: str = None
|
52
|
+
"""
|
53
|
+
The tag of the predefined image or custom image to run on the container.
|
54
|
+
Either docker_path or image must be set.
|
55
|
+
"""
|
56
|
+
|
57
|
+
docker_path: str = None
|
58
|
+
"""
|
59
|
+
The path to the directory containing the Dockerfile.
|
60
|
+
If set, build the image from the dockerfile path instead of using the
|
61
|
+
predefined image. Either docker_path or image must be set.
|
62
|
+
"""
|
63
|
+
|
64
|
+
# Overrides the BaseCodeExecutor attribute: this executor cannot be stateful.
|
65
|
+
stateful: bool = Field(default=False, frozen=True, exclude=True)
|
66
|
+
|
67
|
+
# Overrides the BaseCodeExecutor attribute: this executor cannot
|
68
|
+
# optimize_data_file.
|
69
|
+
optimize_data_file: bool = Field(default=False, frozen=True, exclude=True)
|
70
|
+
|
71
|
+
_client: DockerClient = None
|
72
|
+
_container: Container = None
|
73
|
+
|
74
|
+
def __init__(
|
75
|
+
self,
|
76
|
+
base_url: Optional[str] = None,
|
77
|
+
image: Optional[str] = None,
|
78
|
+
docker_path: Optional[str] = None,
|
79
|
+
**data,
|
80
|
+
):
|
81
|
+
"""Initializes the ContainerCodeExecutor.
|
82
|
+
|
83
|
+
Args:
|
84
|
+
base_url: Optional. The base url of the user hosted Docker client.
|
85
|
+
image: The tag of the predefined image or custom image to run on the
|
86
|
+
container. Either docker_path or image must be set.
|
87
|
+
docker_path: The path to the directory containing the Dockerfile. If set,
|
88
|
+
build the image from the dockerfile path instead of using the predefined
|
89
|
+
image. Either docker_path or image must be set.
|
90
|
+
**data: The data to initialize the ContainerCodeExecutor.
|
91
|
+
"""
|
92
|
+
if not image and not docker_path:
|
93
|
+
raise ValueError(
|
94
|
+
'Either image or docker_path must be set for ContainerCodeExecutor.'
|
95
|
+
)
|
96
|
+
if 'stateful' in data and data['stateful']:
|
97
|
+
raise ValueError('Cannot set `stateful=True` in ContainerCodeExecutor.')
|
98
|
+
if 'optimize_data_file' in data and data['optimize_data_file']:
|
99
|
+
raise ValueError(
|
100
|
+
'Cannot set `optimize_data_file=True` in ContainerCodeExecutor.'
|
101
|
+
)
|
102
|
+
|
103
|
+
super().__init__(**data)
|
104
|
+
self.base_url = base_url
|
105
|
+
self.image = image if image else DEFAULT_IMAGE_TAG
|
106
|
+
self.docker_path = os.path.abspath(docker_path) if docker_path else None
|
107
|
+
|
108
|
+
self._client = (
|
109
|
+
docker.from_env()
|
110
|
+
if not self.base_url
|
111
|
+
else docker.DockerClient(base_url=self.base_url)
|
112
|
+
)
|
113
|
+
# Initialize the container.
|
114
|
+
self.__init_container()
|
115
|
+
|
116
|
+
# Close the container when the on exit.
|
117
|
+
atexit.register(self.__cleanup_container)
|
118
|
+
|
119
|
+
@override
|
120
|
+
def execute_code(
|
121
|
+
self,
|
122
|
+
invocation_context: InvocationContext,
|
123
|
+
code_execution_input: CodeExecutionInput,
|
124
|
+
) -> CodeExecutionResult:
|
125
|
+
output = ''
|
126
|
+
error = ''
|
127
|
+
exec_result = self._container.exec_run(
|
128
|
+
['python3', '-c', code_execution_input.code],
|
129
|
+
demux=True,
|
130
|
+
)
|
131
|
+
|
132
|
+
if exec_result.output and exec_result.output[0]:
|
133
|
+
output = exec_result.output[0].decode('utf-8')
|
134
|
+
if (
|
135
|
+
exec_result.output
|
136
|
+
and len(exec_result.output) > 1
|
137
|
+
and exec_result.output[1]
|
138
|
+
):
|
139
|
+
error = exec_result.output[1].decode('utf-8')
|
140
|
+
|
141
|
+
# Collect the final result.
|
142
|
+
return CodeExecutionResult(
|
143
|
+
stdout=output,
|
144
|
+
stderr=error,
|
145
|
+
output_files=[],
|
146
|
+
)
|
147
|
+
|
148
|
+
def _build_docker_image(self):
|
149
|
+
"""Builds the Docker image."""
|
150
|
+
if not self.docker_path:
|
151
|
+
raise ValueError('Docker path is not set.')
|
152
|
+
if not os.path.exists(self.docker_path):
|
153
|
+
raise FileNotFoundError(f'Invalid Docker path: {self.docker_path}')
|
154
|
+
|
155
|
+
print('Building Docker image...')
|
156
|
+
self._client.images.build(
|
157
|
+
path=self.docker_path,
|
158
|
+
tag=self.image,
|
159
|
+
rm=True,
|
160
|
+
)
|
161
|
+
print(f'Docker image: {self.image} built.')
|
162
|
+
|
163
|
+
def _verify_python_installation(self):
|
164
|
+
"""Verifies the container has python3 installed."""
|
165
|
+
exec_result = self._container.exec_run(['which', 'python3'])
|
166
|
+
if exec_result.exit_code != 0:
|
167
|
+
raise ValueError('python3 is not installed in the container.')
|
168
|
+
|
169
|
+
def __init_container(self):
|
170
|
+
"""Initializes the container."""
|
171
|
+
if not self._client:
|
172
|
+
raise RuntimeError('Docker client is not initialized.')
|
173
|
+
|
174
|
+
if self.docker_path:
|
175
|
+
self._build_docker_image()
|
176
|
+
|
177
|
+
print('Starting container for ContainerCodeExecutor...')
|
178
|
+
self._container = self._client.containers.run(
|
179
|
+
image=self.image,
|
180
|
+
detach=True,
|
181
|
+
tty=True,
|
182
|
+
)
|
183
|
+
print(f'Container {self._container.id} started.')
|
184
|
+
|
185
|
+
# Verify the container is able to run python3.
|
186
|
+
self._verify_python_installation()
|
187
|
+
|
188
|
+
def __cleanup_container(self):
|
189
|
+
"""Closes the container on exit."""
|
190
|
+
if not self._container:
|
191
|
+
return
|
192
|
+
|
193
|
+
print('[Cleanup] Stopping the container...')
|
194
|
+
self._container.stop()
|
195
|
+
self._container.remove()
|
196
|
+
print(f'Container {self._container.id} stopped and removed.')
|
@@ -0,0 +1,71 @@
|
|
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
|
+
from contextlib import redirect_stdout
|
16
|
+
import io
|
17
|
+
|
18
|
+
from pydantic import Field
|
19
|
+
from typing_extensions import override
|
20
|
+
|
21
|
+
from ..agents.invocation_context import InvocationContext
|
22
|
+
from .base_code_executor import BaseCodeExecutor
|
23
|
+
from .code_execution_utils import CodeExecutionInput
|
24
|
+
from .code_execution_utils import CodeExecutionResult
|
25
|
+
|
26
|
+
|
27
|
+
class UnsafeLocalCodeExecutor(BaseCodeExecutor):
|
28
|
+
"""A code executor that unsafely execute code in the current local context."""
|
29
|
+
|
30
|
+
# Overrides the BaseCodeExecutor attribute: this executor cannot be stateful.
|
31
|
+
stateful: bool = Field(default=False, frozen=True, exclude=True)
|
32
|
+
|
33
|
+
# Overrides the BaseCodeExecutor attribute: this executor cannot
|
34
|
+
# optimize_data_file.
|
35
|
+
optimize_data_file: bool = Field(default=False, frozen=True, exclude=True)
|
36
|
+
|
37
|
+
def __init__(self, **data):
|
38
|
+
"""Initializes the UnsafeLocalCodeExecutor."""
|
39
|
+
if 'stateful' in data and data['stateful']:
|
40
|
+
raise ValueError('Cannot set `stateful=True` in UnsafeLocalCodeExecutor.')
|
41
|
+
if 'optimize_data_file' in data and data['optimize_data_file']:
|
42
|
+
raise ValueError(
|
43
|
+
'Cannot set `optimize_data_file=True` in UnsafeLocalCodeExecutor.'
|
44
|
+
)
|
45
|
+
super().__init__(**data)
|
46
|
+
|
47
|
+
@override
|
48
|
+
def execute_code(
|
49
|
+
self,
|
50
|
+
invocation_context: InvocationContext,
|
51
|
+
code_execution_input: CodeExecutionInput,
|
52
|
+
) -> CodeExecutionResult:
|
53
|
+
# Execute the code.
|
54
|
+
output = ''
|
55
|
+
error = ''
|
56
|
+
try:
|
57
|
+
globals_ = {}
|
58
|
+
locals_ = {}
|
59
|
+
stdout = io.StringIO()
|
60
|
+
with redirect_stdout(stdout):
|
61
|
+
exec(code_execution_input.code, globals_, locals_)
|
62
|
+
output = stdout.getvalue()
|
63
|
+
except Exception as e:
|
64
|
+
error = str(e)
|
65
|
+
|
66
|
+
# Collect the final result.
|
67
|
+
return CodeExecutionResult(
|
68
|
+
stdout=output,
|
69
|
+
stderr=error,
|
70
|
+
output_files=[],
|
71
|
+
)
|
@@ -0,0 +1,234 @@
|
|
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 datetime
|
16
|
+
import mimetypes
|
17
|
+
import os
|
18
|
+
from typing import Any, Optional
|
19
|
+
|
20
|
+
from typing_extensions import override
|
21
|
+
from vertexai.preview.extensions import Extension
|
22
|
+
|
23
|
+
from ..agents.invocation_context import InvocationContext
|
24
|
+
from .base_code_executor import BaseCodeExecutor
|
25
|
+
from .code_execution_utils import CodeExecutionInput
|
26
|
+
from .code_execution_utils import CodeExecutionResult
|
27
|
+
from .code_execution_utils import File
|
28
|
+
|
29
|
+
_SUPPORTED_IMAGE_TYPES = ['png', 'jpg', 'jpeg']
|
30
|
+
_SUPPORTED_DATA_FILE_TYPES = ['csv']
|
31
|
+
|
32
|
+
_IMPORTED_LIBRARIES = '''
|
33
|
+
import io
|
34
|
+
import math
|
35
|
+
import re
|
36
|
+
|
37
|
+
import matplotlib.pyplot as plt
|
38
|
+
import numpy as np
|
39
|
+
import pandas as pd
|
40
|
+
import scipy
|
41
|
+
|
42
|
+
def crop(s: str, max_chars: int = 64) -> str:
|
43
|
+
"""Crops a string to max_chars characters."""
|
44
|
+
return s[: max_chars - 3] + '...' if len(s) > max_chars else s
|
45
|
+
|
46
|
+
|
47
|
+
def explore_df(df: pd.DataFrame) -> None:
|
48
|
+
"""Prints some information about a pandas DataFrame."""
|
49
|
+
|
50
|
+
with pd.option_context(
|
51
|
+
'display.max_columns', None, 'display.expand_frame_repr', False
|
52
|
+
):
|
53
|
+
# Print the column names to never encounter KeyError when selecting one.
|
54
|
+
df_dtypes = df.dtypes
|
55
|
+
|
56
|
+
# Obtain information about data types and missing values.
|
57
|
+
df_nulls = (len(df) - df.isnull().sum()).apply(
|
58
|
+
lambda x: f'{x} / {df.shape[0]} non-null'
|
59
|
+
)
|
60
|
+
|
61
|
+
# Explore unique total values in columns using `.unique()`.
|
62
|
+
df_unique_count = df.apply(lambda x: len(x.unique()))
|
63
|
+
|
64
|
+
# Explore unique values in columns using `.unique()`.
|
65
|
+
df_unique = df.apply(lambda x: crop(str(list(x.unique()))))
|
66
|
+
|
67
|
+
df_info = pd.concat(
|
68
|
+
(
|
69
|
+
df_dtypes.rename('Dtype'),
|
70
|
+
df_nulls.rename('Non-Null Count'),
|
71
|
+
df_unique_count.rename('Unique Values Count'),
|
72
|
+
df_unique.rename('Unique Values'),
|
73
|
+
),
|
74
|
+
axis=1,
|
75
|
+
)
|
76
|
+
df_info.index.name = 'Columns'
|
77
|
+
print(f"""Total rows: {df.shape[0]}
|
78
|
+
Total columns: {df.shape[1]}
|
79
|
+
|
80
|
+
{df_info}""")
|
81
|
+
'''
|
82
|
+
|
83
|
+
|
84
|
+
def _get_code_interpreter_extension(resource_name: str = None):
|
85
|
+
"""Returns: Load or create the code interpreter extension."""
|
86
|
+
if not resource_name:
|
87
|
+
resource_name = os.environ.get('CODE_INTERPRETER_EXTENSION_NAME')
|
88
|
+
if resource_name:
|
89
|
+
new_code_interpreter = Extension(resource_name)
|
90
|
+
else:
|
91
|
+
print('No CODE_INTERPRETER_ID found in the environment. Create a new one.')
|
92
|
+
new_code_interpreter = Extension.from_hub('code_interpreter')
|
93
|
+
os.environ['CODE_INTERPRETER_EXTENSION_NAME'] = (
|
94
|
+
new_code_interpreter.gca_resource.name
|
95
|
+
)
|
96
|
+
return new_code_interpreter
|
97
|
+
|
98
|
+
|
99
|
+
class VertexAiCodeExecutor(BaseCodeExecutor):
|
100
|
+
"""A code executor that uses Vertex Code Interpreter Extension to execute code.
|
101
|
+
|
102
|
+
Attributes:
|
103
|
+
resource_name: If set, load the existing resource name of the code
|
104
|
+
interpreter extension instead of creating a new one. Format:
|
105
|
+
projects/123/locations/us-central1/extensions/456
|
106
|
+
"""
|
107
|
+
|
108
|
+
resource_name: str = None
|
109
|
+
"""
|
110
|
+
If set, load the existing resource name of the code interpreter extension
|
111
|
+
instead of creating a new one.
|
112
|
+
Format: projects/123/locations/us-central1/extensions/456
|
113
|
+
"""
|
114
|
+
|
115
|
+
_code_interpreter_extension: Extension
|
116
|
+
|
117
|
+
def __init__(
|
118
|
+
self,
|
119
|
+
resource_name: str = None,
|
120
|
+
**data,
|
121
|
+
):
|
122
|
+
"""Initializes the VertexAiCodeExecutor.
|
123
|
+
|
124
|
+
Args:
|
125
|
+
resource_name: If set, load the existing resource name of the code
|
126
|
+
interpreter extension instead of creating a new one. Format:
|
127
|
+
projects/123/locations/us-central1/extensions/456
|
128
|
+
**data: Additional keyword arguments to be passed to the base class.
|
129
|
+
"""
|
130
|
+
super().__init__(**data)
|
131
|
+
self.resource_name = resource_name
|
132
|
+
self._code_interpreter_extension = _get_code_interpreter_extension(
|
133
|
+
self.resource_name
|
134
|
+
)
|
135
|
+
|
136
|
+
@override
|
137
|
+
def execute_code(
|
138
|
+
self,
|
139
|
+
invocation_context: InvocationContext,
|
140
|
+
code_execution_input: CodeExecutionInput,
|
141
|
+
) -> CodeExecutionResult:
|
142
|
+
# Execute the code.
|
143
|
+
code_execution_result = self._execute_code_interpreter(
|
144
|
+
self._get_code_with_imports(code_execution_input.code),
|
145
|
+
code_execution_input.input_files,
|
146
|
+
code_execution_input.execution_id,
|
147
|
+
)
|
148
|
+
|
149
|
+
# Save output file as artifacts.
|
150
|
+
current_timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
|
151
|
+
file_name_prefix = '%s_' % str(current_timestamp)
|
152
|
+
saved_files = []
|
153
|
+
file_count = 0
|
154
|
+
for output_file in code_execution_result['output_files']:
|
155
|
+
file_type = output_file['name'].split('.')[-1]
|
156
|
+
file_name = file_name_prefix + '%d.%s' % (file_count, file_type)
|
157
|
+
if file_type in _SUPPORTED_IMAGE_TYPES:
|
158
|
+
file_count += 1
|
159
|
+
saved_files.append(
|
160
|
+
File(
|
161
|
+
name='plot_' + file_name,
|
162
|
+
content=output_file['contents'],
|
163
|
+
mime_type=f'image/{file_type}',
|
164
|
+
)
|
165
|
+
)
|
166
|
+
elif file_type in _SUPPORTED_DATA_FILE_TYPES:
|
167
|
+
file_count += 1
|
168
|
+
saved_files.append(
|
169
|
+
File(
|
170
|
+
name='data_' + file_name,
|
171
|
+
content=output_file['contents'],
|
172
|
+
mime_type=f'text/{file_type}',
|
173
|
+
)
|
174
|
+
)
|
175
|
+
else:
|
176
|
+
mime_type, _ = mimetypes.guess_type(file_name)
|
177
|
+
saved_files.append(
|
178
|
+
File(
|
179
|
+
name=file_name,
|
180
|
+
content=output_file['contents'],
|
181
|
+
mime_type=mime_type,
|
182
|
+
)
|
183
|
+
)
|
184
|
+
|
185
|
+
# Collect the final result.
|
186
|
+
return CodeExecutionResult(
|
187
|
+
stdout=code_execution_result.get('execution_result', ''),
|
188
|
+
stderr=code_execution_result.get('execution_error', ''),
|
189
|
+
output_files=saved_files,
|
190
|
+
)
|
191
|
+
|
192
|
+
def _execute_code_interpreter(
|
193
|
+
self,
|
194
|
+
code: str,
|
195
|
+
input_files: Optional[list[File]] = None,
|
196
|
+
session_id: Optional[str] = None,
|
197
|
+
) -> dict[str, Any]:
|
198
|
+
"""Executes the code interpreter extension.
|
199
|
+
|
200
|
+
Args:
|
201
|
+
code: The code to execute.
|
202
|
+
input_files: The input files to execute the code with.
|
203
|
+
session_id: The session ID to execute the code with.
|
204
|
+
|
205
|
+
Returns:
|
206
|
+
The response from the code interpreter extension.
|
207
|
+
"""
|
208
|
+
operation_params = {'code': code}
|
209
|
+
if input_files:
|
210
|
+
operation_params['files'] = [
|
211
|
+
{'name': f.name, 'contents': f.content} for f in input_files
|
212
|
+
]
|
213
|
+
if session_id:
|
214
|
+
operation_params['session_id'] = session_id
|
215
|
+
response = self._code_interpreter_extension.execute(
|
216
|
+
operation_id='execute',
|
217
|
+
operation_params=operation_params,
|
218
|
+
)
|
219
|
+
return response
|
220
|
+
|
221
|
+
def _get_code_with_imports(self, code: str) -> str:
|
222
|
+
"""Builds the code string with built-in imports.
|
223
|
+
|
224
|
+
Args:
|
225
|
+
code: The code to execute.
|
226
|
+
|
227
|
+
Returns:
|
228
|
+
The code string with built-in imports.
|
229
|
+
"""
|
230
|
+
return f"""
|
231
|
+
{_IMPORTED_LIBRARIES}
|
232
|
+
|
233
|
+
{code}
|
234
|
+
"""
|