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,150 @@
1
+ /**
2
+ * Copyright 2025 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ .transcription-preview {
18
+ width: 0;
19
+ height: 100%;
20
+ background: var(--Neutral-00);
21
+ border-left: 1px solid var(--Neutral-20);
22
+ display: flex;
23
+ flex-direction: column;
24
+ gap: 0;
25
+ overflow: hidden;
26
+ transition: width 0.2s ease-in-out;
27
+ flex-shrink: 0;
28
+
29
+ &.open {
30
+ width: 300px;
31
+ }
32
+
33
+ .transcription-section {
34
+ flex: 1;
35
+ display: flex;
36
+ flex-direction: column;
37
+ overflow: hidden;
38
+ opacity: 0;
39
+ transition: opacity 0.2s ease-in-out 0.1s;
40
+
41
+ &:first-child {
42
+ border-bottom: 1px solid var(--Neutral-20);
43
+ }
44
+
45
+ .transcription-header {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: 8px;
49
+ padding: 12px 20px;
50
+ background: var(--Neutral-05);
51
+ border-bottom: 1px solid var(--Neutral-20);
52
+ flex-shrink: 0;
53
+
54
+ .material-symbols-outlined {
55
+ font-size: 20px;
56
+ color: var(--Neutral-70);
57
+ }
58
+
59
+ h3 {
60
+ margin: 0;
61
+ font-size: 12px;
62
+ font-weight: 600;
63
+ color: var(--Neutral-90);
64
+ text-transform: uppercase;
65
+ letter-spacing: 0.5px;
66
+ }
67
+ }
68
+
69
+ .transcription-content {
70
+ flex: 1;
71
+ padding: 12px 16px;
72
+ overflow-y: auto;
73
+ overflow-x: hidden;
74
+ word-wrap: break-word;
75
+
76
+ p {
77
+ margin: 0 0 12px 0;
78
+ color: var(--Neutral-90);
79
+ font-size: 13px;
80
+ line-height: 1.5;
81
+ white-space: pre-wrap;
82
+ word-break: break-word;
83
+ font-family: var(--font-family);
84
+
85
+ &.placeholder {
86
+ color: var(--Neutral-50);
87
+ font-style: italic;
88
+ }
89
+
90
+ &.previous {
91
+ color: var(--Neutral-60);
92
+ opacity: 0.7;
93
+ }
94
+
95
+ &.current {
96
+ color: var(--Neutral-90);
97
+ font-weight: 500;
98
+ }
99
+
100
+ &:last-child {
101
+ margin-bottom: 0;
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ &.open .transcription-section {
108
+ opacity: 1;
109
+ }
110
+
111
+ .input-section {
112
+ .transcription-header {
113
+ .material-symbols-outlined {
114
+ color: var(--Green-500);
115
+ }
116
+
117
+ h3 {
118
+ color: var(--Green-500);
119
+ }
120
+ }
121
+
122
+ .transcription-content {
123
+ background: linear-gradient(
124
+ to bottom,
125
+ rgba(0, 200, 100, 0.02),
126
+ transparent
127
+ );
128
+ }
129
+ }
130
+
131
+ .output-section {
132
+ .transcription-header {
133
+ .material-symbols-outlined {
134
+ color: var(--Blue-500);
135
+ }
136
+
137
+ h3 {
138
+ color: var(--Blue-500);
139
+ }
140
+ }
141
+
142
+ .transcription-content {
143
+ background: linear-gradient(
144
+ to bottom,
145
+ rgba(0, 100, 255, 0.02),
146
+ transparent
147
+ );
148
+ }
149
+ }
150
+ }
@@ -76,6 +76,10 @@ export function useLiveAPI({
76
76
  setConnected(false);
77
77
  };
78
78
 
79
+ const onSetupComplete = () => {
80
+ setConnected(true);
81
+ };
82
+
79
83
  const stopAudioStreamer = () => audioStreamerRef.current?.stop();
80
84
 
81
85
  const onAudio = (data: ArrayBuffer) =>
@@ -83,12 +87,14 @@ export function useLiveAPI({
83
87
 
84
88
  client
85
89
  .on("close", onClose)
90
+ .on("setupcomplete", onSetupComplete)
86
91
  .on("interrupted", stopAudioStreamer)
87
92
  .on("audio", onAudio);
88
93
 
89
94
  return () => {
90
95
  client
91
96
  .off("close", onClose)
97
+ .off("setupcomplete", onSetupComplete)
92
98
  .off("interrupted", stopAudioStreamer)
93
99
  .off("audio", onAudio);
94
100
  };
@@ -97,8 +103,8 @@ export function useLiveAPI({
97
103
  const connect = useCallback(async () => {
98
104
  client.disconnect();
99
105
  await client.connect();
100
- setConnected(true);
101
- }, [client, setConnected]);
106
+ // Don't set connected here - wait for setupcomplete event
107
+ }, [client]);
102
108
 
103
109
  const disconnect = useCallback(async () => {
104
110
  client.disconnect();
@@ -94,7 +94,8 @@ export type LiveIncomingMessage =
94
94
  | ToolCallMessage
95
95
  | ToolCallCancellationMessage
96
96
  | SetupCompleteMessage
97
- | ServerContentMessage;
97
+ | ServerContentMessage
98
+ | AdkEvent;
98
99
 
99
100
  export type SetupCompleteMessage = { setupComplete: {} };
100
101
 
@@ -148,7 +149,7 @@ export type StreamingLog = {
148
149
 
149
150
  // Type-Guards
150
151
 
151
- const prop = (a: any, prop: string, kind: string = "object") =>
152
+ const prop = (a: any, prop: string) =>
152
153
  typeof a === "object" && typeof a[prop] === "object";
153
154
 
154
155
  // outgoing messages
@@ -240,3 +241,40 @@ export const isToolCallCancellation = (
240
241
  a: unknown,
241
242
  ): a is ToolCallCancellationMessage["toolCallCancellation"] =>
242
243
  typeof a === "object" && Array.isArray((a as any).ids);
244
+
245
+ // ADK Event types
246
+ export interface AdkEvent {
247
+ user_id: string;
248
+ session_id: string;
249
+ author: string;
250
+ actions: {
251
+ state_delta: any;
252
+ artifact_delta: any;
253
+ requested_auth_configs: any;
254
+ requested_tool_confirmations: any;
255
+ };
256
+ id: string;
257
+ timestamp: number;
258
+ // Optional ADK fields
259
+ input_transcription?: { text: string };
260
+ output_transcription?: { text: string };
261
+ content?: any;
262
+ interrupted?: boolean;
263
+ turn_complete?: boolean;
264
+ partial?: boolean;
265
+ }
266
+
267
+ // ADK Event type guards
268
+ export const isAdkEvent = (a: unknown): a is AdkEvent =>
269
+ typeof a === "object" &&
270
+ a !== null &&
271
+ typeof (a as any).user_id === "string" &&
272
+ typeof (a as any).session_id === "string" &&
273
+ typeof (a as any).author === "string" &&
274
+ typeof (a as any).actions === "object";
275
+
276
+ export const isInputTranscription = (a: unknown): a is AdkEvent =>
277
+ isAdkEvent(a) && (a as AdkEvent).input_transcription !== undefined;
278
+
279
+ export const isOutputTranscription = (a: unknown): a is AdkEvent =>
280
+ isAdkEvent(a) && (a as AdkEvent).output_transcription !== undefined;
@@ -50,7 +50,7 @@ export class AudioRecorder extends EventEmitter {
50
50
  throw new Error("Could not request user media");
51
51
  }
52
52
 
53
- this.starting = new Promise(async (resolve, reject) => {
53
+ this.starting = new Promise(async (resolve) => {
54
54
  this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
55
55
  this.audioContext = await audioContext({ sampleRate: this.sampleRate });
56
56
  this.source = this.audioContext.createMediaStreamSource(this.stream);
@@ -154,7 +154,7 @@ export class AudioStreamer {
154
154
  const worklets = registeredWorklets.get(this.context);
155
155
 
156
156
  if (worklets) {
157
- Object.entries(worklets).forEach(([workletName, graph]) => {
157
+ Object.entries(worklets).forEach(([, graph]) => {
158
158
  const { node, handlers } = graph;
159
159
  if (node) {
160
160
  source.connect(node);
@@ -18,7 +18,6 @@ import { Content, GenerativeContentBlob, Part } from "@google/generative-ai";
18
18
  import { EventEmitter } from "eventemitter3";
19
19
  import { difference } from "lodash";
20
20
  import {
21
- ClientContentMessage,
22
21
  isInterrupted,
23
22
  isModelTurn,
24
23
  isServerContenteMessage,
@@ -26,15 +25,18 @@ import {
26
25
  isToolCallCancellationMessage,
27
26
  isToolCallMessage,
28
27
  isTurnComplete,
28
+ isAdkEvent,
29
+ isInputTranscription,
30
+ isOutputTranscription,
29
31
  LiveIncomingMessage,
30
32
  ModelTurn,
31
- RealtimeInputMessage,
32
33
  ServerContent,
33
34
  StreamingLog,
34
35
  ToolCall,
35
36
  ToolCallCancellation,
36
37
  ToolResponseMessage,
37
38
  type LiveConfig,
39
+ type AdkEvent,
38
40
  } from "../multimodal-live-types";
39
41
  import { blobToJSON, base64ToArrayBuffer } from "./utils";
40
42
 
@@ -53,6 +55,10 @@ interface MultimodalLiveClientEventTypes {
53
55
  turncomplete: () => void;
54
56
  toolcall: (toolCall: ToolCall) => void;
55
57
  toolcallcancellation: (toolcallCancellation: ToolCallCancellation) => void;
58
+ // ADK events
59
+ inputtranscription: (text: string) => void;
60
+ outputtranscription: (text: string) => void;
61
+ adkevent: (event: AdkEvent) => void;
56
62
  }
57
63
 
58
64
  export type MultimodalLiveAPIClientConnection = {
@@ -72,15 +78,27 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
72
78
  public url: string = "";
73
79
  private runId: string;
74
80
  private userId?: string;
81
+ private firstContentSent: boolean = false;
82
+ private audioChunksSent: number = 0;
83
+ private lastAudioSendTime: number = 0;
84
+ private readonly INITIAL_SEND_INTERVAL_MS = 300; // Start slow: 300ms between chunks
85
+ private readonly NORMAL_SEND_INTERVAL_MS = 125; // Normal rate: 125ms (8 chunks/sec)
86
+ private readonly RAMPUP_CHUNKS = 10; // Number of chunks to send at reduced rate
87
+
75
88
  constructor({ url, userId, runId }: MultimodalLiveAPIClientConnection) {
76
89
  super();
77
- url = url || `ws://localhost:8000/ws`;
90
+ const defaultWsUrl = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`;
91
+ url = url || defaultWsUrl;
78
92
  this.url = new URL("ws", url).href;
79
93
  this.userId = userId;
80
94
  this.runId = runId || crypto.randomUUID(); // Ensure runId is always a string by providing default
81
95
  this.send = this.send.bind(this);
82
96
  }
83
97
 
98
+ get currentRunId(): string {
99
+ return this.runId;
100
+ }
101
+
84
102
  log(type: string, message: StreamingLog["message"]) {
85
103
  const log: StreamingLog = {
86
104
  date: new Date(),
@@ -98,15 +116,37 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
98
116
  this.runId = newRunId;
99
117
  }
100
118
 
119
+ // Reset connection state
120
+ this.firstContentSent = false;
121
+ this.audioChunksSent = 0;
122
+ this.lastAudioSendTime = 0;
123
+
101
124
  ws.addEventListener("message", async (evt: MessageEvent) => {
102
125
  if (evt.data instanceof Blob) {
103
126
  this.receive(evt.data);
104
127
  } else if (typeof evt.data === "string") {
105
128
  try {
106
129
  const jsonData = JSON.parse(evt.data);
107
- if (jsonData.status) {
130
+
131
+ // Handle different message types from backend
132
+ if (jsonData.setupComplete) {
133
+ this.emit("setupcomplete");
134
+ this.log("server.setupComplete", "Session ready");
135
+ } else if (jsonData.serverContent) {
136
+ // Handle serverContent messages
137
+ this.receive(new Blob([JSON.stringify(jsonData)], {type: 'application/json'}));
138
+ } else if (jsonData.toolCall) {
139
+ // Handle tool calls
140
+ this.receive(new Blob([JSON.stringify(jsonData)], {type: 'application/json'}));
141
+ } else if (jsonData.status) {
108
142
  this.log("server.status", jsonData.status);
109
- console.log("Status:", jsonData.status); // This will show in console
143
+ console.log("Status:", jsonData.status);
144
+ } else if (jsonData.error) {
145
+ this.log("server.error", jsonData.error);
146
+ console.error("Server error:", jsonData.error);
147
+ } else {
148
+ // Try to process as a regular message
149
+ this.receive(new Blob([JSON.stringify(jsonData)], {type: 'application/json'}));
110
150
  }
111
151
  } catch (error) {
112
152
  console.error("Error parsing message:", error);
@@ -129,11 +169,12 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
129
169
  this.emit("open");
130
170
 
131
171
  this.ws = ws;
132
- // Send initial setup message with runId
172
+ // Send initial setup message with user_id for backend
133
173
  const setupMessage = {
174
+ user_id: this.userId || "default_user",
134
175
  setup: {
135
176
  run_id: this.runId,
136
- user_id: this.userId,
177
+ user_id: this.userId || "default_user",
137
178
  },
138
179
  };
139
180
  this._sendDirect(setupMessage);
@@ -213,11 +254,18 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
213
254
  if (isModelTurn(serverContent)) {
214
255
  let parts: Part[] = serverContent.modelTurn.parts;
215
256
 
216
- // when its audio that is returned for modelTurn
257
+ // when its audio that is returned for modelTurn (check both camelCase and snake_case)
217
258
  const audioParts = parts.filter(
218
- (p) => p.inlineData && p.inlineData.mimeType.startsWith("audio/pcm"),
259
+ (p: any) => {
260
+ const inlineData = p.inlineData || p.inline_data;
261
+ const mimeType = inlineData?.mimeType || inlineData?.mime_type;
262
+ return inlineData && mimeType && mimeType.startsWith("audio/pcm");
263
+ }
219
264
  );
220
- const base64s = audioParts.map((p) => p.inlineData?.data);
265
+ const base64s = audioParts.map((p: any) => {
266
+ const inlineData = p.inlineData || p.inline_data;
267
+ return inlineData?.data;
268
+ });
221
269
 
222
270
  // strip the audio parts out of the modelTurn
223
271
  const otherParts = difference(parts, audioParts);
@@ -240,6 +288,98 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
240
288
  this.emit("content", content);
241
289
  this.log(`server.content`, response);
242
290
  }
291
+ } else if (isAdkEvent(response)) {
292
+ // Handle ADK events
293
+ this.emit("adkevent", response);
294
+
295
+ // Handle specific ADK event types
296
+ if (isInputTranscription(response)) {
297
+ this.emit("inputtranscription", response.input_transcription!.text);
298
+ }
299
+
300
+ if (isOutputTranscription(response)) {
301
+ this.emit("outputtranscription", response.output_transcription!.text);
302
+ }
303
+
304
+ // Handle ADK content (text responses from agent)
305
+ if (response.content && response.content.parts) {
306
+ const parts = response.content.parts;
307
+
308
+ // Extract function calls for tool call logging
309
+ const functionCallParts = parts.filter((p: any) => p.function_call);
310
+
311
+ // Log function calls as tool calls for the console
312
+ if (functionCallParts.length > 0) {
313
+ const functionCalls = functionCallParts.map((p: any) => ({
314
+ id: p.function_call.id,
315
+ name: p.function_call.name,
316
+ args: p.function_call.args || {}
317
+ }));
318
+
319
+ const toolCallMessage = {
320
+ toolCall: {
321
+ functionCalls: functionCalls
322
+ }
323
+ };
324
+
325
+ this.log("server.toolCall", toolCallMessage);
326
+ this.emit("toolcall", toolCallMessage.toolCall);
327
+ }
328
+
329
+ // Extract audio parts for playing (check both camelCase and snake_case)
330
+ const audioParts = parts.filter(
331
+ (p: any) => {
332
+ const inlineData = p.inlineData || p.inline_data;
333
+ const mimeType = inlineData?.mimeType || inlineData?.mime_type;
334
+ return inlineData && mimeType && mimeType.startsWith("audio/");
335
+ }
336
+ );
337
+
338
+ // Play audio if present
339
+ audioParts.forEach((audioPart: any) => {
340
+ const inlineData = audioPart.inlineData || audioPart.inline_data;
341
+ if (inlineData && inlineData.data) {
342
+ const audioData = base64ToArrayBuffer(inlineData.data);
343
+
344
+ // Only emit audio if we have a valid buffer with data
345
+ if (audioData.byteLength > 0) {
346
+ this.emit("audio", audioData);
347
+ this.log(`server.audio`, `buffer (${audioData.byteLength}) - ${inlineData.mime_type || inlineData.mimeType}`);
348
+ } else {
349
+ this.log(`server.audio`, `invalid audio buffer - skipped`);
350
+ }
351
+ }
352
+ });
353
+
354
+ // Send content for other parts (text, etc.) - exclude function calls and audio
355
+ const nonAudioNonFunctionParts = parts.filter(
356
+ (p: any) => {
357
+ const inlineData = p.inlineData || p.inline_data;
358
+ const mimeType = inlineData?.mimeType || inlineData?.mime_type;
359
+ const hasAudio = inlineData && mimeType && mimeType.startsWith("audio/");
360
+ const hasFunctionCall = p.function_call;
361
+ return !hasAudio && !hasFunctionCall;
362
+ }
363
+ );
364
+
365
+ if (nonAudioNonFunctionParts.length > 0) {
366
+ const content: ModelTurn = { modelTurn: { parts: nonAudioNonFunctionParts } };
367
+ this.emit("content", content);
368
+ this.log("server.content", `content with ${nonAudioNonFunctionParts.length} non-audio, non-function parts`);
369
+ }
370
+ }
371
+
372
+ // Handle turn complete
373
+ if (response.turn_complete) {
374
+ this.emit("turncomplete");
375
+ this.log("server.turncomplete", "ADK turn complete");
376
+ }
377
+
378
+ // Handle interruption
379
+ if (response.interrupted) {
380
+ this.emit("interrupted");
381
+ this.log("server.interrupted", "ADK interrupted");
382
+ }
243
383
  } else {
244
384
  console.log("received unmatched message", response);
245
385
  this.log("received unmatched message", response);
@@ -250,6 +390,12 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
250
390
  * send realtimeInput, this is base64 chunks of "audio/pcm" and/or "image/jpg"
251
391
  */
