sunholo 0.144.3__tar.gz → 0.144.5__tar.gz

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 (204) hide show
  1. {sunholo-0.144.3/src/sunholo.egg-info → sunholo-0.144.5}/PKG-INFO +1 -1
  2. {sunholo-0.144.3 → sunholo-0.144.5}/pyproject.toml +1 -1
  3. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/fastapi/vac_routes.py +58 -37
  4. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/__init__.py +10 -1
  5. sunholo-0.144.5/src/sunholo/mcp/sse_utils.py +105 -0
  6. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/vac_mcp_server_fastmcp.py +2 -1
  7. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/vac_tools.py +48 -108
  8. {sunholo-0.144.3 → sunholo-0.144.5/src/sunholo.egg-info}/PKG-INFO +1 -1
  9. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo.egg-info/SOURCES.txt +1 -0
  10. {sunholo-0.144.3 → sunholo-0.144.5}/LICENSE.txt +0 -0
  11. {sunholo-0.144.3 → sunholo-0.144.5}/MANIFEST.in +0 -0
  12. {sunholo-0.144.3 → sunholo-0.144.5}/README.md +0 -0
  13. {sunholo-0.144.3 → sunholo-0.144.5}/setup.cfg +0 -0
  14. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/__init__.py +0 -0
  15. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/a2a/__init__.py +0 -0
  16. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/a2a/agent_card.py +0 -0
  17. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/a2a/task_manager.py +0 -0
  18. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/a2a/vac_a2a_agent.py +0 -0
  19. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/__init__.py +0 -0
  20. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/chat_history.py +0 -0
  21. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/dispatch_to_qa.py +0 -0
  22. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/fastapi/__init__.py +0 -0
  23. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/fastapi/base.py +0 -0
  24. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/fastapi/qna_routes.py +0 -0
  25. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/flask/__init__.py +0 -0
  26. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/flask/base.py +0 -0
  27. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/flask/vac_routes.py +0 -0
  28. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/langserve.py +0 -0
  29. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/pubsub.py +0 -0
  30. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/route.py +0 -0
  31. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/special_commands.py +0 -0
  32. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/agents/swagger.py +0 -0
  33. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/archive/__init__.py +0 -0
  34. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/archive/archive.py +0 -0
  35. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/auth/__init__.py +0 -0
  36. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/auth/gcloud.py +0 -0
  37. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/auth/refresh.py +0 -0
  38. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/auth/run.py +0 -0
  39. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/azure/__init__.py +0 -0
  40. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/azure/auth.py +0 -0
  41. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/azure/blobs.py +0 -0
  42. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/azure/event_grid.py +0 -0
  43. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/bots/__init__.py +0 -0
  44. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/bots/discord.py +0 -0
  45. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/bots/github_webhook.py +0 -0
  46. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/bots/webapp.py +0 -0
  47. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/__init__.py +0 -0
  48. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/azure.py +0 -0
  49. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/doc_handling.py +0 -0
  50. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/encode_metadata.py +0 -0
  51. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/images.py +0 -0
  52. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/loaders.py +0 -0
  53. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/message_data.py +0 -0
  54. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/pdfs.py +0 -0
  55. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/process_chunker_data.py +0 -0
  56. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/publish.py +0 -0
  57. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/pubsub.py +0 -0
  58. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/chunker/splitter.py +0 -0
  59. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/__init__.py +0 -0
  60. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/chat_vac.py +0 -0
  61. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/cli.py +0 -0
  62. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/cli_init.py +0 -0
  63. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/configs.py +0 -0
  64. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/deploy.py +0 -0
  65. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/embedder.py +0 -0
  66. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/merge_texts.py +0 -0
  67. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/run_proxy.py +0 -0
  68. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/sun_rich.py +0 -0
  69. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/swagger.py +0 -0
  70. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/cli/vertex.py +0 -0
  71. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/components/__init__.py +0 -0
  72. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/components/llm.py +0 -0
  73. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/components/retriever.py +0 -0
  74. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/components/vectorstore.py +0 -0
  75. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/custom_logging.py +0 -0
  76. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/__init__.py +0 -0
  77. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/alloydb.py +0 -0
  78. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/alloydb_client.py +0 -0
  79. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/database.py +0 -0
  80. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/lancedb.py +0 -0
  81. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/sql/sb/create_function.sql +0 -0
  82. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/sql/sb/create_function_time.sql +0 -0
  83. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/sql/sb/create_table.sql +0 -0
  84. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  85. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/sql/sb/return_sources.sql +0 -0
  86. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/sql/sb/setup.sql +0 -0
  87. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/static_dbs.py +0 -0
  88. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/database/uuid.py +0 -0
  89. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/discovery_engine/__init__.py +0 -0
  90. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/discovery_engine/chunker_handler.py +0 -0
  91. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/discovery_engine/cli.py +0 -0
  92. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/discovery_engine/create_new.py +0 -0
  93. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  94. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  95. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/embedder/__init__.py +0 -0
  96. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/embedder/embed_chunk.py +0 -0
  97. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/embedder/embed_metadata.py +0 -0
  98. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/excel/__init__.py +0 -0
  99. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/excel/plugin.py +0 -0
  100. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/gcs/__init__.py +0 -0
  101. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/gcs/add_file.py +0 -0
  102. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/gcs/download_folder.py +0 -0
  103. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/gcs/download_gcs_text.py +0 -0
  104. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/gcs/download_url.py +0 -0
  105. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/gcs/extract_and_sign.py +0 -0
  106. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/gcs/metadata.py +0 -0
  107. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/genai/__init__.py +0 -0
  108. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/genai/file_handling.py +0 -0
  109. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/genai/genaiv2.py +0 -0
  110. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/genai/images.py +0 -0
  111. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/genai/init.py +0 -0
  112. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/genai/process_funcs_cls.py +0 -0
  113. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/genai/safety.py +0 -0
  114. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/invoke/__init__.py +0 -0
  115. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/invoke/async_class.py +0 -0
  116. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/invoke/direct_vac_func.py +0 -0
  117. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/invoke/invoke_vac_utils.py +0 -0
  118. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/langchain_types.py +0 -0
  119. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/langfuse/__init__.py +0 -0
  120. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/langfuse/callback.py +0 -0
  121. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/langfuse/evals.py +0 -0
  122. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/langfuse/prompts.py +0 -0
  123. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/llamaindex/__init__.py +0 -0
  124. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/llamaindex/get_files.py +0 -0
  125. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/llamaindex/import_files.py +0 -0
  126. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/llamaindex/llamaindex_class.py +0 -0
  127. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/llamaindex/user_history.py +0 -0
  128. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/lookup/__init__.py +0 -0
  129. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/lookup/model_lookup.yaml +0 -0
  130. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/cli.py +0 -0
  131. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/cli_fastmcp.py +0 -0
  132. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/extensible_mcp_server.py +0 -0
  133. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/mcp_manager.py +0 -0
  134. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/stdio_http_bridge.py +0 -0
  135. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/mcp/vac_mcp_server.py +0 -0
  136. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/ollama/__init__.py +0 -0
  137. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/ollama/ollama_images.py +0 -0
  138. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/pubsub/__init__.py +0 -0
  139. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/pubsub/process_pubsub.py +0 -0
  140. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/pubsub/pubsub_manager.py +0 -0
  141. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/qna/__init__.py +0 -0
  142. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/qna/parsers.py +0 -0
  143. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/qna/retry.py +0 -0
  144. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/senses/__init__.py +0 -0
  145. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/senses/stream_voice.py +0 -0
  146. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/streaming/__init__.py +0 -0
  147. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/streaming/content_buffer.py +0 -0
  148. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/streaming/langserve.py +0 -0
  149. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/streaming/stream_lookup.py +0 -0
  150. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/streaming/streaming.py +0 -0
  151. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/summarise/__init__.py +0 -0
  152. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/summarise/summarise.py +0 -0
  153. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/agent/__init__.py +0 -0
  154. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/agent/agent_service.py +0 -0
  155. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/agent/app.py +0 -0
  156. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/agent/my_log.py +0 -0
  157. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/agent/tools/__init__.py +0 -0
  158. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/agent/tools/your_agent.py +0 -0
  159. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/agent/vac_service.py +0 -0
  160. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/project/__init__.py +0 -0
  161. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/project/app.py +0 -0
  162. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/project/my_log.py +0 -0
  163. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/project/vac_service.py +0 -0
  164. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/system_services/__init__.py +0 -0
  165. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/system_services/app.py +0 -0
  166. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/templates/system_services/my_log.py +0 -0
  167. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/terraform/__init__.py +0 -0
  168. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/terraform/tfvars_editor.py +0 -0
  169. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/tools/__init__.py +0 -0
  170. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/tools/web_browser.py +0 -0
  171. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/__init__.py +0 -0
  172. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/api_key.py +0 -0
  173. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/big_context.py +0 -0
  174. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/config.py +0 -0
  175. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/config_class.py +0 -0
  176. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/config_schema.py +0 -0
  177. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/gcp.py +0 -0
  178. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/gcp_project.py +0 -0
  179. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/mime.py +0 -0
  180. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/parsers.py +0 -0
  181. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/proto_convert.py +0 -0
  182. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/timedelta.py +0 -0
  183. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/user_ids.py +0 -0
  184. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/utils/version.py +0 -0
  185. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/vertex/__init__.py +0 -0
  186. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/vertex/extensions_call.py +0 -0
  187. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/vertex/extensions_class.py +0 -0
  188. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/vertex/genai_functions.py +0 -0
  189. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/vertex/init.py +0 -0
  190. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/vertex/memory_tools.py +0 -0
  191. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/vertex/safety.py +0 -0
  192. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo/vertex/type_dict_to_json.py +0 -0
  193. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo.egg-info/dependency_links.txt +0 -0
  194. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo.egg-info/entry_points.txt +0 -0
  195. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo.egg-info/requires.txt +0 -0
  196. {sunholo-0.144.3 → sunholo-0.144.5}/src/sunholo.egg-info/top_level.txt +0 -0
  197. {sunholo-0.144.3 → sunholo-0.144.5}/tests/test_async.py +0 -0
  198. {sunholo-0.144.3 → sunholo-0.144.5}/tests/test_async_genai2.py +0 -0
  199. {sunholo-0.144.3 → sunholo-0.144.5}/tests/test_chat_history.py +0 -0
  200. {sunholo-0.144.3 → sunholo-0.144.5}/tests/test_config.py +0 -0
  201. {sunholo-0.144.3 → sunholo-0.144.5}/tests/test_genai2.py +0 -0
  202. {sunholo-0.144.3 → sunholo-0.144.5}/tests/test_unstructured.py +0 -0
  203. {sunholo-0.144.3 → sunholo-0.144.5}/tests/test_vac_routes_fastapi.py +0 -0
  204. {sunholo-0.144.3 → sunholo-0.144.5}/tests/test_vac_routes_mcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.144.3
