agent-starter-pack 0.3.3__py3-none-any.whl → 0.21.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 (255) hide show
  1. agent_starter_pack/agents/README.md +7 -0
  2. agents/langgraph_base_react/template/.templateconfig.yaml → agent_starter_pack/agents/adk_a2a_base/.template/templateconfig.yaml +5 -10
  3. agent_starter_pack/agents/adk_a2a_base/README.md +37 -0
  4. src/deployment_targets/cloud_run/Dockerfile → agent_starter_pack/agents/adk_a2a_base/app/__init__.py +2 -14
  5. agent_starter_pack/agents/adk_a2a_base/app/agent.py +70 -0
  6. agent_starter_pack/agents/adk_a2a_base/notebooks/adk_a2a_app_testing.ipynb +583 -0
  7. agents/crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb → agent_starter_pack/agents/adk_a2a_base/notebooks/evaluating_adk_agent.ipynb +163 -199
  8. {agents/adk_base → agent_starter_pack/agents/adk_a2a_base}/tests/integration/test_agent.py +2 -2
  9. agents/adk_base/template/.templateconfig.yaml → agent_starter_pack/agents/adk_base/.template/templateconfig.yaml +4 -1
  10. {agents → agent_starter_pack/agents}/adk_base/README.md +1 -1
  11. agent_starter_pack/agents/adk_base/app/__init__.py +17 -0
  12. {agents → agent_starter_pack/agents}/adk_base/app/agent.py +5 -2
  13. {agents → agent_starter_pack/agents}/adk_base/notebooks/adk_app_testing.ipynb +128 -82
  14. agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb → agent_starter_pack/agents/adk_base/notebooks/evaluating_adk_agent.ipynb +181 -207
  15. agent_starter_pack/agents/adk_base/tests/integration/test_agent.py +58 -0
  16. agents/crewai_coding_crew/template/.templateconfig.yaml → agent_starter_pack/agents/adk_live/.template/templateconfig.yaml +5 -9
  17. agent_starter_pack/agents/adk_live/README.md +32 -0
  18. agent_starter_pack/agents/adk_live/app/__init__.py +17 -0
  19. agent_starter_pack/agents/adk_live/app/agent.py +51 -0
  20. agent_starter_pack/agents/adk_live/tests/unit/test_dummy.py +38 -0
  21. agents/agentic_rag/template/.templateconfig.yaml → agent_starter_pack/agents/agentic_rag/.template/templateconfig.yaml +7 -3
  22. {agents → agent_starter_pack/agents}/agentic_rag/README.md +1 -1
  23. agent_starter_pack/agents/agentic_rag/app/__init__.py +17 -0
  24. {agents → agent_starter_pack/agents}/agentic_rag/app/agent.py +8 -4
  25. {agents → agent_starter_pack/agents}/agentic_rag/notebooks/adk_app_testing.ipynb +128 -82
  26. agent_starter_pack/agents/agentic_rag/notebooks/evaluating_adk_agent.ipynb +1535 -0
  27. {agents → agent_starter_pack/agents}/agentic_rag/tests/integration/test_agent.py +3 -3
  28. agent_starter_pack/agents/langgraph_base/.template/templateconfig.yaml +31 -0
  29. agent_starter_pack/agents/langgraph_base/README.md +30 -0
  30. agent_starter_pack/agents/langgraph_base/app/__init__.py +17 -0
  31. agent_starter_pack/agents/langgraph_base/app/agent.py +34 -0
  32. {agents/crewai_coding_crew → agent_starter_pack/agents/langgraph_base}/notebooks/evaluating_langgraph_agent.ipynb +30 -17
  33. {agents/langgraph_base_react → agent_starter_pack/agents/langgraph_base}/tests/integration/test_agent.py +2 -2
  34. {src → agent_starter_pack}/base_template/.gitignore +5 -3
  35. agent_starter_pack/base_template/GEMINI.md +5 -0
  36. agent_starter_pack/base_template/Makefile +339 -0
  37. agent_starter_pack/base_template/README.md +267 -0
  38. agent_starter_pack/base_template/deployment/README.md +11 -0
  39. {src → agent_starter_pack}/base_template/deployment/terraform/apis.tf +2 -2
  40. {src → agent_starter_pack}/base_template/deployment/terraform/dev/apis.tf +6 -1
  41. {src → agent_starter_pack}/base_template/deployment/terraform/dev/iam.tf +12 -11
  42. {src → agent_starter_pack}/base_template/deployment/terraform/dev/providers.tf +5 -1
  43. {src → agent_starter_pack}/base_template/deployment/terraform/dev/storage.tf +1 -1
  44. {src → agent_starter_pack}/base_template/deployment/terraform/dev/variables.tf +10 -10
  45. agent_starter_pack/base_template/deployment/terraform/dev/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +193 -0
  46. agent_starter_pack/base_template/deployment/terraform/github.tf +337 -0
  47. {src → agent_starter_pack}/base_template/deployment/terraform/iam.tf +20 -41
  48. {src → agent_starter_pack}/base_template/deployment/terraform/locals.tf +10 -3
  49. {src/resources/setup_cicd → agent_starter_pack/base_template/deployment/terraform}/providers.tf +8 -1
  50. {src → agent_starter_pack}/base_template/deployment/terraform/service_accounts.tf +7 -8
  51. agent_starter_pack/base_template/deployment/terraform/sql/completions.sql +138 -0
  52. {src → agent_starter_pack}/base_template/deployment/terraform/storage.tf +7 -16
  53. {src → agent_starter_pack}/base_template/deployment/terraform/variables.tf +61 -28
  54. {src → agent_starter_pack}/base_template/deployment/terraform/vars/env.tfvars +6 -1
  55. agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'github_actions' %}wif.tf{% else %}unused_wif.tf{% endif %} +43 -0
  56. src/base_template/deployment/terraform/build_triggers.tf → agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}build_triggers.tf{% else %}unused_build_triggers.tf{% endif %} +55 -38
  57. agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +206 -0
  58. {src → agent_starter_pack}/base_template/pyproject.toml +24 -37
  59. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +132 -0
  60. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +65 -0
  61. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +259 -0
  62. src/base_template/deployment/cd/deploy-to-prod.yaml → agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml +38 -30
  63. src/base_template/deployment/ci/pr_checks.yaml → agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/pr_checks.yaml +5 -5
  64. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +322 -0
  65. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/telemetry.py +96 -0
  66. {src/base_template/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/typing.py +7 -9
  67. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/__init__.py +25 -0
  68. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/part_converter.py +138 -0
  69. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/__init__.py +13 -0
  70. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/a2a_agent_executor.py +265 -0
  71. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/task_result_aggregator.py +152 -0
  72. agent_starter_pack/cli/commands/create.py +1256 -0
  73. agent_starter_pack/cli/commands/enhance.py +611 -0
  74. agent_starter_pack/cli/commands/list.py +203 -0
  75. agent_starter_pack/cli/commands/register_gemini_enterprise.py +1070 -0
  76. agent_starter_pack/cli/commands/setup_cicd.py +862 -0
  77. {src → agent_starter_pack}/cli/main.py +10 -2
  78. {src → agent_starter_pack}/cli/utils/cicd.py +139 -48
  79. agent_starter_pack/cli/utils/gcp.py +263 -0
  80. agent_starter_pack/cli/utils/logging.py +103 -0
  81. agent_starter_pack/cli/utils/remote_template.py +677 -0
  82. agent_starter_pack/cli/utils/template.py +1466 -0
  83. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/process_data.py +1 -1
  84. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/submit_pipeline.py +20 -6
  85. {src → agent_starter_pack}/data_ingestion/pyproject.toml +1 -0
  86. {src → agent_starter_pack}/data_ingestion/uv.lock +602 -494
  87. agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +484 -0
  88. agent_starter_pack/deployment_targets/agent_engine/tests/load_test/README.md +84 -0
  89. agent_starter_pack/deployment_targets/agent_engine/tests/load_test/load_test.py +424 -0
  90. agent_starter_pack/deployment_targets/agent_engine/tests/{% if cookiecutter.is_a2a %}helpers.py{% else %}unused_helpers.py{% endif %} +138 -0
  91. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +263 -0
  92. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/deploy.py +414 -0
  93. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_adk_live %}expose_app.py{% else %}unused_expose_app.py{% endif %} +519 -0
  94. agent_starter_pack/deployment_targets/cloud_run/Dockerfile +51 -0
  95. agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +243 -0
  96. agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/service.tf +417 -0
  97. agent_starter_pack/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +705 -0
  98. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +321 -0
  99. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/README.md +165 -0
  100. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +329 -0
  101. agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/fast_api_app.py +556 -0
  102. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package-lock.json +79 -1044
  103. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package.json +1 -9
  104. agent_starter_pack/frontends/adk_live_react/frontend/src/App.tsx +65 -0
  105. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/Logger.tsx +8 -3
  106. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/logger.scss +26 -0
  107. agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/SidePanel.tsx +516 -0
  108. agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/side-panel.scss +563 -0
  109. agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/TranscriptionPreview.tsx +106 -0
  110. agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/transcription-preview.scss +150 -0
  111. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-live-api.ts +8 -2
  112. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/multimodal-live-types.ts +40 -2
  113. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-recorder.ts +1 -1
  114. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-streamer.ts +1 -1
  115. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/multimodal-live-client.ts +210 -24
  116. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/utils.ts +27 -5
  117. agent_starter_pack/resources/docs/adk-cheatsheet.md +1628 -0
  118. agent_starter_pack/resources/locks/uv-adk_a2a_base-agent_engine.lock +4966 -0
  119. agent_starter_pack/resources/locks/uv-adk_a2a_base-cloud_run.lock +5011 -0
  120. agent_starter_pack/resources/locks/uv-adk_base-agent_engine.lock +4946 -0
  121. agent_starter_pack/resources/locks/uv-adk_base-cloud_run.lock +4991 -0
  122. agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +4963 -0
  123. agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +5006 -0
  124. agent_starter_pack/resources/locks/uv-agentic_rag-agent_engine.lock +5487 -0
  125. agent_starter_pack/resources/locks/uv-agentic_rag-cloud_run.lock +5532 -0
  126. agent_starter_pack/resources/locks/uv-langgraph_base-agent_engine.lock +5788 -0
  127. agent_starter_pack/resources/locks/uv-langgraph_base-cloud_run.lock +5811 -0
  128. {src → agent_starter_pack}/utils/generate_locks.py +15 -12
  129. {src → agent_starter_pack}/utils/lock_utils.py +4 -7
  130. {src → agent_starter_pack}/utils/watch_and_rebuild.py +2 -2
  131. agent_starter_pack-0.21.0.dist-info/METADATA +182 -0
  132. agent_starter_pack-0.21.0.dist-info/RECORD +171 -0
  133. agent_starter_pack-0.21.0.dist-info/entry_points.txt +2 -0
  134. llm.txt +362 -0
  135. agent_starter_pack-0.3.3.dist-info/METADATA +0 -164
  136. agent_starter_pack-0.3.3.dist-info/RECORD +0 -176
  137. agent_starter_pack-0.3.3.dist-info/entry_points.txt +0 -2
  138. agents/crewai_coding_crew/README.md +0 -34
  139. agents/crewai_coding_crew/app/agent.py +0 -86
  140. agents/crewai_coding_crew/app/crew/config/agents.yaml +0 -39
  141. agents/crewai_coding_crew/app/crew/config/tasks.yaml +0 -37
  142. agents/crewai_coding_crew/app/crew/crew.py +0 -71
  143. agents/crewai_coding_crew/tests/integration/test_agent.py +0 -47
  144. agents/langgraph_base_react/README.md +0 -9
  145. agents/langgraph_base_react/app/agent.py +0 -73
  146. agents/live_api/README.md +0 -37
  147. agents/live_api/app/agent.py +0 -78
  148. agents/live_api/app/server.py +0 -196
  149. agents/live_api/app/templates.py +0 -51
  150. agents/live_api/app/vector_store.py +0 -55
  151. agents/live_api/template/.templateconfig.yaml +0 -29
  152. agents/live_api/tests/integration/test_server_e2e.py +0 -254
  153. agents/live_api/tests/load_test/load_test.py +0 -40
  154. agents/live_api/tests/unit/test_server.py +0 -143
  155. src/base_template/Makefile +0 -72
  156. src/base_template/README.md +0 -208
  157. src/base_template/app/__init__.py +0 -3
  158. src/base_template/app/utils/tracing.py +0 -155
  159. src/base_template/deployment/README.md +0 -126
  160. src/base_template/deployment/cd/staging.yaml +0 -216
  161. src/base_template/deployment/terraform/dev/log_sinks.tf +0 -63
  162. src/base_template/deployment/terraform/log_sinks.tf +0 -70
  163. src/base_template/deployment/terraform/providers.tf +0 -37
  164. src/cli/commands/create.py +0 -664
  165. src/cli/commands/setup_cicd.py +0 -829
  166. src/cli/utils/gcp.py +0 -117
  167. src/cli/utils/logging.py +0 -51
  168. src/cli/utils/template.py +0 -737
  169. src/deployment_targets/agent_engine/app/agent_engine_app.py +0 -336
  170. src/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -1025
  171. src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +0 -183
  172. src/deployment_targets/agent_engine/tests/load_test/README.md +0 -42
  173. src/deployment_targets/agent_engine/tests/load_test/load_test.py +0 -107
  174. src/deployment_targets/cloud_run/app/server.py +0 -154
  175. src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +0 -249
  176. src/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +0 -0
  177. src/deployment_targets/cloud_run/tests/load_test/README.md +0 -83
  178. src/deployment_targets/cloud_run/tests/load_test/load_test.py +0 -118
  179. src/deployment_targets/cloud_run/uv.lock +0 -6952
  180. src/frontends/live_api_react/frontend/src/App.tsx +0 -205
  181. src/frontends/live_api_react/frontend/src/components/control-tray/ControlTray.tsx +0 -217
  182. src/frontends/live_api_react/frontend/src/components/control-tray/control-tray.scss +0 -201
  183. src/frontends/live_api_react/frontend/src/components/side-panel/SidePanel.tsx +0 -161
  184. src/frontends/live_api_react/frontend/src/components/side-panel/side-panel.scss +0 -285
  185. src/frontends/streamlit/frontend/side_bar.py +0 -214
  186. src/frontends/streamlit/frontend/streamlit_app.py +0 -265
  187. src/frontends/streamlit/frontend/style/app_markdown.py +0 -37
  188. src/frontends/streamlit/frontend/utils/chat_utils.py +0 -67
  189. src/frontends/streamlit/frontend/utils/local_chat_history.py +0 -125
  190. src/frontends/streamlit/frontend/utils/message_editing.py +0 -59
  191. src/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -217
  192. src/frontends/streamlit/frontend/utils/stream_handler.py +0 -301
  193. src/frontends/streamlit/frontend/utils/title_summary.py +0 -94
  194. src/frontends/streamlit_adk/frontend/side_bar.py +0 -214
  195. src/frontends/streamlit_adk/frontend/streamlit_app.py +0 -314
  196. src/frontends/streamlit_adk/frontend/style/app_markdown.py +0 -37
  197. src/frontends/streamlit_adk/frontend/utils/chat_utils.py +0 -84
  198. src/frontends/streamlit_adk/frontend/utils/local_chat_history.py +0 -110
  199. src/frontends/streamlit_adk/frontend/utils/message_editing.py +0 -61
  200. src/frontends/streamlit_adk/frontend/utils/multimodal_utils.py +0 -223
  201. src/frontends/streamlit_adk/frontend/utils/stream_handler.py +0 -311
  202. src/frontends/streamlit_adk/frontend/utils/title_summary.py +0 -129
  203. src/resources/containers/data_processing/Dockerfile +0 -27
  204. src/resources/containers/e2e-tests/Dockerfile +0 -19
  205. src/resources/idx/.idx/dev.nix +0 -57
  206. src/resources/idx/idx-template.json +0 -21
  207. src/resources/idx/idx-template.nix +0 -26
  208. src/resources/locks/uv-adk_base-agent_engine.lock +0 -5338
  209. src/resources/locks/uv-adk_base-cloud_run.lock +0 -5930
  210. src/resources/locks/uv-agentic_rag-agent_engine.lock +0 -5528
  211. src/resources/locks/uv-agentic_rag-cloud_run.lock +0 -6120
  212. src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +0 -6231
  213. src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +0 -6839
  214. src/resources/locks/uv-langgraph_base_react-agent_engine.lock +0 -5233
  215. src/resources/locks/uv-langgraph_base_react-cloud_run.lock +0 -5862
  216. src/resources/locks/uv-live_api-cloud_run.lock +0 -5832
  217. src/resources/setup_cicd/cicd_variables.tf +0 -41
  218. src/resources/setup_cicd/github.tf +0 -87
  219. {agents → agent_starter_pack/agents}/agentic_rag/app/retrievers.py +0 -0
  220. {agents → agent_starter_pack/agents}/agentic_rag/app/templates.py +0 -0
  221. {src → agent_starter_pack}/base_template/deployment/terraform/dev/vars/env.tfvars +0 -0
  222. {src → agent_starter_pack}/base_template/tests/unit/test_dummy.py +0 -0
  223. {src/deployment_targets/agent_engine/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/gcs.py +0 -0
  224. {src → agent_starter_pack}/cli/utils/__init__.py +0 -0
  225. {src → agent_starter_pack}/cli/utils/datastores.py +0 -0
  226. {src → agent_starter_pack}/cli/utils/version.py +0 -0
  227. {src → agent_starter_pack}/data_ingestion/README.md +0 -0
  228. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/ingest_data.py +0 -0
  229. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/pipeline.py +0 -0
  230. {src → agent_starter_pack}/deployment_targets/agent_engine/deployment_metadata.json +0 -0
  231. {src → agent_starter_pack}/deployment_targets/agent_engine/tests/load_test/.results/.placeholder +0 -0
  232. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/favicon.ico +0 -0
  233. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/index.html +0 -0
  234. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/robots.txt +0 -0
  235. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.scss +0 -0
  236. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.test.tsx +0 -0
  237. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/AudioPulse.tsx +0 -0
  238. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/audio-pulse.scss +0 -0
  239. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/mock-logs.ts +0 -0
  240. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/contexts/LiveAPIContext.tsx +0 -0
  241. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-media-stream-mux.ts +0 -0
  242. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-screen-capture.ts +0 -0
  243. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-webcam.ts +0 -0
  244. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.css +0 -0
  245. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.tsx +0 -0
  246. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/react-app-env.d.ts +0 -0
  247. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/reportWebVitals.ts +0 -0
  248. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/setupTests.ts +0 -0
  249. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audioworklet-registry.ts +0 -0
  250. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/store-logger.ts +0 -0
  251. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/audio-processing.ts +0 -0
  252. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/vol-meter.ts +0 -0
  253. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/tsconfig.json +0 -0
  254. {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/WHEEL +0 -0
  255. {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,677 @@
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 logging
16
+ import os
17
+ import pathlib
18
+ import re
19
+ import shutil
20
+ import subprocess
21
+ import sys
22
+ import tempfile
23
+ from dataclasses import dataclass
24
+ from typing import Any
25
+
26
+ if sys.version_info >= (3, 11):
27
+ import tomllib
28
+ else:
29
+ import tomli as tomllib
30
+ from jinja2 import Environment
31
+ from packaging import version as pkg_version
32
+ from rich.console import Console
33
+
34
+
35
+ @dataclass
36
+ class RemoteTemplateSpec:
37
+ """Parsed remote template specification."""
38
+
39
+ repo_url: str
40
+ template_path: str
41
+ git_ref: str
42
+ is_adk_samples: bool = False
43
+
44
+
45
+ def parse_agent_spec(agent_spec: str) -> RemoteTemplateSpec | None:
46
+ """Parse agent specification to determine if it's a remote template.
47
+
48
+ Args:
49
+ agent_spec: Agent specification string
50
+
51
+ Returns:
52
+ RemoteTemplateSpec if remote template, None if local template
53
+ """
54
+ # Check for local@ prefix
55
+ if agent_spec.startswith("local@"):
56
+ return None
57
+
58
+ # Check for adk@ shortcut
59
+ if agent_spec.startswith("adk@"):
60
+ sample_name = agent_spec[4:] # Remove "adk@" prefix
61
+ return RemoteTemplateSpec(
62
+ repo_url="https://github.com/google/adk-samples",
63
+ template_path=f"python/agents/{sample_name}",
64
+ git_ref="main",
65
+ is_adk_samples=True,
66
+ )
67
+
68
+ # GitHub /tree/ URL pattern
69
+ tree_pattern = r"^(https?://[^/]+/[^/]+/[^/]+)/tree/([^/]+)/(.*)$"
70
+ match = re.match(tree_pattern, agent_spec)
71
+ if match:
72
+ repo_url = match.group(1)
73
+ git_ref = match.group(2)
74
+ template_path = match.group(3)
75
+ return RemoteTemplateSpec(
76
+ repo_url=repo_url,
77
+ template_path=template_path.strip("/"),
78
+ git_ref=git_ref,
79
+ )
80
+
81
+ # General remote pattern: <repo_url>[/<path>][@<ref>]
82
+ # Handles github.com, gitlab.com, etc.
83
+ remote_pattern = r"^(https?://[^/]+/[^/]+/[^/]+)(?:/(.*?))?(?:@([^/]+))?/?$"
84
+ match = re.match(remote_pattern, agent_spec)
85
+ if match:
86
+ repo_url = match.group(1)
87
+ template_path_with_ref = match.group(2) or ""
88
+ git_ref_from_url = match.group(3)
89
+
90
+ # Separate path and ref if ref is part of the path
91
+ template_path = template_path_with_ref
92
+ git_ref = git_ref_from_url or "main"
93
+
94
+ if "@" in template_path:
95
+ path_parts = template_path.split("@")
96
+ template_path = path_parts[0]
97
+ git_ref = path_parts[1]
98
+
99
+ # Check if this is the ADK samples repository
100
+ is_adk_samples = repo_url == "https://github.com/google/adk-samples"
101
+
102
+ return RemoteTemplateSpec(
103
+ repo_url=repo_url,
104
+ template_path=template_path.strip("/"),
105
+ git_ref=git_ref,
106
+ is_adk_samples=is_adk_samples,
107
+ )
108
+
109
+ # GitHub shorthand: <org>/<repo>[/<path>][@<ref>]
110
+ github_shorthand_pattern = r"^([^/]+)/([^/]+)(?:/(.*?))?(?:@([^/]+))?/?$"
111
+ match = re.match(github_shorthand_pattern, agent_spec)
112
+ if match and "/" in agent_spec: # Ensure it has at least one slash
113
+ org = match.group(1)
114
+ repo = match.group(2)
115
+ template_path = match.group(3) or ""
116
+ git_ref = match.group(4) or "main"
117
+
118
+ # Check if this is the ADK samples repository
119
+ is_adk_samples = org == "google" and repo == "adk-samples"
120
+
121
+ return RemoteTemplateSpec(
122
+ repo_url=f"https://github.com/{org}/{repo}",
123
+ template_path=template_path,
124
+ git_ref=git_ref,
125
+ is_adk_samples=is_adk_samples,
126
+ )
127
+
128
+ return None
129
+
130
+
131
+ def check_and_execute_with_version_lock(
132
+ template_dir: pathlib.Path,
133
+ original_agent_spec: str | None = None,
134
+ locked: bool = False,
135
+ ) -> bool:
136
+ """Check if remote template has agent-starter-pack version lock and execute if found.
137
+
138
+ Args:
139
+ template_dir: Path to the fetched template directory
140
+ original_agent_spec: The original agent spec (remote URL) to replace with local path
141
+ locked: Whether this is already a locked execution (prevents recursion)
142
+
143
+ Returns:
144
+ True if version lock was found and executed, False otherwise
145
+ """
146
+ # Skip version locking if we're already in a locked execution (prevents recursion)
147
+ if locked:
148
+ return False
149
+ uv_lock_path = template_dir / "uv.lock"
150
+ version = parse_agent_starter_pack_version_from_lock(uv_lock_path)
151
+
152
+ if version:
153
+ console = Console()
154
+ console.print(
155
+ f"🔒 Remote template requires agent-starter-pack version {version}",
156
+ style="bold blue",
157
+ )
158
+ console.print(
159
+ f"📦 Switching to version {version}...",
160
+ style="dim",
161
+ )
162
+
163
+ # Reconstruct the original command but with version constraint
164
+ import sys
165
+
166
+ original_args = sys.argv[1:] # Skip 'agent-starter-pack' or script name
167
+
168
+ # Add version lock specific parameters and handle remote URL replacement
169
+ if original_agent_spec:
170
+ # Check if --agent flag exists in original args
171
+ agent_flag_exists = "--agent" in original_args or "-a" in original_args
172
+
173
+ if agent_flag_exists:
174
+ # Replace remote agent spec with local path
175
+ original_args = [
176
+ f"local@{template_dir}" if arg == original_agent_spec else arg
177
+ for arg in original_args
178
+ ]
179
+ else:
180
+ # Agent was selected interactively, add --agent flag
181
+ original_args.extend(["--agent", f"local@{template_dir}"])
182
+
183
+ # Add version lock flags only for ASP versions 0.14.1 and above
184
+ if pkg_version.parse(version) > pkg_version.parse("0.14.1"):
185
+ original_args.extend(["--skip-welcome", "--locked"])
186
+
187
+ try:
188
+ # Check if uvx is available
189
+ subprocess.run(["uvx", "--version"], capture_output=True, check=True)
190
+ except (subprocess.CalledProcessError, FileNotFoundError):
191
+ console.print(
192
+ f"❌ Remote template requires agent-starter-pack version {version}, but 'uvx' is not installed",
193
+ style="bold red",
194
+ )
195
+ console.print(
196
+ "💡 Install uv to use version-locked remote templates:",
197
+ style="bold blue",
198
+ )
199
+ console.print(" curl -LsSf https://astral.sh/uv/install.sh | sh")
200
+ console.print(
201
+ " OR visit: https://docs.astral.sh/uv/getting-started/installation/"
202
+ )
203
+ sys.exit(1)
204
+
205
+ try:
206
+ # Execute uvx with the locked version
207
+ cmd = ["uvx", f"agent-starter-pack@{version}", *original_args]
208
+ logging.debug(f"Executing nested command: {' '.join(cmd)}")
209
+ subprocess.run(cmd, check=True)
210
+ return True
211
+
212
+ except subprocess.CalledProcessError as e:
213
+ console.print(
214
+ f"❌ Failed to execute with locked version {version}: {e}",
215
+ style="bold red",
216
+ )
217
+ console.print(
218
+ "⚠️ Continuing with current version, but compatibility is not guaranteed",
219
+ style="yellow",
220
+ )
221
+ # Continue with current execution instead of failing completely
222
+
223
+ return False
224
+
225
+
226
+ def fetch_remote_template(
227
+ spec: RemoteTemplateSpec,
228
+ original_agent_spec: str | None = None,
229
+ locked: bool = False,
230
+ ) -> tuple[pathlib.Path, pathlib.Path]:
231
+ """Fetch remote template and return path to template directory.
232
+
233
+ Uses Git to clone the remote repository. If the template contains a uv.lock
234
+ with agent-starter-pack version constraint, will execute nested uvx command.
235
+
236
+ Args:
237
+ spec: Remote template specification
238
+ original_agent_spec: Original agent spec string (used to prevent recursion)
239
+ locked: Whether this is already a locked execution (prevents recursion)
240
+
241
+ Returns:
242
+ A tuple containing:
243
+ - Path to the fetched template directory.
244
+ - Path to the top-level temporary directory that should be cleaned up.
245
+ """
246
+ temp_dir = tempfile.mkdtemp(prefix="asp_remote_template_")
247
+ temp_path = pathlib.Path(temp_dir)
248
+ repo_path = temp_path / "repo"
249
+
250
+ # Attempt Git Clone
251
+ try:
252
+ clone_url = spec.repo_url
253
+ clone_cmd = [
254
+ "git",
255
+ "clone",
256
+ "--depth",
257
+ "1",
258
+ "--branch",
259
+ spec.git_ref,
260
+ clone_url,
261
+ str(repo_path),
262
+ ]
263
+ logging.debug(
264
+ f"Attempting to clone remote template with Git: {' '.join(clone_cmd)}"
265
+ )
266
+ # GIT_TERMINAL_PROMPT=0 prevents git from prompting for credentials
267
+ subprocess.run(
268
+ clone_cmd,
269
+ capture_output=True,
270
+ text=True,
271
+ check=True,
272
+ encoding="utf-8",
273
+ env={**os.environ, "GIT_TERMINAL_PROMPT": "0"},
274
+ )
275
+ logging.debug("Git clone successful.")
276
+ except subprocess.CalledProcessError as e:
277
+ shutil.rmtree(temp_path, ignore_errors=True)
278
+ raise RuntimeError(f"Git clone failed: {e.stderr.strip()}") from e
279
+
280
+ # Process the successfully fetched template
281
+ try:
282
+ if spec.template_path:
283
+ template_dir = repo_path / spec.template_path
284
+ else:
285
+ template_dir = repo_path
286
+
287
+ if not template_dir.exists():
288
+ raise FileNotFoundError(
289
+ f"Template path not found in the repository: {spec.template_path}"
290
+ )
291
+
292
+ # Check for version lock and execute nested command if found
293
+ if check_and_execute_with_version_lock(
294
+ template_dir, original_agent_spec, locked
295
+ ):
296
+ # If we executed with locked version, the nested process will handle everything
297
+ # Clean up and exit successfully
298
+ shutil.rmtree(temp_path, ignore_errors=True)
299
+ # Exit with success since the nested command will handle the rest
300
+ sys.exit(0)
301
+
302
+ return template_dir, temp_path
303
+ except Exception as e:
304
+ # Clean up on error
305
+ shutil.rmtree(temp_path, ignore_errors=True)
306
+ raise RuntimeError(
307
+ f"An unexpected error occurred after fetching remote template: {e}"
308
+ ) from e
309
+
310
+
311
+ def _infer_agent_directory_for_adk(
312
+ template_dir: pathlib.Path, is_adk_sample: bool
313
+ ) -> dict[str, Any]:
314
+ """Infer agent configuration for ADK samples only using Python conventions.
315
+
316
+ Args:
317
+ template_dir: Path to template directory
318
+ is_adk_sample: Whether this is an ADK sample
319
+
320
+ Returns:
321
+ Dictionary with inferred configuration, or empty dict if not ADK sample
322
+ """
323
+ if not is_adk_sample:
324
+ return {}
325
+
326
+ # Convert folder name to Python package convention (hyphens to underscores)
327
+ folder_name = template_dir.name
328
+ agent_directory = folder_name.replace("-", "_")
329
+
330
+ logging.debug(
331
+ f"Inferred agent_directory '{agent_directory}' from folder name '{folder_name}' for ADK sample"
332
+ )
333
+
334
+ return {
335
+ "settings": {
336
+ "agent_directory": agent_directory,
337
+ },
338
+ "has_explicit_config": False, # Track that this was inferred
339
+ }
340
+
341
+
342
+ def load_remote_template_config(
343
+ template_dir: pathlib.Path,
344
+ cli_overrides: dict[str, Any] | None = None,
345
+ is_adk_sample: bool = False,
346
+ ) -> dict[str, Any]:
347
+ """Load template configuration from remote template's pyproject.toml with CLI overrides.
348
+
349
+ Loads configuration from [tool.agent-starter-pack] section with fallbacks
350
+ to [project] section for name and description if not specified. CLI overrides
351
+ take precedence over all other sources. For ADK samples without explicit config,
352
+ uses smart inference for agent directory naming.
353
+
354
+ Args:
355
+ template_dir: Path to template directory
356
+ cli_overrides: Configuration overrides from CLI (takes highest precedence)
357
+ is_adk_sample: Whether this is an ADK sample (enables smart inference)
358
+
359
+ Returns:
360
+ Template configuration dictionary with merged sources
361
+ """
362
+ config: dict[str, Any] = {}
363
+ has_explicit_config = False
364
+
365
+ # Start with defaults
366
+ defaults = {
367
+ "base_template": "adk_base",
368
+ "name": template_dir.name,
369
+ "description": "",
370
+ "agent_directory": "app", # Default for non-ADK samples
371
+ }
372
+ config.update(defaults)
373
+
374
+ # Load from pyproject.toml if it exists
375
+ pyproject_path = template_dir / "pyproject.toml"
376
+ if pyproject_path.exists():
377
+ try:
378
+ with open(pyproject_path, "rb") as f:
379
+ pyproject_data = tomllib.load(f)
380
+
381
+ # Extract the agent-starter-pack configuration
382
+ toml_config = pyproject_data.get("tool", {}).get("agent-starter-pack", {})
383
+
384
+ # Fallback to [project] fields if not specified in agent-starter-pack section
385
+ project_info = pyproject_data.get("project", {})
386
+
387
+ # Track if we have explicit configuration
388
+ has_explicit_config = bool(toml_config)
389
+
390
+ # Apply pyproject.toml configuration (overrides defaults)
391
+ if toml_config:
392
+ config.update(toml_config)
393
+ logging.debug("Found explicit [tool.agent-starter-pack] configuration")
394
+
395
+ # Apply [project] fallbacks if not already set
396
+ if "name" not in toml_config and "name" in project_info:
397
+ config["name"] = project_info["name"]
398
+
399
+ if "description" not in toml_config and "description" in project_info:
400
+ config["description"] = project_info["description"]
401
+
402
+ logging.debug(f"Loaded template config from {pyproject_path}")
403
+ except Exception as e:
404
+ logging.error(f"Error loading pyproject.toml config: {e}")
405
+ else:
406
+ # No pyproject.toml found
407
+ if is_adk_sample:
408
+ logging.debug(
409
+ f"No pyproject.toml found for ADK sample {template_dir.name}, will use inference"
410
+ )
411
+ else:
412
+ logging.debug(
413
+ f"No pyproject.toml found for template {template_dir.name}, using defaults"
414
+ )
415
+
416
+ # Apply ADK inference if no explicit config and this is an ADK sample
417
+ if not has_explicit_config and is_adk_sample:
418
+ try:
419
+ inferred_config = _infer_agent_directory_for_adk(
420
+ template_dir, is_adk_sample
421
+ )
422
+ config.update(inferred_config)
423
+ logging.debug("Applied ADK inference for template without explicit config")
424
+ except Exception as e:
425
+ logging.warning(f"Failed to apply ADK inference for {template_dir}: {e}")
426
+ # Continue with default configuration
427
+
428
+ # Add metadata about configuration source
429
+ config["has_explicit_config"] = bool(has_explicit_config)
430
+
431
+ # Apply CLI overrides (highest precedence) using deep merge
432
+ if cli_overrides:
433
+ config = merge_template_configs(config, cli_overrides)
434
+ logging.debug(f"Applied CLI overrides: {cli_overrides}")
435
+
436
+ return config
437
+
438
+
439
+ def get_base_template_name(config: dict[str, Any]) -> str:
440
+ """Get base template name from remote template config.
441
+
442
+ Args:
443
+ config: Template configuration dictionary
444
+
445
+ Returns:
446
+ Base template name (defaults to "adk_base")
447
+ """
448
+ return config.get("base_template", "adk_base")
449
+
450
+
451
+ def merge_template_configs(
452
+ base_config: dict[str, Any], remote_config: dict[str, Any]
453
+ ) -> dict[str, Any]:
454
+ """Merge base template config with remote template config using a deep merge.
455
+
456
+ Args:
457
+ base_config: Base template configuration
458
+ remote_config: Remote template configuration
459
+
460
+ Returns:
461
+ Merged configuration with remote overriding base
462
+ """
463
+ import copy
464
+
465
+ def deep_merge(d1: dict[str, Any], d2: dict[str, Any]) -> dict[str, Any]:
466
+ """Recursively merges d2 into d1."""
467
+ for k, v in d2.items():
468
+ if k in d1 and isinstance(d1[k], dict) and isinstance(v, dict):
469
+ d1[k] = deep_merge(d1[k], v)
470
+ else:
471
+ d1[k] = v
472
+ return d1
473
+
474
+ # Start with a deep copy of the base to avoid modifying it
475
+ merged_config = copy.deepcopy(base_config)
476
+
477
+ # Perform the deep merge
478
+ return deep_merge(merged_config, remote_config)
479
+
480
+
481
+ def discover_adk_agents(repo_path: pathlib.Path) -> dict[int, dict[str, Any]]:
482
+ """Discover and load all ADK agents from a repository with inference support.
483
+
484
+ Args:
485
+ repo_path: Path to the cloned ADK samples repository
486
+
487
+ Returns:
488
+ Dictionary mapping agent numbers to agent info with keys:
489
+ - name: Agent display name
490
+ - description: Agent description
491
+ - path: Relative path from repo root
492
+ - spec: adk@ specification string
493
+ - has_explicit_config: Whether agent has explicit configuration
494
+ """
495
+ import logging
496
+
497
+ adk_agents = {}
498
+
499
+ # Search specifically for agents in python/agents/* directories
500
+ agents_dir = repo_path / "python" / "agents"
501
+ logging.debug(f"Looking for agents in: {agents_dir}")
502
+ if agents_dir.exists():
503
+ all_items = list(agents_dir.iterdir())
504
+ logging.debug(
505
+ f"Found items in agents directory: {[item.name for item in all_items]}"
506
+ )
507
+
508
+ # Collect all agents first, then sort by configuration type
509
+ all_agents = []
510
+
511
+ for agent_dir in sorted(agents_dir.iterdir()):
512
+ if not agent_dir.is_dir():
513
+ logging.debug(f"Skipping non-directory: {agent_dir.name}")
514
+ continue
515
+ logging.debug(f"Processing agent directory: {agent_dir.name}")
516
+
517
+ try:
518
+ # Load configuration with ADK inference support
519
+ config = load_remote_template_config(
520
+ template_dir=agent_dir, is_adk_sample=True
521
+ )
522
+
523
+ agent_name = config.get("name", agent_dir.name)
524
+ description = config.get("description", "")
525
+ has_explicit_config = config.get("has_explicit_config", False)
526
+
527
+ # Get the relative path from repo root
528
+ relative_path = agent_dir.relative_to(repo_path)
529
+ agent_spec_name = agent_dir.name
530
+
531
+ agent_info = {
532
+ "name": agent_name,
533
+ "description": description,
534
+ "path": str(relative_path),
535
+ "spec": f"adk@{agent_spec_name}",
536
+ "has_explicit_config": has_explicit_config,
537
+ }
538
+ all_agents.append(agent_info)
539
+
540
+ except Exception as e:
541
+ logging.warning(f"Could not load agent from {agent_dir}: {e}")
542
+
543
+ # Sort agents: explicit config first, then inferred (both alphabetically within their groups)
544
+ all_agents.sort(key=lambda x: (not x["has_explicit_config"], x["name"].lower()))
545
+
546
+ # Convert to numbered dictionary
547
+ for i, agent_info in enumerate(all_agents, 1):
548
+ adk_agents[i] = agent_info
549
+
550
+ return adk_agents
551
+
552
+
553
+ def display_adk_caveat_if_needed(agents: dict[int, dict[str, Any]]) -> None:
554
+ """Display helpful note for agents that use inference.
555
+
556
+ Args:
557
+ agents: Dictionary of agent info from discover_adk_agents
558
+ """
559
+ console = Console()
560
+ inferred_agents = [
561
+ a for a in agents.values() if not a.get("has_explicit_config", True)
562
+ ]
563
+ if inferred_agents:
564
+ console.print(
565
+ "\n[blue]ℹ️ Note: Agents marked with * are templated using starter pack heuristics for ADK samples.[/]"
566
+ )
567
+ console.print(
568
+ "[dim] The starter pack attempts to create a working codebase, but you'll need to follow the generated README for complete setup.[/]"
569
+ )
570
+
571
+
572
+ def parse_agent_starter_pack_version_from_lock(
573
+ uv_lock_path: pathlib.Path,
574
+ ) -> str | None:
575
+ """Parse agent-starter-pack version from uv.lock file.
576
+
577
+ Args:
578
+ uv_lock_path: Path to uv.lock file
579
+
580
+ Returns:
581
+ Version string if found, None otherwise
582
+ """
583
+ if not uv_lock_path.exists():
584
+ return None
585
+
586
+ try:
587
+ with open(uv_lock_path, "rb") as f:
588
+ lock_data = tomllib.load(f)
589
+
590
+ # Look for agent-starter-pack in the packages section
591
+ packages = lock_data.get("package", [])
592
+ for package in packages:
593
+ if package.get("name") == "agent-starter-pack":
594
+ version = package.get("version")
595
+ if version:
596
+ logging.debug(
597
+ f"Found agent-starter-pack version {version} in uv.lock"
598
+ )
599
+ return version
600
+
601
+ except Exception as e:
602
+ logging.warning(f"Error parsing uv.lock file {uv_lock_path}: {e}")
603
+
604
+ return None
605
+
606
+
607
+ def render_and_merge_makefiles(
608
+ base_template_path: pathlib.Path,
609
+ final_destination: pathlib.Path,
610
+ cookiecutter_config: dict,
611
+ remote_template_path: pathlib.Path | None = None,
612
+ ) -> None:
613
+ """
614
+ Renders the base and remote Makefiles separately, then merges them.
615
+
616
+ If remote_template_path is not provided, only the base Makefile is rendered.
617
+ """
618
+
619
+ env = Environment()
620
+
621
+ # Render the base Makefile
622
+ base_makefile_path = base_template_path / "Makefile"
623
+ if base_makefile_path.exists():
624
+ with open(base_makefile_path, encoding="utf-8") as f:
625
+ base_template = env.from_string(f.read())
626
+ rendered_base_makefile = base_template.render(cookiecutter=cookiecutter_config)
627
+ else:
628
+ rendered_base_makefile = ""
629
+
630
+ # Render the remote Makefile if a path is provided
631
+ rendered_remote_makefile = ""
632
+ if remote_template_path:
633
+ remote_makefile_path = remote_template_path / "Makefile"
634
+ if remote_makefile_path.exists():
635
+ with open(remote_makefile_path, encoding="utf-8") as f:
636
+ remote_template = env.from_string(f.read())
637
+ rendered_remote_makefile = remote_template.render(
638
+ cookiecutter=cookiecutter_config
639
+ )
640
+
641
+ # Merge the rendered Makefiles
642
+ if rendered_base_makefile and rendered_remote_makefile:
643
+ # A simple merge: remote content first, then append missing commands from base
644
+ base_commands = set(
645
+ re.findall(r"^([a-zA-Z0-9_-]+):", rendered_base_makefile, re.MULTILINE)
646
+ )
647
+ remote_commands = set(
648
+ re.findall(r"^([a-zA-Z0-9_-]+):", rendered_remote_makefile, re.MULTILINE)
649
+ )
650
+ missing_commands = base_commands - remote_commands
651
+
652
+ if missing_commands:
653
+ commands_to_append = ["\n\n# --- Commands from Agent Starter Pack ---\n\n"]
654
+ for command in sorted(missing_commands):
655
+ command_block_match = re.search(
656
+ rf"^{command}:.*?(?=\n\n(?:^#.*\n)*?^[a-zA-Z0-9_-]+:|" + r"\Z)",
657
+ rendered_base_makefile,
658
+ re.MULTILINE | re.DOTALL,
659
+ )
660
+ if command_block_match:
661
+ commands_to_append.append(command_block_match.group(0))
662
+ commands_to_append.append("\n\n")
663
+
664
+ final_makefile_content = rendered_remote_makefile + "".join(
665
+ commands_to_append
666
+ )
667
+ else:
668
+ final_makefile_content = rendered_remote_makefile
669
+ elif rendered_remote_makefile:
670
+ final_makefile_content = rendered_remote_makefile
671
+ else:
672
+ final_makefile_content = rendered_base_makefile
673
+
674
+ # Write the final merged Makefile
675
+ with open(final_destination / "Makefile", "w", encoding="utf-8") as f:
676
+ f.write(final_makefile_content)
677
+ logging.debug("Rendered and merged Makefile written to final destination.")