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
@@ -3,7 +3,6 @@
3
3
  "version": "0.1.0",
4
4
  "dependencies": {
5
5
  "classnames": "^2.5.1",
6
- "dotenv-flow": "^4.1.0",
7
6
  "eventemitter3": "^5.0.1",
8
7
  "lodash": "^4.17.21",
9
8
  "react": "^18.3.1",
@@ -12,9 +11,6 @@
12
11
  "react-scripts": "5.0.1",
13
12
  "react-select": "^5.8.3",
14
13
  "sass": "^1.80.6",
15
- "vega": "^5.33.0",
16
- "vega-embed": "^6.29.0",
17
- "vega-lite": "^5.22.0",
18
14
  "web-vitals": "^2.1.4",
19
15
  "zustand": "^5.0.1"
20
16
  },
@@ -41,13 +37,9 @@
41
37
  "@google/generative-ai": "^0.21.0",
42
38
  "@testing-library/jest-dom": "^5.17.0",
43
39
  "@testing-library/react": "^13.4.0",
44
- "@testing-library/user-event": "^13.5.0",
45
- "@types/jest": "^27.5.2",
46
- "@types/node": "^16.18.119",
40
+ "@types/lodash": "^4.17.13",
47
41
  "@types/react": "^18.3.12",
48
42
  "@types/react-dom": "^18.3.1",
49
- "@types/lodash": "^4.17.13",
50
- "ts-node": "^10.9.2",
51
43
  "typescript": "^5.6.3"
52
44
  },