3
+ Version: 0.144.5
4
4
  Summary: AI DevOps - a package to help deploy GenAI to the Cloud.
5
5
  Author-email: Holosun ApS <multivac@sunholo.com>
6
6
  License: Apache License, Version 2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sunholo"
7
- version = "0.144.3"
7
+ version = "0.144.5"
8
8
  description = "AI DevOps - a package to help deploy GenAI to the Cloud."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -534,44 +534,64 @@ class VACRoutesFastAPI:
534
534
  async def app_lifespan(app: FastAPI):
535
535
  yield
536
536
 
537
- # Create temporary app to get MCP app (always enabled for this method)
538
- temp_app = FastAPI()
539
- temp_routes = VACRoutesFastAPI(
540
- temp_app,
541
- stream_interpreter=stream_interpreter,
542
- vac_interpreter=vac_interpreter,
543
- enable_mcp_server=True, # Always enabled for create_app_with_mcp
544
- **kwargs
545
- )
546
-
547
- mcp_app = None
548
- if temp_routes.vac_mcp_server:
549
- mcp_app = temp_routes.vac_mcp_server.get_http_app()
550
-
551
- # Create combined lifespan
552
- @asynccontextmanager
553
- async def combined_lifespan(app: FastAPI):
554
- async with app_lifespan(app):
555
- if mcp_app:
537
+ # Import here to avoid circular imports
538
+ if VACMCPServer:
539
+ from fastmcp import FastMCP
540
+
541
+ # Create MCP server directly to get its lifespan
542
+ mcp_server = FastMCP("sunholo-vac-fastapi-server")
543
+
544
+ # Register built-in VAC tools directly with the stream interpreter
545
+ from sunholo.mcp.vac_tools import register_vac_tools
546
+ register_vac_tools(mcp_server, None, stream_interpreter)
547
+
548
+ # Get the MCP app with path="" so when mounted at /mcp it's accessible at /mcp
549
+ mcp_app = mcp_server.http_app(path="", stateless_http=True)
550
+
551
+ # Create combined lifespan
552
+ @asynccontextmanager
553
+ async def combined_lifespan(app: FastAPI):
554
+ async with app_lifespan(app):
556
555
  async with mcp_app.lifespan(app):