252
392
  sendRealtimeInput(chunks: GenerativeContentBlob[]) {
393
+ // Don't send if WebSocket is not open - this prevents flooding the queue
394
+ // during connection setup
395
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
396
+ return;
397
+ }
398
+
253
399
  let hasAudio = false;
254
400
  let hasVideo = false;
255
401
  for (let i = 0; i < chunks.length; i++) {
@@ -264,6 +410,25 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
264
410
  break;
265
411
  }
266
412
  }
413
+
414
+ // Throttle audio chunks during initial connection phase
415
+ if (hasAudio && !hasVideo) {
416
+ const now = Date.now();
417
+
418
+ // Calculate required interval based on how many chunks we've sent
419
+ const requiredInterval = this.audioChunksSent < this.RAMPUP_CHUNKS
420
+ ? this.INITIAL_SEND_INTERVAL_MS
421
+ : this.NORMAL_SEND_INTERVAL_MS;
422
+
423
+ // If not enough time has passed since last send, drop this chunk
424
+ if (this.lastAudioSendTime > 0 && (now - this.lastAudioSendTime) < requiredInterval) {
425
+ return;
426
+ }
427
+
428
+ this.lastAudioSendTime = now;
429
+ this.audioChunksSent++;
430
+ }
431
+
267
432
  const message =
