sunholo 0.144.2__tar.gz → 0.144.3__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.
- {sunholo-0.144.2/src/sunholo.egg-info → sunholo-0.144.3}/PKG-INFO +1 -1
- {sunholo-0.144.2 → sunholo-0.144.3}/pyproject.toml +1 -1
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/fastapi/vac_routes.py +229 -13
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/vac_mcp_server_fastmcp.py +1 -1
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/vac_tools.py +5 -4
- {sunholo-0.144.2 → sunholo-0.144.3/src/sunholo.egg-info}/PKG-INFO +1 -1
- {sunholo-0.144.2 → sunholo-0.144.3}/tests/test_vac_routes_mcp.py +24 -3
- {sunholo-0.144.2 → sunholo-0.144.3}/LICENSE.txt +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/MANIFEST.in +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/README.md +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/setup.cfg +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/a2a/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/a2a/agent_card.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/a2a/task_manager.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/a2a/vac_a2a_agent.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/chat_history.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/dispatch_to_qa.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/fastapi/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/fastapi/base.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/fastapi/qna_routes.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/flask/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/flask/base.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/flask/vac_routes.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/langserve.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/pubsub.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/route.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/special_commands.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/agents/swagger.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/archive/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/archive/archive.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/auth/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/auth/gcloud.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/auth/refresh.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/auth/run.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/azure/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/azure/auth.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/azure/blobs.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/azure/event_grid.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/bots/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/bots/discord.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/bots/github_webhook.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/bots/webapp.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/azure.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/doc_handling.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/encode_metadata.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/images.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/loaders.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/message_data.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/pdfs.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/process_chunker_data.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/publish.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/pubsub.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/chunker/splitter.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/chat_vac.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/cli.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/cli_init.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/configs.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/deploy.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/embedder.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/merge_texts.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/run_proxy.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/sun_rich.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/swagger.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/cli/vertex.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/components/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/components/llm.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/components/retriever.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/components/vectorstore.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/custom_logging.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/alloydb.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/alloydb_client.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/database.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/lancedb.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/sql/sb/create_function.sql +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/sql/sb/create_function_time.sql +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/sql/sb/create_table.sql +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/sql/sb/delete_source_row.sql +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/sql/sb/return_sources.sql +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/sql/sb/setup.sql +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/static_dbs.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/database/uuid.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/discovery_engine/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/discovery_engine/chunker_handler.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/discovery_engine/cli.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/discovery_engine/create_new.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/discovery_engine/discovery_engine_client.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/embedder/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/embedder/embed_chunk.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/embedder/embed_metadata.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/excel/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/excel/plugin.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/gcs/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/gcs/add_file.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/gcs/download_folder.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/gcs/download_gcs_text.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/gcs/download_url.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/gcs/extract_and_sign.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/gcs/metadata.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/genai/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/genai/file_handling.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/genai/genaiv2.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/genai/images.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/genai/init.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/genai/process_funcs_cls.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/genai/safety.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/invoke/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/invoke/async_class.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/invoke/direct_vac_func.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/invoke/invoke_vac_utils.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/langchain_types.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/langfuse/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/langfuse/callback.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/langfuse/evals.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/langfuse/prompts.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/llamaindex/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/llamaindex/get_files.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/llamaindex/import_files.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/llamaindex/llamaindex_class.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/llamaindex/user_history.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/lookup/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/lookup/model_lookup.yaml +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/cli.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/cli_fastmcp.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/extensible_mcp_server.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/mcp_manager.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/stdio_http_bridge.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/mcp/vac_mcp_server.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/ollama/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/ollama/ollama_images.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/pubsub/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/pubsub/process_pubsub.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/pubsub/pubsub_manager.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/qna/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/qna/parsers.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/qna/retry.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/senses/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/senses/stream_voice.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/streaming/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/streaming/content_buffer.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/streaming/langserve.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/streaming/stream_lookup.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/streaming/streaming.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/summarise/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/summarise/summarise.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/agent/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/agent/agent_service.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/agent/app.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/agent/my_log.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/agent/tools/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/agent/tools/your_agent.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/agent/vac_service.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/project/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/project/app.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/project/my_log.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/project/vac_service.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/system_services/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/system_services/app.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/templates/system_services/my_log.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/terraform/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/terraform/tfvars_editor.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/tools/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/tools/web_browser.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/api_key.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/big_context.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/config.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/config_class.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/config_schema.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/gcp.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/gcp_project.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/mime.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/parsers.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/proto_convert.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/timedelta.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/user_ids.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/utils/version.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/vertex/__init__.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/vertex/extensions_call.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/vertex/extensions_class.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/vertex/genai_functions.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/vertex/init.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/vertex/memory_tools.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/vertex/safety.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo/vertex/type_dict_to_json.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo.egg-info/SOURCES.txt +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo.egg-info/dependency_links.txt +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo.egg-info/entry_points.txt +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo.egg-info/requires.txt +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/src/sunholo.egg-info/top_level.txt +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/tests/test_async.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/tests/test_async_genai2.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/tests/test_chat_history.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/tests/test_config.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/tests/test_genai2.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/tests/test_unstructured.py +0 -0
- {sunholo-0.144.2 → sunholo-0.144.3}/tests/test_vac_routes_fastapi.py +0 -0
@@ -113,31 +113,92 @@ class VACRoutesFastAPI:
|
|
113
113
|
|
114
114
|
## Basic Usage
|
115
115
|
|
116
|
+
### Simplified Setup (Recommended)
|
117
|
+
|
118
|
+
Use the helper method for automatic lifespan management:
|
119
|
+
|
116
120
|
```python
|
117
|
-
from fastapi import FastAPI
|
118
121
|
from sunholo.agents.fastapi import VACRoutesFastAPI
|
119
122
|
|
120
|
-
app = FastAPI()
|
121
|
-
|
122
123
|
async def my_stream_interpreter(question, vector_name, chat_history, callback, **kwargs):
|
123
124
|
# Your streaming VAC logic here
|
124
125
|
# Use callback.async_on_llm_new_token(token) for streaming
|
125
|
-
# Return final result with sources
|
126
126
|
return {"answer": "Response", "sources": []}
|
127
127
|
|
128
|
-
#
|
128
|
+
# Single call sets up everything with MCP server and proper lifespan management
|
129
|
+
app, vac_routes = VACRoutesFastAPI.create_app_with_mcp(
|
130
|
+
title="My VAC Application",
|
131
|
+
stream_interpreter=my_stream_interpreter
|
132
|
+
# MCP server is automatically enabled when using this method
|
133
|
+
)
|
134
|
+
|
135
|
+
# Add custom endpoints if needed
|
136
|
+
@app.get("/custom")
|
137
|
+
async def custom_endpoint():
|
138
|
+
return {"message": "Hello"}
|
139
|
+
|
140
|
+
# Run the app
|
141
|
+
if __name__ == "__main__":
|
142
|
+
import uvicorn
|
143
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
144
|
+
```
|
145
|
+
|
146
|
+
### Manual Setup (Advanced)
|
147
|
+
|
148
|
+
For more control over lifespan management:
|
149
|
+
|
150
|
+
```python
|
151
|
+
from contextlib import asynccontextmanager
|
152
|
+
from fastapi import FastAPI
|
153
|
+
from sunholo.agents.fastapi import VACRoutesFastAPI
|
154
|
+
|
155
|
+
async def my_stream_interpreter(question, vector_name, chat_history, callback, **kwargs):
|
156
|
+
return {"answer": "Response", "sources": []}
|
157
|
+
|
158
|
+
# Define your app's lifespan
|
159
|
+
@asynccontextmanager
|
160
|
+
async def app_lifespan(app: FastAPI):
|
161
|
+
print("Starting up...")
|
162
|
+
yield
|
163
|
+
print("Shutting down...")
|
164
|
+
|
165
|
+
# Create temp app to get MCP lifespan
|
166
|
+
temp_app = FastAPI()
|
167
|
+
vac_routes_temp = VACRoutesFastAPI(
|
168
|
+
temp_app,
|
169
|
+
stream_interpreter=my_stream_interpreter,
|
170
|
+
enable_mcp_server=True
|
171
|
+
)
|
172
|
+
|
173
|
+
# Get MCP lifespan
|
174
|
+
mcp_lifespan = vac_routes_temp.get_mcp_lifespan()
|
175
|
+
|
176
|
+
# Combine lifespans
|
177
|
+
@asynccontextmanager
|
178
|
+
async def combined_lifespan(app: FastAPI):
|
179
|
+
async with app_lifespan(app):
|
180
|
+
if mcp_lifespan:
|
181
|
+
async with mcp_lifespan(app):
|
182
|
+
yield
|
183
|
+
else:
|
184
|
+
yield
|
185
|
+
|
186
|
+
# Create app with combined lifespan
|
187
|
+
app = FastAPI(title="My VAC Application", lifespan=combined_lifespan)
|
188
|
+
|
189
|
+
# Initialize VAC routes
|
129
190
|
vac_routes = VACRoutesFastAPI(
|
130
191
|
app=app,
|
131
192
|
stream_interpreter=my_stream_interpreter,
|
132
|
-
enable_mcp_server=True
|
193
|
+
enable_mcp_server=True
|
133
194
|
)
|
134
|
-
|
135
|
-
# Your FastAPI app now includes:
|
136
|
-
# - All VAC endpoints
|
137
|
-
# - MCP server at /mcp (for Claude Desktop/Code to connect)
|
138
|
-
# - Built-in VAC tools: vac_stream, vac_query, list_available_vacs, get_vac_info
|
139
195
|
```
|
140
196
|
|
197
|
+
Your FastAPI app now includes:
|
198
|
+
- All VAC endpoints
|
199
|
+
- MCP server at /mcp (for Claude Desktop/Code to connect)
|
200
|
+
- Built-in VAC tools: vac_stream, vac_query, list_available_vacs, get_vac_info
|
201
|
+
|
141
202
|
## Adding Custom MCP Tools
|
142
203
|
|
143
204
|
### Method 1: Using Decorators
|
@@ -416,6 +477,138 @@ class VACRoutesFastAPI:
|
|
416
477
|
|
417
478
|
self.register_routes()
|
418
479
|
|
480
|
+
@staticmethod
|
481
|
+
def create_app_with_mcp(
|
482
|
+
title: str = "VAC Application",
|
483
|
+
stream_interpreter: Optional[callable] = None,
|
484
|
+
vac_interpreter: Optional[callable] = None,
|
485
|
+
app_lifespan: Optional[callable] = None,
|
486
|
+
**kwargs
|
487
|
+
) -> tuple[FastAPI, 'VACRoutesFastAPI']:
|
488
|
+
"""
|
489
|
+
Helper method to create a FastAPI app with proper MCP lifespan management.
|
490
|
+
|
491
|
+
This method simplifies the setup process by handling the lifespan combination
|
492
|
+
automatically, avoiding the need for the double initialization pattern.
|
493
|
+
MCP server is automatically enabled when using this method.
|
494
|
+
|
495
|
+
Args:
|
496
|
+
title: Title for the FastAPI app
|
497
|
+
stream_interpreter: Streaming interpreter function
|
498
|
+
vac_interpreter: Non-streaming interpreter function
|
499
|
+
app_lifespan: Optional app lifespan context manager
|
500
|
+
**kwargs: Additional arguments passed to VACRoutesFastAPI (except enable_mcp_server)
|
501
|
+
|
502
|
+
Returns:
|
503
|
+
Tuple of (FastAPI app, VACRoutesFastAPI instance)
|
504
|
+
|
505
|
+
Example:
|
506
|
+
```python
|
507
|
+
from sunholo.agents.fastapi import VACRoutesFastAPI
|
508
|
+
|
509
|
+
async def my_interpreter(question, vector_name, chat_history, callback, **kwargs):
|
510
|
+
# Your logic here
|
511
|
+
return {"answer": "response", "sources": []}
|
512
|
+
|
513
|
+
# Single call to set up everything (MCP is automatically enabled)
|
514
|
+
app, vac_routes = VACRoutesFastAPI.create_app_with_mcp(
|
515
|
+
title="My VAC App",
|
516
|
+
stream_interpreter=my_interpreter
|
517
|
+
)
|
518
|
+
|
519
|
+
# Add custom endpoints
|
520
|
+
@app.get("/custom")
|
521
|
+
async def custom_endpoint():
|
522
|
+
return {"message": "Custom endpoint"}
|
523
|
+
|
524
|
+
if __name__ == "__main__":
|
525
|
+
import uvicorn
|
526
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
527
|
+
```
|
528
|
+
"""
|
529
|
+
from contextlib import asynccontextmanager
|
530
|
+
|
531
|
+
# Default app lifespan if not provided
|
532
|
+
if app_lifespan is None:
|
533
|
+
@asynccontextmanager
|
534
|
+
async def app_lifespan(app: FastAPI):
|
535
|
+
yield
|
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:
|
556
|
+
async with mcp_app.lifespan(app):
|
557
|
+
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
|
+
)
|
575
|
+
|
576
|
+
return app, vac_routes
|
577
|
+
|
578
|
+
def get_mcp_lifespan(self):
|
579
|
+
"""
|
580
|
+
Get the MCP app's lifespan for manual lifespan management.
|
581
|
+
|
582
|
+
Returns:
|
583
|
+
The MCP app's lifespan if MCP server is enabled, None otherwise.
|
584
|
+
|
585
|
+
Example:
|
586
|
+
```python
|
587
|
+
from contextlib import asynccontextmanager
|
588
|
+
|
589
|
+
# Create temp app to get MCP lifespan
|
590
|
+
temp_app = FastAPI()
|
591
|
+
vac_routes = VACRoutesFastAPI(temp_app, ..., enable_mcp_server=True)
|
592
|
+
mcp_lifespan = vac_routes.get_mcp_lifespan()
|
593
|
+
|
594
|
+
# Combine with your app's lifespan
|
595
|
+
@asynccontextmanager
|
596
|
+
async def combined_lifespan(app: FastAPI):
|
597
|
+
async with my_app_lifespan(app):
|
598
|
+
if mcp_lifespan:
|
599
|
+
async with mcp_lifespan(app):
|
600
|
+
yield
|
601
|
+
else:
|
602
|
+
yield
|
603
|
+
|
604
|
+
app = FastAPI(lifespan=combined_lifespan)
|
605
|
+
```
|
606
|
+
"""
|
607
|
+
if self.vac_mcp_server:
|
608
|
+
mcp_app = self.vac_mcp_server.get_http_app()
|
609
|
+
return mcp_app.lifespan
|
610
|
+
return None
|
611
|
+
|
419
612
|
async def vac_interpreter_default(self, question: str, vector_name: str, chat_history=None, **kwargs):
|
420
613
|
"""Default VAC interpreter that uses the stream interpreter without streaming."""
|
421
614
|
class NoOpCallback:
|
@@ -484,11 +677,34 @@ class VACRoutesFastAPI:
|
|
484
677
|
if self.enable_mcp_server and self.vac_mcp_server:
|
485
678
|
try:
|
486
679
|
mcp_app = self.vac_mcp_server.get_http_app()
|
680
|
+
|
681
|
+
# Note: FastAPI doesn't expose lifespan as a public attribute,
|
682
|
+
# so we can't easily check if it's configured. The error will be
|
683
|
+
# caught below if lifespan is missing.
|
684
|
+
|
487
685
|
self.app.mount("/mcp", mcp_app)
|
488
|
-
log.info("MCP server mounted at /mcp endpoint")
|
686
|
+
log.info("✅ MCP server mounted at /mcp endpoint")
|
687
|
+
|
688
|
+
except RuntimeError as e:
|
689
|
+
if "Task group is not initialized" in str(e):
|
690
|
+
error_msg = (
|
691
|
+
"MCP server initialization failed: Lifespan not configured properly.\n"
|
692
|
+
"The FastAPI app must be created with the MCP lifespan.\n\n"
|
693
|
+
"Quick fix: Use the helper method:\n"
|
694
|
+
" app, vac_routes = VACRoutesFastAPI.create_app_with_mcp(\n"
|
695
|
+
" stream_interpreter=your_interpreter,\n"
|
696
|
+
" enable_mcp_server=True\n"
|
697
|
+
" )\n\n"
|
698
|
+
"Or manually configure the lifespan - see documentation for details."
|
699
|
+
)
|
700
|
+
log.error(error_msg)
|
701
|
+
raise RuntimeError(error_msg) from e
|
702
|
+
else:
|
703
|
+
log.error(f"Failed to mount MCP server: {e}")
|
704
|
+
raise RuntimeError(f"MCP server initialization failed: {e}") from e
|
489
705
|
except Exception as e:
|
490
706
|
log.error(f"Failed to mount MCP server: {e}")
|
491
|
-
raise RuntimeError(f"MCP server initialization failed: {e}")
|
707
|
+
raise RuntimeError(f"MCP server initialization failed: {e}") from e
|
492
708
|
|
493
709
|
# A2A agent endpoints
|
494
710
|
if self.enable_a2a_agent:
|
@@ -241,9 +241,10 @@ def register_vac_tools(server: 'FastMCP', registry: 'MCPToolRegistry' = None):
|
|
241
241
|
|
242
242
|
# Register tools in registry if provided
|
243
243
|
if registry:
|
244
|
-
|
245
|
-
registry.register_tool("
|
246
|
-
registry.register_tool("
|
247
|
-
registry.register_tool("
|
244
|
+
# 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
|
+
registry.register_tool("vac_query", vac_query.fn if hasattr(vac_query, 'fn') else vac_query)
|
247
|
+
registry.register_tool("list_available_vacs", list_available_vacs.fn if hasattr(list_available_vacs, 'fn') else list_available_vacs)
|
248
|
+
registry.register_tool("get_vac_info", get_vac_info.fn if hasattr(get_vac_info, 'fn') else get_vac_info)
|
248
249
|
|
249
250
|
log.info("Registered built-in VAC tools with MCP server")
|
@@ -200,19 +200,40 @@ class MockMCPClientManager:
|
|
200
200
|
@pytest.fixture
|
201
201
|
def mcp_server_app():
|
202
202
|
"""Create a FastAPI app with MCP server enabled."""
|
203
|
-
|
203
|
+
from contextlib import asynccontextmanager
|
204
|
+
|
205
|
+
# Create a simple lifespan for the test
|
206
|
+
@asynccontextmanager
|
207
|
+
async def test_lifespan(app: FastAPI):
|
208
|
+
yield
|
209
|
+
|
210
|
+
app = FastAPI(lifespan=test_lifespan)
|
211
|
+
|
212
|
+
# First disable MCP server to avoid initialization issues
|
204
213
|
vac_routes = VACRoutesFastAPI(
|
205
214
|
app,
|
206
215
|
stream_interpreter=mock_async_stream_interpreter,
|
207
216
|
vac_interpreter=mock_async_vac_interpreter,
|
208
|
-
enable_mcp_server=
|
217
|
+
enable_mcp_server=False, # Disable initially
|
209
218
|
add_langfuse_eval=False
|
210
219
|
)
|
211
|
-
|
220
|
+
|
221
|
+
# Add a mock MCP endpoint manually for testing
|
222
|
+
@app.post("/mcp")
|
223
|
+
async def mock_mcp_endpoint(request: dict):
|
224
|
+
"""Mock MCP endpoint for testing."""
|
225
|
+
mock_server = MockVACMCPServer(
|
226
|
+
mock_async_stream_interpreter,
|
227
|
+
mock_async_vac_interpreter
|
228
|
+
)
|
229
|
+
return await mock_server.handle_request(request)
|
230
|
+
|
231
|
+
# Set the mock server for other tests that might need it
|
212
232
|
vac_routes.vac_mcp_server = MockVACMCPServer(
|
213
233
|
mock_async_stream_interpreter,
|
214
234
|
mock_async_vac_interpreter
|
215
235
|
)
|
236
|
+
|
216
237
|
return app
|
217
238
|
|
218
239
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|