557
556
  yield
558
- else:
559
- yield
560
-
561
- # Create the actual app with combined lifespan
562
- app = FastAPI(
563
- title=title,
564
- lifespan=combined_lifespan if mcp_app else app_lifespan
565
- )
566
-
567
- # Initialize VAC routes (MCP always enabled for this method)
568
- vac_routes = VACRoutesFastAPI(
569
- app,
570
- stream_interpreter=stream_interpreter,
571
- vac_interpreter=vac_interpreter,
572
- enable_mcp_server=True, # Always enabled for create_app_with_mcp
573
- **kwargs
574
- )
557
+
558
+ # Create the actual app with combined lifespan
559
+ app = FastAPI(
560
+ title=title,
561
+ lifespan=combined_lifespan
562
+ )
563
+
564
+ # Mount the MCP app at /mcp
565
+ app.mount("/mcp", mcp_app)
566
+
567
+ # Now create VAC routes WITHOUT MCP (since we already mounted it)
568
+ vac_routes = VACRoutesFastAPI(
569
+ app,
570
+ stream_interpreter=stream_interpreter,
571
+ vac_interpreter=vac_interpreter,
572
+ enable_mcp_server=False, # Don't enable again since we manually mounted
573
+ **kwargs
574
+ )
575
+
576
+ # Store reference to MCP server for tool registration
577
+ vac_routes.vac_mcp_server = type('MockMCPServer', (), {
578
+ 'add_tool': lambda self, func, name=None, desc=None: mcp_server.tool(func) if name is None else mcp_server.tool(name=name)(func),
579
+ 'server': mcp_server
580
+ })()
581
+ else:
582
+ # No MCP support available
583
+ app = FastAPI(
584
+ title=title,
585
+ lifespan=app_lifespan
586
+ )
587
+
588
+ vac_routes = VACRoutesFastAPI(
589
+ app,
590
+ stream_interpreter=stream_interpreter,
591
+ vac_interpreter=vac_interpreter,
592
+ enable_mcp_server=False,
593
+ **kwargs
594
+ )
575
595
 