268
433
  hasAudio && hasVideo
269
434
  ? "audio + video"
@@ -273,12 +438,26 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
273
438
  ? "video"
274
439
  : "unknown";
275
440
 
276
- const data: RealtimeInputMessage = {
277
- realtimeInput: {
278
- mediaChunks: chunks,
279
- },
280
- };
281
- this._sendDirect(data);
441
+ // Convert to LiveRequest format for backend
442
+ for (const chunk of chunks) {
443
+ let data: any = {
444
+ blob: {
445
+ mimeType: chunk.mimeType,
446
+ data: chunk.data,
447
+ },
448
+ };
449
+
450
+ // For remote mode: wrap first content in {user_id, live_request} format
451
+ if (!this.firstContentSent) {
452
+ data = {
453
+ user_id: this.userId || "default_user",
454
+ live_request: data,
455
+ };
456
+ this.firstContentSent = true;
457
+ }
458
+
459
+ this._sendDirect(data);
460
+ }
282
461
  this.log(`client.realtimeInput`, message);
283
462
  }
284
463
 
@@ -297,22 +476,29 @@ export class MultimodalLiveClient extends EventEmitter<MultimodalLiveClientEvent
297
476
  /**
298
477
  * send normal content parts such as { text }
299
478
  */
300
- send(parts: Part | Part[], turnComplete: boolean = true) {
479
+ send(parts: Part | Part[], _turnComplete: boolean = true) {
301
480
  parts = Array.isArray(parts) ? parts : [parts];
302
481
  const content: Content = {
303
482
  role: "user",
304
483
  parts,
305
484
  };
306
485
 
307
- const clientContentRequest: ClientContentMessage = {
308
- clientContent: {
309
- turns: [content],
310
- turnComplete,
311
- },
486
+ // Convert to LiveRequest format for backend
487
+ let data: any = {
488
+ content: content,
312
489
  };
313
490
 
314
- this._sendDirect(clientContentRequest);
315
- this.log(`client.send`, clientContentRequest);
491
+ // For remote mode: wrap first content in {user_id, live_request} format
492
+ if (!this.firstContentSent) {
493
+ data = {
494
+ user_id: this.userId || "default_user",
495
+ live_request: data,
496
+ };
497
+ this.firstContentSent = true;
498
+ }
499
+
500
+ this._sendDirect(data);
501
+ this.log(`client.send`, `content with ${parts.length} parts`);
316
502
  }
317
503
 
318
504
  /**
@@ -76,11 +76,33 @@ export const blobToJSON = (blob: Blob) =>
76
76
  reader.readAsText(blob);
77
77
  });
78
78
 
79
+ function cleanBase64String(base64: string): string {
80
+ // Convert URL-safe base64 to standard base64
81
+ let cleaned = base64
82
+ .replace(/-/g, '+') // Replace - with +
83
+ .replace(/_/g, '/') // Replace _ with /
84
+ .replace(/[^A-Za-z0-9+/=]/g, ''); // Remove any other invalid characters
85
+
86
+ // Ensure proper padding (base64 strings must be multiples of 4)
87
+ return cleaned + '='.repeat((4 - cleaned.length % 4) % 4);
88
+ }
89
+
79
90
  export function base64ToArrayBuffer(base64: string) {
80
- var binaryString = atob(base64);
81
- var bytes = new Uint8Array(binaryString.length);
82
- for (let i = 0; i < binaryString.length; i++) {
83
- bytes[i] = binaryString.charCodeAt(i);
91
+ const cleanedBase64 = cleanBase64String(base64);
92
+
93
+ try {
94
+ var binaryString = atob(cleanedBase64);
95
+ var bytes = new Uint8Array(binaryString.length);
96
+ for (let i = 0; i < binaryString.length; i++) {
97
+ bytes[i] = binaryString.charCodeAt(i);
98
+ }
99
+ return bytes.buffer;
100
+ } catch (error) {
101
+ console.error('Failed to decode base64 audio data:', error);
102
+ console.error('Original base64 length:', base64.length);
103
+ console.error('Cleaned base64 length:', cleanedBase64.length);
104
+ console.error('First 100 chars:', base64.substring(0, 100));
105
+ // Return empty buffer on error
106
+ return new ArrayBuffer(0);
84
107
  }
85
- return bytes.buffer;
86
108
  }