53
45
  "overrides": {
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Copyright 2024 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
+ import { useRef, useState } from "react";
18
+ import "./App.scss";
19
+ import { LiveAPIProvider } from "./contexts/LiveAPIContext";
20
+ import SidePanel from "./components/side-panel/SidePanel";
21
+ import cn from "classnames";
22
+
23
+ // In development mode (frontend on :8501), connect to backend on :8000
24
+ const isDevelopment = window.location.port === '8501';
25
+ const defaultHost = isDevelopment ? `${window.location.hostname}:8000` : window.location.host;
26
+ const defaultUri = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${defaultHost}/`;
27
+
28
+ function App() {
29
+ const videoRef = useRef<HTMLVideoElement>(null);
30
+ const [videoStream, setVideoStream] = useState<MediaStream | null>(null);
31
+ const [serverUrl, setServerUrl] = useState<string>(defaultUri);
32
+ const [userId, setUserId] = useState<string>("user1");
33
+
34
+ return (
35
+ <div className="App">
36
+ <LiveAPIProvider url={serverUrl} userId={userId}>
37
+ <div className="streaming-console">
38
+ <SidePanel
39
+ videoRef={videoRef}
40
+ supportsVideo={true}
41
+ onVideoStreamChange={setVideoStream}
42
+ serverUrl={serverUrl}
43
+ userId={userId}
44
+ onServerUrlChange={setServerUrl}
45
+ onUserIdChange={setUserId}
46
+ />
47
+ <main>
48
+ <div className="main-app-area">
49
+ <video
50
+ className={cn("stream", {
51
+ hidden: !videoRef.current || !videoStream,
52
+ })}
53
+ ref={videoRef}
54
+ autoPlay
55
+ playsInline
56
+ />
57
+ </div>
58
+ </main>
59
+ </div>
60
+ </LiveAPIProvider>
61
+ </div>
62
+ );
63
+ }
64
+
65
+ export default App;
@@ -115,10 +115,15 @@ const ToolCallLog = ({ message }: Message) => {
115
115
  const { toolCall } = message as ToolCallMessage;
116
116
  return (
117
117
  <div className={cn("rich-log tool-call")}>
118
- {toolCall.functionCalls.map((fc, i) => (
118
+ <h4 className="role-tool">Tool Call</h4>
119
+ {toolCall.functionCalls.map((fc) => (
119
120
  <div key={fc.id} className="part part-functioncall">
120
- <h5>Function call: {fc.name}</h5>
121
- <pre>{JSON.stringify(fc, null, " ")}</pre>
121
+ <h5>Function: {fc.name}</h5>
122
+ <div className="function-details">
123
+ <div><strong>ID:</strong> {fc.id}</div>
124
+ <div><strong>Args:</strong></div>
125
+ <pre>{JSON.stringify(fc.args, null, 2)}</pre>
126
+ </div>
122
127
  </div>
123
128
  ))}
124
129
  </div>
@@ -35,6 +35,10 @@
35
35
  color: var(--Blue-500);
36
36
  }
37
37
 
38
+ .tool-call h4 {
39
+ color: var(--Orange-500, #ff9800);
40
+ }
41
+
38
42
  .rich-log {
39
43
  display: flex;
40
44
  justify-content: center;
@@ -66,6 +70,28 @@
66
70
  color: var(--Neutral-90);
67
71
  border-radius: 8px;
68
72
  }
73
+
74
+ .part-functioncall {
75
+ background: rgba(255, 152, 0, 0.1);
76
+ border-left: 3px solid var(--Orange-500, #ff9800);
77
+
78
+ .function-details {
79
+ margin-top: 8px;
80
+ font-size: 13px;
81
+
82
+ strong {
83
+ color: var(--Orange-500, #ff9800);
84
+ }
85
+
86
+ pre {
87
+ background: var(--Neutral-10);
88
+ padding: 8px;
89
+ border-radius: 4px;
90
+ margin: 4px 0;
91
+ font-size: 12px;
92
+ }
93
+ }
94
+ }
69
95
  }
70
96
 
71
97
  .plain-log {
@@ -0,0 +1,516 @@
1
+ /**
2
+ * Copyright 2024 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
+ import cn from "classnames";
18
+ import { memo, ReactNode, RefObject, useEffect, useRef, useState } from "react";
19
+ import { RiSidebarFoldLine, RiSidebarUnfoldLine } from "react-icons/ri";
20
+ import Select from "react-select";
21
+ import { useLiveAPIContext } from "../../contexts/LiveAPIContext";
22
+ import { useLoggerStore } from "../../utils/store-logger";
23
+ import { UseMediaStreamResult } from "../../hooks/use-media-stream-mux";
24
+ import { useScreenCapture } from "../../hooks/use-screen-capture";
25
+ import { useWebcam } from "../../hooks/use-webcam";
26
+ import { AudioRecorder } from "../../utils/audio-recorder";
27
+ import AudioPulse from "../audio-pulse/AudioPulse";
28
+ import Logger, { LoggerFilterType } from "../logger/Logger";
29
+ import TranscriptionPreview from "../transcription-preview/TranscriptionPreview";
30
+ import "./side-panel.scss";
31
+
32
+ const filterOptions = [
33
+ { value: "conversations", label: "Conversations" },
34
+ { value: "tools", label: "Tool Use" },
35
+ { value: "none", label: "All" },
36
+ ];
37
+
38
+ export type SidePanelProps = {
39
+ videoRef?: RefObject<HTMLVideoElement>;
40
+ children?: ReactNode;
41
+ supportsVideo?: boolean;
42
+ onVideoStreamChange?: (stream: MediaStream | null) => void;
43
+ serverUrl?: string;
44
+ userId?: string;
45
+ onServerUrlChange?: (url: string) => void;
46
+ onUserIdChange?: (userId: string) => void;
47
+ };
48
+
49
+ type MediaStreamButtonProps = {
50
+ isStreaming: boolean;
51
+ onIcon: string;
52
+ offIcon: string;
53
+ start: () => Promise<any>;
54
+ stop: () => any;
55
+ };
56
+
57
+ const MediaStreamButton = memo(
58
+ ({ isStreaming, onIcon, offIcon, start, stop }: MediaStreamButtonProps) =>
59
+ isStreaming ? (
60
+ <button className={cn("action-button", { active: isStreaming })} onClick={stop}>
61
+ <span className="material-symbols-outlined">{onIcon}</span>
62
+ </button>
63
+ ) : (
64
+ <button className="action-button" onClick={start}>
65
+ <span className="material-symbols-outlined">{offIcon}</span>
66
+ </button>
67
+ ),
68
+ );
69
+
70
+ function SidePanel({
71
+ videoRef,
72
+ children,
73
+ onVideoStreamChange = () => {},
74
+ supportsVideo = true,
75
+ serverUrl = "ws://localhost:8000/",
76
+ userId = "user1",
77
+ onServerUrlChange = () => {},
78
+ onUserIdChange = () => {},
79
+ }: SidePanelProps) {
80
+ const { connected, client, connect, disconnect, volume } = useLiveAPIContext();
81
+ const [open, setOpen] = useState(true);
82
+ const [connectionExpanded, setConnectionExpanded] = useState(false);
83
+
84
+ // Auto-collapse connection settings when panel is closed
85
+ useEffect(() => {
86
+ if (!open && connectionExpanded) {
87
+ setConnectionExpanded(false);
88
+ }
89
+ }, [open, connectionExpanded]);
90
+ const loggerRef = useRef<HTMLDivElement>(null);
91
+ const loggerLastHeightRef = useRef<number>(-1);
92
+ const { log, logs } = useLoggerStore();
93
+
94
+ const [textInput, setTextInput] = useState("");
95
+ const [selectedOption, setSelectedOption] = useState<{
96
+ value: string;
97
+ label: string;
98
+ } | null>(null);
99
+ const inputRef = useRef<HTMLTextAreaElement>(null);
100
+
101
+ // Control states
102
+ const videoStreams = [useWebcam(), useScreenCapture()];
103
+ const [activeVideoStream, setActiveVideoStream] = useState<MediaStream | null>(null);
104
+ const [webcam, screenCapture] = videoStreams;
105
+ const [inVolume, setInVolume] = useState(0);
106
+ const [audioRecorder] = useState(() => new AudioRecorder());
107
+ const [muted, setMuted] = useState(false);
108
+ const renderCanvasRef = useRef<HTMLCanvasElement>(null);
109
+ const connectButtonRef = useRef<HTMLButtonElement>(null);
110
+
111
+ // Feedback state (local to SidePanel)
112
+ const [feedbackScore, setFeedbackScore] = useState<number>(10);
113
+ const [feedbackText, setFeedbackText] = useState<string>("");
114
+ const [sendFeedback, setShowFeedback] = useState(false);
115
+
116
+ useEffect(() => {
117
+ if (!connected && connectButtonRef.current) {
118
+ connectButtonRef.current.focus();
119
+ }
120
+ }, [connected]);
121
+
122
+ useEffect(() => {
123
+ document.documentElement.style.setProperty(
124
+ "--volume",
125
+ `${Math.max(5, Math.min(inVolume * 200, 8))}px`,
126
+ );
127
+ }, [inVolume]);
128
+
129
+ useEffect(() => {
130
+ const onData = (base64: string) => {
131
+ client.sendRealtimeInput([
132
+ {
133
+ mimeType: "audio/pcm;rate=16000",
134
+ data: base64,
135
+ },
136
+ ]);
137
+ };
138
+ if (connected && !muted && audioRecorder) {
139
+ audioRecorder.on("data", onData).on("volume", setInVolume).start();
140
+ } else {
141
+ audioRecorder.stop();
142
+ }
143
+ return () => {
144
+ audioRecorder.off("data", onData).off("volume", setInVolume);
145
+ };
146
+ }, [connected, client, muted, audioRecorder]);
147
+
148
+ useEffect(() => {
149
+ if (videoRef && videoRef.current) {
150
+ videoRef.current.srcObject = activeVideoStream;
151
+ }
152
+
153
+ let timeoutId = -1;
154
+
155
+ function sendVideoFrame() {
156
+ const video = videoRef && videoRef.current;
157
+ const canvas = renderCanvasRef.current;
158
+
159
+ if (!video || !canvas) {
160
+ return;
161
+ }
162
+
163
+ const ctx = canvas.getContext("2d")!;
164
+ canvas.width = video.videoWidth * 0.25;
165
+ canvas.height = video.videoHeight * 0.25;
166
+ if (canvas.width + canvas.height > 0) {
167
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
168
+ const base64 = canvas.toDataURL("image/jpeg", 1.0);
169
+ const data = base64.slice(base64.indexOf(",") + 1, Infinity);
170
+ client.sendRealtimeInput([{ mimeType: "image/jpeg", data }]);
171
+ }
172
+ if (connected) {
173
+ timeoutId = window.setTimeout(sendVideoFrame, 1000 / 0.5);
174
+ }
175
+ }
176
+ if (connected && activeVideoStream !== null) {
177
+ requestAnimationFrame(sendVideoFrame);
178
+ }
179
+ return () => {
180
+ clearTimeout(timeoutId);
181
+ };
182
+ }, [connected, activeVideoStream, client, videoRef]);
183
+
184
+ //handler for swapping from one video-stream to the next
185
+ const changeStreams = (next?: UseMediaStreamResult) => async () => {
186
+ if (next) {
187
+ const mediaStream = await next.start();
188
+ setActiveVideoStream(mediaStream);
189
+ onVideoStreamChange(mediaStream);
190
+ } else {
191
+ setActiveVideoStream(null);
192
+ onVideoStreamChange(null);
193
+ }
194
+
195
+ videoStreams.filter((msr) => msr !== next).forEach((msr) => msr.stop());
196
+ };
197
+
198
+ const submitFeedback = async () => {
199
+ const feedbackUrl = new URL('feedback', serverUrl.replace('ws', 'http')).href;
200
+
201
+ try {
202
+ const response = await fetch(feedbackUrl, {
203
+ method: 'POST',
204
+ headers: {
205
+ 'Content-Type': 'application/json'
206
+ },
207
+ body: JSON.stringify({
208
+ score: feedbackScore,
209
+ text: feedbackText,
210
+ run_id: client.currentRunId,
211
+ user_id: userId,
212
+ log_type: "feedback"
213
+ })
214
+ });
215
+ if (!response.ok) {
216
+ throw new Error(`Failed to submit feedback: Server returned status ${response.status} ${response.statusText}`);
217
+ }
218
+
219
+ // Clear feedback after successful submission
220
+ setFeedbackScore(10);
221
+ setFeedbackText("");
222
+ setShowFeedback(false);
223
+ alert("Feedback submitted successfully!");
224
+ } catch (error) {
225
+ console.error('Error submitting feedback:', error);
226
+ alert(`Failed to submit feedback: ${error}`);
227
+ }
228
+ };
229
+
230
+ //scroll the log to the bottom when new logs come in
231
+ useEffect(() => {
232
+ if (loggerRef.current) {
233
+ const el = loggerRef.current;
234
+ const scrollHeight = el.scrollHeight;
235
+ if (scrollHeight !== loggerLastHeightRef.current) {
236
+ el.scrollTop = scrollHeight;
237
+ loggerLastHeightRef.current = scrollHeight;
238
+ }
239
+ }
240
+ }, [logs]);
241
+
242
+ // listen for log events and store them
243
+ useEffect(() => {
244
+ client.on("log", log);
245
+ return () => {
246
+ client.off("log", log);
247
+ };
248
+ }, [client, log]);
249
+
250
+ const handleSubmit = () => {
251
+ client.send([{ text: textInput }]);
252
+
253
+ setTextInput("");
254
+ if (inputRef.current) {
255
+ inputRef.current.innerText = "";
256
+ }
257
+ };
258
+
259
+ return (
260
+ <div className={`console-container ${open ? "open" : ""}`}>
261
+ <header className="console-header">
262
+ <h2>Console</h2>
263
+ {open ? (
264
+ <button className="toggle-button" onClick={() => setOpen(!open)}>
265
+ <RiSidebarFoldLine color="#b4b8bb" />
266
+ </button>
267
+ ) : (
268
+ <button className="toggle-button" onClick={() => setOpen(!open)}>
269
+ <RiSidebarUnfoldLine color="#b4b8bb" />
270
+ </button>
271
+ )}
272
+ </header>
273
+ <div className="console-content">
274
+ <div className="side-panel">
275
+ <canvas style={{ display: "none" }} ref={renderCanvasRef} />
276
+
277
+ {/* Connection Settings Section */}
278
+ <section className="connection-settings">
279
+ <button
280
+ className="connection-expander"
281
+ onClick={() => setConnectionExpanded(!connectionExpanded)}
282
+ >
283
+ Connection Settings
284
+ <span>{connectionExpanded ? '▼' : '▶'}</span>
285
+ </button>
286
+ {connectionExpanded && open && (
287
+ <div className="connection-content">
288
+ <div className="setting-group">
289
+ <label htmlFor="server-url">Server URL</label>
290
+ <input
291
+ id="server-url"
292
+ type="text"
293
+ value={serverUrl}
294
+ onChange={(e) => onServerUrlChange(e.target.value)}
295
+ placeholder="ws://localhost:8000/"
296
+ className="setting-input"
297
+ />
298
+ </div>
299
+ <div className="setting-group">
300
+ <label htmlFor="user-id">User ID</label>
301
+ <input
302
+ id="user-id"
303
+ type="text"
304
+ value={userId}
305
+ onChange={(e) => onUserIdChange(e.target.value)}
306
+ placeholder="user123"
307
+ className="setting-input"
308
+ />
309
+ </div>
310
+ <button
311
+ onClick={() => setShowFeedback(!sendFeedback)}
312
+ className="feedback-button"
313
+ >
314
+ {sendFeedback ? 'Hide Feedback' : 'Send Feedback'}
315
+ </button>
316
+ </div>
317
+ )}
318
+ </section>
319
+
320
+ {/* Control Tray - All buttons moved here */}
321
+ <section className="control-tray">
322
+ <nav className={cn("actions-nav", { disabled: !connected })}>
323
+ <button
324
+ ref={connectButtonRef}
325
+ className={cn("action-button connect-toggle", { connected })}
326
+ onClick={connected ? disconnect : connect}
327
+ >
328
+ <span className="material-symbols-outlined filled">
329
+ {connected ? "pause" : "play_arrow"}
330
+ </span>
331
+ </button>
332
+
333
+ <button
334
+ className={cn("action-button mic-button", { active: !muted })}
335
+ onClick={() => setMuted(!muted)}
336
+ >
337
+ {!muted ? (
338
+ <span className="material-symbols-outlined filled">mic</span>
339
+ ) : (
340
+ <span className="material-symbols-outlined filled">mic_off</span>
341
+ )}
342
+ </button>
343
+
344
+ <div className="action-button no-action outlined">
345
+ <AudioPulse volume={volume} active={connected} hover={false} />
346
+ </div>
347
+
348
+ {supportsVideo && (
349
+ <>
350
+ <MediaStreamButton
351
+ isStreaming={screenCapture.isStreaming}
352
+ start={changeStreams(screenCapture)}
353
+ stop={changeStreams()}
354
+ onIcon="cancel_presentation"
355
+ offIcon="present_to_all"
356
+ />
357
+ <MediaStreamButton
358
+ isStreaming={webcam.isStreaming}
359
+ start={changeStreams(webcam)}
360
+ stop={changeStreams()}
361
+ onIcon="videocam_off"
362
+ offIcon="videocam"
363
+ />
364
+ </>
365
+ )}
366
+ {children}
367
+ </nav>
368
+
369
+ <div className="connection-status">
370
+ <span className={cn("text-indicator", { connected })}>
371
+ {connected ? "Streaming" : "Disconnected"}
372
+ </span>
373
+ </div>
374
+ </section>
375
+
376
+ <section className="indicators">
377
+ <Select
378
+ className="react-select"
379
+ classNamePrefix="react-select"
380
+ styles={{
381
+ control: (baseStyles) => ({
382
+ ...baseStyles,
383
+ background: "var(--Neutral-15)",
384
+ color: "var(--Neutral-90)",
385
+ minHeight: "33px",
386
+ maxHeight: "33px",
387
+ border: 0,
388
+ }),
389
+ option: (styles, { isFocused, isSelected }) => ({
390
+ ...styles,
391
+ backgroundColor: isFocused
392
+ ? "var(--Neutral-30)"
393
+ : isSelected
394
+ ? "var(--Neutral-20)"
395
+ : undefined,
396
+ }),
397
+ }}
398
+ defaultValue={selectedOption}
399
+ options={filterOptions}
400
+ onChange={(e) => {
401
+ setSelectedOption(e);
402
+ }}
403
+ />
404
+ <div className={cn("streaming-indicator", { connected })}>
405
+ {connected
406
+ ? `🔵${open ? " Streaming" : ""}`
407
+ : `⏸️${open ? " Paused" : ""}`}
408
+ </div>
409
+ </section>
410
+ <div className="side-panel-container" ref={loggerRef}>
411
+ <Logger
412
+ filter={(selectedOption?.value as LoggerFilterType) || "none"}
413
+ />
414
+ </div>
415
+ <div className={cn("input-container", { disabled: !connected })}>
416
+ <div className="input-content">
417
+ <textarea
418
+ className="input-area"
419
+ ref={inputRef}
420
+ onKeyDown={(e) => {
421
+ if (e.key === "Enter" && !e.shiftKey) {
422
+ e.preventDefault();
423
+ e.stopPropagation();
424
+ handleSubmit();
425
+ }
426
+ }}
427
+ onChange={(e) => setTextInput(e.target.value)}
428
+ value={textInput}
429
+ ></textarea>
430
+ <span
431
+ className={cn("input-content-placeholder", {
432
+ hidden: textInput.length,
433
+ })}
434
+ >
435
+ Type&nbsp;something...
436
+ </span>
437
+
438
+ <button
439
+ className="send-button material-symbols-outlined filled"
440
+ onClick={handleSubmit}
441
+ >
442
+ send
443
+ </button>
444
+ </div>
445
+ </div>
446
+
447
+ {/* Audio Pulse Bottom Section */}
448
+ <section className="audio-pulse-bottom">
449
+ <div className="pulse-container">
450
+ <AudioPulse volume={volume} active={connected} hover={false} />
451
+ <span className="pulse-label">
452
+ {connected ? (volume > 0 ? "AI Speaking..." : "AI Ready") : "Not connected"}
453
+ </span>
454
+ </div>
455
+ </section>
456
+
457
+ {/* Feedback Overlay Section */}
458
+ {sendFeedback && (
459
+ <div className="feedback-section" style={{
460
+ position: 'absolute',
461
+ top: '50%',
462
+ left: '50%',
463
+ transform: 'translate(-50%, -50%)',
464
+ padding: '20px',
465
+ background: 'rgba(255, 255, 255, 0.95)',
466
+ boxShadow: '0 0 10px rgba(0,0,0,0.2)',
467
+ borderRadius: '8px',
468
+ zIndex: 1001,
469
+ minWidth: '300px'
470
+ }}>
471
+ <h3>Provide Feedback</h3>
472
+ <div>
473
+ <label htmlFor="feedback-score">Score (0-10): </label>
474
+ <input
475
+ id="feedback-score"
476
+ type="number"
477
+ min="0"
478
+ max="10"
479
+ value={feedbackScore}
480
+ onChange={(e) => setFeedbackScore(Number(e.target.value))}
481
+ style={{margin: '0 10px'}}
482
+ />
483
+ </div>
484
+ <div style={{marginTop: '10px'}}>
485
+ <label htmlFor="feedback-text">Comments: </label>
486
+ <textarea
487
+ id="feedback-text"
488
+ value={feedbackText}
489
+ onChange={(e) => setFeedbackText(e.target.value)}
490
+ style={{
491
+ width: '100%',
492
+ height: '60px',
493
+ margin: '5px 0'
494
+ }}
495
+ />
496
+ </div>
497
+ <button
498
+ onClick={submitFeedback}
499
+ style={{
500
+ padding: '5px 10px',
501
+ marginTop: '5px',
502
+ cursor: 'pointer'
503
+ }}
504
+ >
505
+ Submit Feedback
506
+ </button>
507
+ </div>
508
+ )}
509
+ </div>
510
+ <TranscriptionPreview open={open} />
511
+ </div>
512
+ </div>
513
+ );
514
+ }
515
+
516
+ export default memo(SidePanel);