576
596
  return app, vac_routes
577
597
 
@@ -682,7 +702,8 @@ class VACRoutesFastAPI:
682
702
  # so we can't easily check if it's configured. The error will be
683
703
  # caught below if lifespan is missing.
684
704
 
685
- self.app.mount("/mcp", mcp_app)
705
+ # Mount at root - the MCP app already has /mcp path configured
706
+ self.app.mount("", mcp_app)
686
707
  log.info("✅ MCP server mounted at /mcp endpoint")
687
708
 
688
709
  except RuntimeError as e:
@@ -26,4 +26,13 @@ except ImportError as e:
26
26
  print(f"Warning: VACMCPServer not available - {e}")
27
27
  VACMCPServer = None
28
28
 
29
- __all__ = ['MCPClientManager', 'VACMCPServer']
29
+ # SSE utilities are always available
30
+ from .sse_utils import parse_sse_response, is_sse_response, extract_sse_data
31
+
32
+ __all__ = [
33
+ 'MCPClientManager',
34
+ 'VACMCPServer',
35
+ 'parse_sse_response',
36
+ 'is_sse_response',
37
+ 'extract_sse_data'
38
+ ]
@@ -0,0 +1,105 @@
1
+ # Copyright [2024] [Holosun ApS]
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
+ """
16
+ Utilities for parsing Server-Sent Events (SSE) responses from MCP servers.
17
+ """
18
+
19
+ import json
20
+ from typing import Any, Dict, Optional
21
+
22
+
23
+ def parse_sse_response(text: str) -> Dict[str, Any]:
24
+ """
25
+ Parse SSE-formatted response from MCP server.
26
+
27
+ FastMCP returns responses in SSE format when using HTTP transport,
28
+ even with stateless_http=True. This function extracts the JSON data
29
+ from the SSE format.
30
+
31
+ Args:
32
+ text: Raw response text from MCP server
33
+
34
+ Returns:
35
+ Parsed JSON data from the SSE response
36
+
37
+ Raises:
38
+ ValueError: If the response cannot be parsed
39
+
40
+ Example:
41
+ >>> response_text = 'event: message\\ndata: {"jsonrpc": "2.0", "id": 1, "result": {...}}'
42
+ >>> data = parse_sse_response(response_text)
43
+ >>> print(data['result'])
44
+ """
45
+ # Check if it's SSE format
46
+ if text.startswith('event:') or text.startswith('data:'):
47
+ # Parse SSE format - extract JSON from data: line
48
+ lines = text.split('\n')
49
+
50
+ # Find the data line
51
+ data_line = None
52
+ for line in lines:
53
+ if line.startswith('data:'):
54
+ data_line = line
55
+ break
56
+
57
+ if data_line:
58
+ # Remove 'data:' prefix and parse JSON
59
+ json_str = data_line[5:].strip()
60
+ try:
61
+ return json.loads(json_str)
62
+ except json.JSONDecodeError as e:
63
+ raise ValueError(f"Failed to parse JSON from SSE data: {e}")
64
+ else:
65
+ raise ValueError("No data line found in SSE response")
66
+ else:
67
+ # Try parsing as regular JSON
68
+ try:
69
+ return json.loads(text)
70
+ except json.JSONDecodeError as e:
71
+ raise ValueError(f"Response is not valid JSON or SSE format: {e}")
72
+
73
+
74
+ def is_sse_response(text: str) -> bool:
75
+ """
76
+ Check if a response is in SSE format.
77
+
78
+ Args:
79
+ text: Response text to check
80
+
81
+ Returns:
82
+ True if the response appears to be SSE format
83
+ """
84
+ return text.startswith('event:') or text.startswith('data:')
85
+
86
+
87
+ def extract_sse_data(text: str) -> Optional[str]:
88
+ """
89
+ Extract the data portion from an SSE response.
90
+
91
+ Args:
92
+ text: SSE-formatted response text
93
+
94
+ Returns:
95
+ The extracted data string, or None if not found
96
+ """
97
+ if not is_sse_response(text):
98
+ return None
99
+
100
+ lines = text.split('\n')
101
+ for line in lines:
102
+ if line.startswith('data:'):
103
+ return line[5:].strip()
104
+
105
+ return None
@@ -73,7 +73,8 @@ class VACMCPServer:
73
73
 
74
74
  def get_http_app(self):
75
75
  """Get the HTTP app for mounting in FastAPI."""
76
- return self.server.http_app()
76
+ # Following FastMCP docs: when mounted at root "", path="/mcp" gives us /mcp endpoint
77
+ return self.server.http_app(path="/mcp")
77
78
 
78
79
  def add_tool(self, func: Callable, name: str = None, description: str = None):
79
80
  """
@@ -20,6 +20,7 @@ Provides core Sunholo VAC functionality as MCP tools.
20
20
  import asyncio
21
21
  import os
22
22
  import sys
23
+ import traceback
23
24
  from typing import Dict, List, Optional, Any
24
25
 
25
26
  try:
@@ -39,14 +40,6 @@ except ImportError:
39
40
  ConfigManager = None
40
41
  CONFIG_AVAILABLE = False
41
42
 
42
- try:
43
- from ..streaming import start_streaming_chat_async
44
- STREAMING_AVAILABLE = True
45
- except ImportError:
46
- start_streaming_chat_async = None
47
- STREAMING_AVAILABLE = False
48
-
49
-
50
43
  def get_vac_config(vector_name: str = None) -> 'ConfigManager':
51
44
  """Get VAC configuration for the specified vector name."""
52
45
  if not CONFIG_AVAILABLE:
@@ -54,115 +47,21 @@ def get_vac_config(vector_name: str = None) -> 'ConfigManager':
54
47
 
55
48
  default_vac = os.getenv("DEFAULT_VAC_NAME", "demo")
56
49
  vac_name = vector_name or default_vac
57
- vac_config_folder = os.getenv("VAC_CONFIG_FOLDER")
58
-
59
- if vac_config_folder:
60
- return ConfigManager(vac_name, config_folder=vac_config_folder)
61
- else:
62
- return ConfigManager(vac_name)
63
-
64
-
65
- async def call_vac_async(question: str, vector_name: str, chat_history: List[Dict[str, str]] = None) -> str:
66
- """
67
- Call VAC asynchronously using the streaming interface.
68
-
69
- Args:
70
- question: The user's question
71
- vector_name: Name of the VAC to query
72
- chat_history: Previous conversation history
73
-
74
- Returns:
75
- The VAC's response
76
- """
77
- if not STREAMING_AVAILABLE:
78
- raise ImportError("Streaming functionality not available. Install sunholo with streaming support.")
79
-
80
- if chat_history is None:
81
- chat_history = []
82
50
 
83
- try:
84
- config = get_vac_config(vector_name)
85
-
86
- # Import the appropriate QNA function based on configuration
87
- llm_str = config.vacConfig('llm')
88
-
89
- if llm_str and 'anthropic' in llm_str.lower():
90
- try:
91
- from ..agents.langchain.vertex_genai2 import qna_async
92
- except ImportError:
93
- log.warning("Anthropic integration not available, falling back to default")
94
- from ..agents.langchain.vertex_genai2 import qna_async
95
- elif llm_str and 'openai' in llm_str.lower():
96
- try:
97
- from ..agents.langchain.vertex_genai2 import qna_async
98
- except ImportError:
99
- log.warning("OpenAI integration not available, falling back to default")
100
- from ..agents.langchain.vertex_genai2 import qna_async
101
- else:
102
- # Default to vertex AI
103
- from ..agents.langchain.vertex_genai2 import qna_async
104
-
105
- # Use streaming interface to get response
106
- full_response = ""
107
- async for chunk in start_streaming_chat_async(
108
- question=question,
109
- vector_name=vector_name,
110
- qna_func_async=qna_async,
111
- chat_history=chat_history
112
- ):
113
- if isinstance(chunk, dict) and 'answer' in chunk:
114
- full_response = chunk['answer']
115
- elif isinstance(chunk, str):
116
- full_response += chunk
117
-
118
- return full_response or "No response generated"
119
-
120
- except Exception as e:
121
- log.error(f"Error calling VAC {vector_name}: {str(e)}")
122
- return f"Error: {str(e)}"
51
+ # ConfigManager uses VAC_CONFIG_FOLDER env var automatically
52
+ return ConfigManager(vac_name)
123
53
 
124
54
 
125
- def register_vac_tools(server: 'FastMCP', registry: 'MCPToolRegistry' = None):
55
+ def register_vac_tools(server: 'FastMCP', registry: Optional[Any] = None, stream_interpreter: Optional[Any] = None):
126
56
  """
127
57
  Register built-in VAC tools with a FastMCP server.
128
58
 
129
59
  Args:
130
60
  server: FastMCP server instance
131
61
  registry: Optional registry to track tools
62
+ stream_interpreter: The stream interpreter function from VACRoutesFastAPI
132
63
  """
133
64
 
134
- @server.tool
135
- async def vac_stream(
136
- vector_name: str,
137
- user_input: str,
138
- chat_history: Optional[List[Dict[str, str]]] = None,
139
- stream_wait_time: float = 7,
140
- stream_timeout: float = 120
141
- ) -> str:
142
- """
143
- Stream responses from a Sunholo VAC (Virtual Agent Computer).
144
-
145
- Args:
146
- vector_name: Name of the VAC to interact with
147
- user_input: The user's question or input
148
- chat_history: Previous conversation history
149
- stream_wait_time: Time to wait between stream chunks (default: 7)
150
- stream_timeout: Maximum time to wait for response (default: 120)
151
-
152
- Returns:
153
- The streamed response from the VAC
154
- """
155
- if chat_history is None:
156
- chat_history = []
157
-
158
- log.info(f"MCP streaming request for VAC '{vector_name}': {user_input}")
159
-
160
- try:
161
- return await call_vac_async(user_input, vector_name, chat_history)
162
- except Exception as e:
163
- log.error(f"Error in MCP VAC stream: {str(e)}")
164
- return f"Error: {str(e)}"
165
-
166
65
  @server.tool
167
66
  async def vac_query(
168
67
  vector_name: str,
@@ -186,9 +85,51 @@ def register_vac_tools(server: 'FastMCP', registry: 'MCPToolRegistry' = None):
186
85
  log.info(f"MCP query request for VAC '{vector_name}': {user_input}")
187
86
 
188
87
  try:
189
- return await call_vac_async(user_input, vector_name, chat_history)
88
+ # If we have a stream_interpreter, use it directly
89
+ if stream_interpreter:
90
+ # Create a no-op callback for non-streaming
91
+ class NoOpCallback:
92
+ async def async_on_llm_new_token(self, token): pass
93
+ async def async_on_llm_end(self, response): pass
94
+ def on_llm_new_token(self, token): pass
95
+ def on_llm_end(self, response): pass
96
+
97
+ callback = NoOpCallback()
98
+
99
+ # Call the stream interpreter
100
+ import inspect
101
+ if inspect.iscoroutinefunction(stream_interpreter):
102
+ result = await stream_interpreter(
103
+ question=user_input,
104
+ vector_name=vector_name,
105
+ chat_history=chat_history,
106
+ callback=callback
107
+ )
108
+ else:
109
+ # Run sync function in executor
110
+ import asyncio
111
+ loop = asyncio.get_event_loop()
112
+ result = await loop.run_in_executor(
113
+ None,
114
+ stream_interpreter,
115
+ user_input,
116
+ vector_name,
117
+ chat_history,
118
+ callback
119
+ )
120
+
121
+ # Extract answer from result
122
+ if isinstance(result, dict):
123
+ return result.get('answer', str(result))
124
+ else:
125
+ return str(result)
126
+ else:
127
+ # Fallback to simple response if no interpreter provided
128
+ return f"VAC '{vector_name}' received: {user_input}"
129
+
190
130
  except Exception as e:
191
131
  log.error(f"Error in MCP VAC query: {str(e)}")
132
+ log.error(f"Traceback: {traceback.format_exc()}")
192
133
  return f"Error: {str(e)}"
193
134
 
194
135
  @server.tool
@@ -242,7 +183,6 @@ def register_vac_tools(server: 'FastMCP', registry: 'MCPToolRegistry' = None):
242
183
  # Register tools in registry if provided
243
184
  if registry:
244
185
  # Extract the underlying function from FunctionTool objects
245
- registry.register_tool("vac_stream", vac_stream.fn if hasattr(vac_stream, 'fn') else vac_stream)
246
186
  registry.register_tool("vac_query", vac_query.fn if hasattr(vac_query, 'fn') else vac_query)
247
187
  registry.register_tool("list_available_vacs", list_available_vacs.fn if hasattr(list_available_vacs, 'fn') else list_available_vacs)
248
188
  registry.register_tool("get_vac_info", get_vac_info.fn if hasattr(get_vac_info, 'fn') else get_vac_info)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.144.3
3
+ Version: 0.144.5
4
4
  Summary: AI DevOps - a package to help deploy GenAI to the Cloud.
5
5
  Author-email: Holosun ApS <multivac@sunholo.com>
6
6
  License: Apache License, Version 2.0
@@ -130,6 +130,7 @@ src/sunholo/mcp/cli.py
130
130
  src/sunholo/mcp/cli_fastmcp.py
131
131
  src/sunholo/mcp/extensible_mcp_server.py
132
132
  src/sunholo/mcp/mcp_manager.py
133
+ src/sunholo/mcp/sse_utils.py
133
134
  src/sunholo/mcp/stdio_http_bridge.py
134
135
  src/sunholo/mcp/vac_mcp_server.py
135
136
  src/sunholo/mcp/vac_mcp_server_fastmcp.py
File without changes
File without changes
File without changes
File without changes