dao-ai 0.1.16__tar.gz → 0.1.17__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.
- {dao_ai-0.1.16 → dao_ai-0.1.17}/PKG-INFO +2 -2
- {dao_ai-0.1.16 → dao_ai-0.1.17}/README.md +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/custom_mcp.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/filtered_mcp.yaml +1 -2
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/managed_mcp.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/slack_integration.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/genie_lru_cache.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/genie_semantic_cache.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/genie_with_conversation_id.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/conversation_summarization.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/07_human_in_the_loop/human_in_the_loop.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/11_prompt_engineering/prompt_optimization.yaml +0 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/11_prompt_engineering/prompt_registry.yaml +0 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/13_orchestration/README.md +7 -5
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/deep_research.yaml +0 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/hardware_store_swarm.yaml +0 -4
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/quick_serve_restaurant.yaml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/architecture.md +0 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/configuration-reference.md +0 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/pyproject.toml +1 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/schemas/model_config_schema.json +6 -7
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/cli.py +4 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/config.py +57 -12
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/orchestration/swarm.py +6 -1
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/mcp.py +21 -10
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_mcp.py +3 -2
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_mcp_filtering_integration.py +30 -19
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_mcp_function_model.py +23 -19
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_swarm_middleware.py +0 -8
- dao_ai-0.1.17/tests/test_mcp_app_auth.py +114 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/.gitignore +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/.python-version +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/CHANGELOG.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/CONTRIBUTING.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/LICENSE +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/Makefile +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/app.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/01_getting_started/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/01_getting_started/minimal.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/external_mcp.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/03_reranking/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/03_reranking/vector_search_with_reranking.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/genie_basic.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/in_memory_basic.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/lakebase_persistence.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/postgres_persistence.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/06_on_behalf_of_user/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/06_on_behalf_of_user/obo_basic.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/07_human_in_the_loop/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/08_guardrails/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/08_guardrails/guardrails_basic.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/09_structured_output/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/09_structured_output/structured_output.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/10_agent_integrations/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/10_agent_integrations/agent_bricks.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/10_agent_integrations/kasal.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/11_prompt_engineering/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/combined_middleware.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/context_management.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/custom_field_validation.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/limit_middleware.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/logging_middleware.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/pii_middleware.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/retry_middleware.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/tool_selector_middleware.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/13_orchestration/supervisor_pattern.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/13_orchestration/swarm_pattern.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/14_basic_tools/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/14_basic_tools/sql_tool_example.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/brick_store.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/executive_assistant.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/genie_and_genie_mcp.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/genie_vector_search_hybrid.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/hardware_store.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/hardware_store_lakebase.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/reservations_system.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/appointments.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/appointments_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/brand_rep_demo_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/brand_rep_demo_queries.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/brand_rep_demo_tables.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/brand_rep_demo_validation.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/customers.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/customers_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/dim_stores.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/dim_stores_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/employee_performance.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/employee_performance_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/employee_tasks.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/employee_tasks_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/inventory.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/inventory_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/managers.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/managers_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/product_data.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/products.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/task_assignments.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/hardware_store/inventory.snappy.parquet +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/hardware_store/inventory.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/hardware_store/products.snappy.parquet +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/hardware_store/products.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/.gitkeep +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/fulfil_item_orders.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/items_description.csv +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/items_description.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/items_raw.csv +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/items_raw.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/orders_raw.csv +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/orders_raw.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/databricks.yaml.template +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/cli-reference.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/contributing.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/examples.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/faq.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/hardware_store/README.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/hardware_store/retail_supervisor.png +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/hardware_store/retail_swarm.png +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/images/genie.png +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/key-capabilities.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/python-api.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/quick_serve_restaurant/.gitkeep +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/quick_serve_restaurant/quick-serve-restaurant.png +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/why-dao.md +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/environment.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/dais2025/examples.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/deep_research/examples.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/executive_assistant/examples.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/hardware_store/examples.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/quick_serve_restaurant/.gitkeep +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/quick_serve_restaurant/examples.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/extract_store_numbers.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_inventory_by_sku.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_inventory_by_upc.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_product_by_sku.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_product_by_upc.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_store_by_number.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_store_inventory_by_sku.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_store_inventory_by_upc.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_inventory_by_sku.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_inventory_by_upc.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_product_by_sku.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_product_by_upc.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_store_inventory_by_sku.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_store_inventory_by_upc.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/.gitkeep +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/insert_coffee_order.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/lookup_items_by_descriptions.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/match_historical_item_order_by_date.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/match_item_by_description_and_price.sql +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/01_ingest_and_transform.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/02_provision_vector_search.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/03_provision_lakebase.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/04_unity_catalog_tools.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/05_deploy_agent.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/06_generate_evaluation_data.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/07_run_evaluation.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/08_run_examples.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/09_evaluate_inferences.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/10_optimize_prompts.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/99_scratchpad.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/requirements.txt +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/schemas/bundle_config_schema.json +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/models.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/customer.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/employee.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/executive.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/genie.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/inventory.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/models.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/store.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/handlers.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/model_serving.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/resources.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/server.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/catalog.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/base.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/core.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/lru.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/semantic.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/core.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/graph.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/hooks/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/hooks/core.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/logging.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/base.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/core.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/databricks.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/postgres.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/messages.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/assertions.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/base.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/context_editing.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/core.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/guardrails.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/human_in_the_loop.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/message_validation.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/model_call_limit.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/model_retry.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/pii.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/summarization.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/tool_call_limit.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/tool_retry.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/tool_selector.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/models.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/nodes.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/optimization.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/orchestration/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/orchestration/core.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/orchestration/supervisor.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/prompts.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/providers/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/providers/base.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/providers/databricks.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/state.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/__init__.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/agent.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/core.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/email.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/genie.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/memory.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/python.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/search.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/slack.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/sql.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/time.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/unity_catalog.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/vector_search.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/types.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/utils.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/vector_search.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/config/test_model_config.yaml +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/conftest.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_context_editing.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_model_call_limit.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_model_retry.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_pii.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_tool_call_limit.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_tool_retry.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_tool_selector.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_agent_response_format.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_assertions_middleware.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_catalog.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_chat_history.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_config.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_databricks.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_function_parsing.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_genie.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_genie_conversation_ids_in_outputs.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_genie_databricks_integration.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_genie_room_model.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_guardrail_retry.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_hitl_config_model.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_hitl_responses_agent.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_hooks.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_human_in_the_loop.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_inference.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_inference_integration.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_input_output_structure.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_interrupt_type.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_llm_interrupt_handling.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_mcp_filtering.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_message_validation_middleware.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_messages.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_models.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_optimization.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_postgres_integration.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_prompt_optimizations.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_prompts.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_reranking.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_reranking_integration.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_resources_model_genie_integration.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_response_format.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_responses_agent_structured_output_unit.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_semantic_cache_context.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_sql_tool.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_sql_tool_integration.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_state.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_summarization_inference.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_tools.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_types.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_unity_catalog.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_utils.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_utils_type_from_fqn.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_vector_search.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_warehouse_model.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/weather_server_mcp.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/hardware_store/.gitkeep +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/hardware_store/test_graph.py +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/images/doritos_upc.png +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/images/lays_upc.png +0 -0
- {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/quick_serve_restaurant/.gitkeep +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dao-ai
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.17
|
|
4
4
|
Summary: DAO AI: A modular, multi-agent orchestration framework for complex AI workflows. Supports agent handoff, tool integration, and dynamic configuration via YAML.
|
|
5
5
|
Project-URL: Homepage, https://github.com/natefleming/dao-ai
|
|
6
6
|
Project-URL: Documentation, https://natefleming.github.io/dao-ai
|
|
@@ -235,7 +235,7 @@ app:
|
|
|
235
235
|
- *assistant
|
|
236
236
|
orchestration:
|
|
237
237
|
swarm:
|
|
238
|
-
|
|
238
|
+
default_agent: *assistant
|
|
239
239
|
```
|
|
240
240
|
|
|
241
241
|
**💡 What's happening here?**
|
|
@@ -309,8 +309,7 @@ app:
|
|
|
309
309
|
- *functions_agent # Functions agent
|
|
310
310
|
orchestration: # Agent orchestration configuration
|
|
311
311
|
swarm: # Supervisor orchestration pattern
|
|
312
|
-
|
|
313
|
-
# Agents will be automatically routed based on their capabilities
|
|
312
|
+
default_agent: *general_agent # Default agent for routing
|
|
314
313
|
|
|
315
314
|
# =============================================================================
|
|
316
315
|
# USAGE NOTES
|
|
@@ -93,6 +93,6 @@ app:
|
|
|
93
93
|
orchestration: # Agent orchestration configuration
|
|
94
94
|
memory: *memory # In-memory conversation persistence
|
|
95
95
|
swarm: # Swarm orchestration pattern
|
|
96
|
-
|
|
96
|
+
default_agent: *genie # Default agent for routing
|
|
97
97
|
|
|
98
98
|
|
|
@@ -131,5 +131,5 @@ app:
|
|
|
131
131
|
orchestration: # Agent orchestration configuration
|
|
132
132
|
memory: *memory # In-memory conversation persistence
|
|
133
133
|
swarm: # Swarm orchestration pattern
|
|
134
|
-
|
|
134
|
+
default_agent: *genie # Default agent for routing
|
|
135
135
|
|
|
@@ -132,7 +132,7 @@ app:
|
|
|
132
132
|
orchestration: # Agent orchestration configuration
|
|
133
133
|
memory: *memory # Memory store for conversation context
|
|
134
134
|
swarm: # Supervisor orchestration pattern
|
|
135
|
-
|
|
135
|
+
default_agent: *genie # Default agent for routing
|
|
136
136
|
|
|
137
137
|
|
|
138
138
|
|
|
@@ -105,11 +105,13 @@ app:
|
|
|
105
105
|
- inventory_agent # Can transfer to product or comparison
|
|
106
106
|
- comparison_agent # Can transfer back to product or inventory
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
orchestration:
|
|
109
|
+
swarm:
|
|
110
|
+
default_agent: product_agent # Starting agent for new conversations
|
|
111
|
+
handoffs:
|
|
112
|
+
product_agent: [inventory_agent, comparison_agent]
|
|
113
|
+
inventory_agent: [product_agent]
|
|
114
|
+
comparison_agent: [product_agent, inventory_agent]
|
|
113
115
|
```
|
|
114
116
|
|
|
115
117
|
See [`swarm_pattern.yaml`](./swarm_pattern.yaml) for a complete working example.
|
{dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/hardware_store_swarm.yaml
RENAMED
|
@@ -709,10 +709,6 @@ app:
|
|
|
709
709
|
# - If no specific handoffs defined, agent can hand off to any agent
|
|
710
710
|
# ========================================================================
|
|
711
711
|
swarm:
|
|
712
|
-
# LLM used for swarm coordination and agent decision-making
|
|
713
|
-
# This model powers the underlying swarm orchestration logic
|
|
714
|
-
model: *tool_calling_llm
|
|
715
|
-
|
|
716
712
|
# Starting agent for new conversations - acts as the entry point
|
|
717
713
|
# Users initially interact with this agent before potential handoffs
|
|
718
714
|
default_agent: *general
|
{dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/quick_serve_restaurant.yaml
RENAMED
|
@@ -355,7 +355,7 @@ app:
|
|
|
355
355
|
- *barista
|
|
356
356
|
orchestration: # Agent orchestration configuration
|
|
357
357
|
swarm: # Supervisor orchestration pattern
|
|
358
|
-
|
|
358
|
+
default_agent: *barista # Default agent for routing
|
|
359
359
|
memory: *memory # Memory store for conversation context
|
|
360
360
|
input_example:
|
|
361
361
|
messages:
|
|
@@ -245,7 +245,6 @@ No central supervisor needed — agents decide collaboratively.
|
|
|
245
245
|
```yaml
|
|
246
246
|
orchestration:
|
|
247
247
|
swarm:
|
|
248
|
-
model: *default_llm
|
|
249
248
|
default_agent: *general_agent # Where to start
|
|
250
249
|
handoffs:
|
|
251
250
|
product_agent: [orders_agent, diy_agent] # Product agent can hand off to these
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dao-ai"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.17"
|
|
8
8
|
description = "DAO AI: A modular, multi-agent orchestration framework for complex AI workflows. Supports agent handoff, tool integration, and dynamic configuration via YAML."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -3155,11 +3155,16 @@
|
|
|
3155
3155
|
{
|
|
3156
3156
|
"$ref": "#/$defs/SwarmModel"
|
|
3157
3157
|
},
|
|
3158
|
+
{
|
|
3159
|
+
"const": true,
|
|
3160
|
+
"type": "boolean"
|
|
3161
|
+
},
|
|
3158
3162
|
{
|
|
3159
3163
|
"type": "null"
|
|
3160
3164
|
}
|
|
3161
3165
|
],
|
|
3162
|
-
"default": null
|
|
3166
|
+
"default": null,
|
|
3167
|
+
"title": "Swarm"
|
|
3163
3168
|
},
|
|
3164
3169
|
"memory": {
|
|
3165
3170
|
"anyOf": [
|
|
@@ -4005,9 +4010,6 @@
|
|
|
4005
4010
|
"SwarmModel": {
|
|
4006
4011
|
"additionalProperties": false,
|
|
4007
4012
|
"properties": {
|
|
4008
|
-
"model": {
|
|
4009
|
-
"$ref": "#/$defs/LLMModel"
|
|
4010
|
-
},
|
|
4011
4013
|
"default_agent": {
|
|
4012
4014
|
"anyOf": [
|
|
4013
4015
|
{
|
|
@@ -4063,9 +4065,6 @@
|
|
|
4063
4065
|
"title": "Handoffs"
|
|
4064
4066
|
}
|
|
4065
4067
|
},
|
|
4066
|
-
"required": [
|
|
4067
|
-
"model"
|
|
4068
|
-
],
|
|
4069
4068
|
"title": "SwarmModel",
|
|
4070
4069
|
"type": "object"
|
|
4071
4070
|
},
|
|
@@ -64,6 +64,7 @@ def detect_cloud_provider(profile: Optional[str] = None) -> Optional[str]:
|
|
|
64
64
|
"""
|
|
65
65
|
try:
|
|
66
66
|
import os
|
|
67
|
+
|
|
67
68
|
from databricks.sdk import WorkspaceClient
|
|
68
69
|
|
|
69
70
|
# Check for environment variables that might override profile
|
|
@@ -1208,7 +1209,9 @@ def run_databricks_command(
|
|
|
1208
1209
|
f"Using CLI-specified deployment target: {resolved_deployment_target}"
|
|
1209
1210
|
)
|
|
1210
1211
|
elif app_config and app_config.app and app_config.app.deployment_target:
|
|
1211
|
-
|
|
1212
|
+
# deployment_target is DeploymentTarget enum (str subclass) or string
|
|
1213
|
+
# str() works for both since DeploymentTarget inherits from str
|
|
1214
|
+
resolved_deployment_target = str(app_config.app.deployment_target)
|
|
1212
1215
|
logger.debug(
|
|
1213
1216
|
f"Using config file deployment target: {resolved_deployment_target}"
|
|
1214
1217
|
)
|
|
@@ -373,15 +373,19 @@ class IsDatabricksResource(ABC, BaseModel):
|
|
|
373
373
|
"""
|
|
374
374
|
from dao_ai.utils import normalize_host
|
|
375
375
|
|
|
376
|
-
logger.trace(
|
|
376
|
+
logger.trace(
|
|
377
|
+
"workspace_client_from called",
|
|
378
|
+
context=context,
|
|
379
|
+
on_behalf_of_user=self.on_behalf_of_user,
|
|
380
|
+
)
|
|
377
381
|
|
|
378
382
|
# Check if we have headers in context for OBO
|
|
379
383
|
if context and context.headers and self.on_behalf_of_user:
|
|
380
384
|
headers = context.headers
|
|
381
385
|
# Try both lowercase and title-case header names (HTTP headers are case-insensitive)
|
|
382
|
-
forwarded_token: str = headers.get(
|
|
383
|
-
"
|
|
384
|
-
)
|
|
386
|
+
forwarded_token: str = headers.get(
|
|
387
|
+
"x-forwarded-access-token"
|
|
388
|
+
) or headers.get("X-Forwarded-Access-Token")
|
|
385
389
|
|
|
386
390
|
if forwarded_token:
|
|
387
391
|
forwarded_user = headers.get("x-forwarded-user") or headers.get(
|
|
@@ -2091,9 +2095,47 @@ class McpFunctionModel(BaseFunctionModel, IsDatabricksResource):
|
|
|
2091
2095
|
return f"{workspace_host}/api/2.0/mcp/sql"
|
|
2092
2096
|
|
|
2093
2097
|
# Databricks App - MCP endpoint is at {app_url}/mcp
|
|
2098
|
+
# Try McpFunctionModel's workspace_client first (which may have credentials),
|
|
2099
|
+
# then fall back to DatabricksAppModel.url property (which uses its own workspace_client)
|
|
2094
2100
|
if self.app:
|
|
2095
|
-
|
|
2096
|
-
|
|
2101
|
+
from databricks.sdk.service.apps import App
|
|
2102
|
+
|
|
2103
|
+
app_url: str | None = None
|
|
2104
|
+
|
|
2105
|
+
# First, try using McpFunctionModel's workspace_client
|
|
2106
|
+
try:
|
|
2107
|
+
app: App = self.workspace_client.apps.get(self.app.name)
|
|
2108
|
+
app_url = app.url
|
|
2109
|
+
logger.trace(
|
|
2110
|
+
"Got app URL using McpFunctionModel workspace_client",
|
|
2111
|
+
app_name=self.app.name,
|
|
2112
|
+
url=app_url,
|
|
2113
|
+
)
|
|
2114
|
+
except Exception as e:
|
|
2115
|
+
logger.debug(
|
|
2116
|
+
"Failed to get app URL using McpFunctionModel workspace_client, "
|
|
2117
|
+
"trying DatabricksAppModel.url property",
|
|
2118
|
+
app_name=self.app.name,
|
|
2119
|
+
error=str(e),
|
|
2120
|
+
)
|
|
2121
|
+
|
|
2122
|
+
# Fall back to DatabricksAppModel.url property
|
|
2123
|
+
if not app_url:
|
|
2124
|
+
try:
|
|
2125
|
+
app_url = self.app.url
|
|
2126
|
+
logger.trace(
|
|
2127
|
+
"Got app URL using DatabricksAppModel.url property",
|
|
2128
|
+
app_name=self.app.name,
|
|
2129
|
+
url=app_url,
|
|
2130
|
+
)
|
|
2131
|
+
except Exception as e:
|
|
2132
|
+
raise RuntimeError(
|
|
2133
|
+
f"Databricks App '{self.app.name}' does not have a URL. "
|
|
2134
|
+
"The app may not be deployed yet, or credentials may be invalid. "
|
|
2135
|
+
f"Error: {e}"
|
|
2136
|
+
) from e
|
|
2137
|
+
|
|
2138
|
+
return f"{app_url.rstrip('/')}/mcp"
|
|
2097
2139
|
|
|
2098
2140
|
# Vector Search
|
|
2099
2141
|
if self.vector_search:
|
|
@@ -2608,7 +2650,6 @@ class SupervisorModel(BaseModel):
|
|
|
2608
2650
|
|
|
2609
2651
|
class SwarmModel(BaseModel):
|
|
2610
2652
|
model_config = ConfigDict(use_enum_values=True, extra="forbid")
|
|
2611
|
-
model: LLMModel
|
|
2612
2653
|
default_agent: Optional[AgentModel | str] = None
|
|
2613
2654
|
middleware: list[MiddlewareModel] = Field(
|
|
2614
2655
|
default_factory=list,
|
|
@@ -2622,11 +2663,17 @@ class SwarmModel(BaseModel):
|
|
|
2622
2663
|
class OrchestrationModel(BaseModel):
|
|
2623
2664
|
model_config = ConfigDict(use_enum_values=True, extra="forbid")
|
|
2624
2665
|
supervisor: Optional[SupervisorModel] = None
|
|
2625
|
-
swarm: Optional[SwarmModel] = None
|
|
2666
|
+
swarm: Optional[SwarmModel | Literal[True]] = None
|
|
2626
2667
|
memory: Optional[MemoryModel] = None
|
|
2627
2668
|
|
|
2628
2669
|
@model_validator(mode="after")
|
|
2629
|
-
def
|
|
2670
|
+
def validate_and_normalize(self) -> Self:
|
|
2671
|
+
"""Validate orchestration and normalize swarm shorthand."""
|
|
2672
|
+
# Convert swarm: true to SwarmModel()
|
|
2673
|
+
if self.swarm is True:
|
|
2674
|
+
self.swarm = SwarmModel()
|
|
2675
|
+
|
|
2676
|
+
# Validate mutually exclusive
|
|
2630
2677
|
if self.supervisor is not None and self.swarm is not None:
|
|
2631
2678
|
raise ValueError("Cannot specify both supervisor and swarm")
|
|
2632
2679
|
if self.supervisor is None and self.swarm is None:
|
|
@@ -2898,9 +2945,7 @@ class AppModel(BaseModel):
|
|
|
2898
2945
|
elif len(self.agents) == 1:
|
|
2899
2946
|
default_agent: AgentModel = self.agents[0]
|
|
2900
2947
|
self.orchestration = OrchestrationModel(
|
|
2901
|
-
swarm=SwarmModel(
|
|
2902
|
-
model=default_agent.model, default_agent=default_agent
|
|
2903
|
-
)
|
|
2948
|
+
swarm=SwarmModel(default_agent=default_agent)
|
|
2904
2949
|
)
|
|
2905
2950
|
else:
|
|
2906
2951
|
raise ValueError("At least one agent must be specified")
|
|
@@ -167,8 +167,13 @@ def create_swarm_graph(config: AppConfig) -> CompiledStateGraph:
|
|
|
167
167
|
default_agent: str
|
|
168
168
|
if isinstance(swarm.default_agent, AgentModel):
|
|
169
169
|
default_agent = swarm.default_agent.name
|
|
170
|
-
|
|
170
|
+
elif swarm.default_agent is not None:
|
|
171
171
|
default_agent = swarm.default_agent
|
|
172
|
+
elif len(config.app.agents) > 0:
|
|
173
|
+
# Fallback to first agent if no default specified
|
|
174
|
+
default_agent = config.app.agents[0].name
|
|
175
|
+
else:
|
|
176
|
+
raise ValueError("Swarm requires at least one agent and a default_agent")
|
|
172
177
|
|
|
173
178
|
logger.info(
|
|
174
179
|
"Creating swarm graph",
|
|
@@ -144,31 +144,42 @@ def _should_include_tool(
|
|
|
144
144
|
return True
|
|
145
145
|
|
|
146
146
|
|
|
147
|
+
def _has_auth_configured(resource: IsDatabricksResource) -> bool:
|
|
148
|
+
"""Check if a resource has explicit authentication configured."""
|
|
149
|
+
return bool(
|
|
150
|
+
resource.on_behalf_of_user
|
|
151
|
+
or resource.service_principal
|
|
152
|
+
or resource.client_id
|
|
153
|
+
or resource.pat
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
147
157
|
def _get_auth_resource(function: McpFunctionModel) -> IsDatabricksResource:
|
|
148
158
|
"""
|
|
149
159
|
Get the IsDatabricksResource to use for authentication.
|
|
150
160
|
|
|
151
161
|
Follows a priority hierarchy:
|
|
152
|
-
1.
|
|
162
|
+
1. Nested resource with explicit auth (app, connection, genie_room, vector_search)
|
|
153
163
|
2. McpFunctionModel itself (which also inherits from IsDatabricksResource)
|
|
154
164
|
|
|
165
|
+
Only uses a nested resource if it has authentication configured.
|
|
166
|
+
Otherwise falls back to McpFunctionModel which may have credentials set at the tool level.
|
|
167
|
+
|
|
155
168
|
Returns the resource whose workspace_client should be used for authentication.
|
|
156
169
|
"""
|
|
157
|
-
# Check each possible resource source
|
|
158
|
-
|
|
159
|
-
if function.app:
|
|
170
|
+
# Check each possible resource source - only use if it has auth configured
|
|
171
|
+
if function.app and _has_auth_configured(function.app):
|
|
160
172
|
return function.app
|
|
161
|
-
if function.connection:
|
|
173
|
+
if function.connection and _has_auth_configured(function.connection):
|
|
162
174
|
return function.connection
|
|
163
|
-
if function.genie_room:
|
|
175
|
+
if function.genie_room and _has_auth_configured(function.genie_room):
|
|
164
176
|
return function.genie_room
|
|
165
|
-
if function.vector_search:
|
|
177
|
+
if function.vector_search and _has_auth_configured(function.vector_search):
|
|
166
178
|
return function.vector_search
|
|
167
|
-
|
|
168
|
-
# SchemaModel doesn't have auth - fall through to McpFunctionModel
|
|
169
|
-
pass
|
|
179
|
+
# SchemaModel (functions) doesn't have auth - always fall through
|
|
170
180
|
|
|
171
181
|
# Fall back to McpFunctionModel itself (it inherits from IsDatabricksResource)
|
|
182
|
+
# This allows credentials to be set at the tool level
|
|
172
183
|
return function
|
|
173
184
|
|
|
174
185
|
|
|
@@ -270,9 +270,10 @@ def test_mcp_function_with_databricks_app():
|
|
|
270
270
|
assert mcp_function_model.app.name == "my-mcp-server"
|
|
271
271
|
assert mcp_function_model.url is None # URL is retrieved from app
|
|
272
272
|
|
|
273
|
-
# Verify the mcp_url property returns the app's URL
|
|
273
|
+
# Verify the mcp_url property returns the app's URL with /mcp suffix
|
|
274
274
|
assert (
|
|
275
|
-
mcp_function_model.mcp_url
|
|
275
|
+
mcp_function_model.mcp_url
|
|
276
|
+
== "https://my-mcp-server.cloud.databricks.com/mcp"
|
|
276
277
|
)
|
|
277
278
|
|
|
278
279
|
# Verify the workspace client was called correctly
|
|
@@ -523,7 +523,7 @@ class TestBuildConnectionConfigWithApp:
|
|
|
523
523
|
|
|
524
524
|
@patch("databricks_mcp.DatabricksOAuthClientProvider")
|
|
525
525
|
def test_app_source_uses_oauth_provider(self, mock_provider_class):
|
|
526
|
-
"""Test that app source uses DatabricksOAuthClientProvider with
|
|
526
|
+
"""Test that app source uses DatabricksOAuthClientProvider with function's workspace_client."""
|
|
527
527
|
from unittest.mock import PropertyMock
|
|
528
528
|
|
|
529
529
|
# Create mock app with URL
|
|
@@ -537,25 +537,26 @@ class TestBuildConnectionConfigWithApp:
|
|
|
537
537
|
# Create DatabricksAppModel
|
|
538
538
|
app_model = DatabricksAppModel(name="my-mcp-app")
|
|
539
539
|
|
|
540
|
-
#
|
|
540
|
+
# Create McpFunctionModel with app source
|
|
541
|
+
function = McpFunctionModel(app=app_model)
|
|
542
|
+
|
|
543
|
+
# Mock the workspace_client property on McpFunctionModel
|
|
544
|
+
# (since app has no auth configured, function's workspace_client is used)
|
|
541
545
|
with patch.object(
|
|
542
|
-
type(
|
|
546
|
+
type(function),
|
|
543
547
|
"workspace_client",
|
|
544
548
|
new_callable=PropertyMock,
|
|
545
549
|
return_value=mock_ws,
|
|
546
550
|
):
|
|
547
|
-
# Create McpFunctionModel with app source
|
|
548
|
-
function = McpFunctionModel(app=app_model)
|
|
549
|
-
|
|
550
551
|
# Build connection config
|
|
551
552
|
config = _build_connection_config(function)
|
|
552
553
|
|
|
553
|
-
# Verify structure
|
|
554
|
-
assert config["url"] == "https://my-mcp-app.cloud.databricks.com"
|
|
554
|
+
# Verify structure - app URLs get /mcp suffix
|
|
555
|
+
assert config["url"] == "https://my-mcp-app.cloud.databricks.com/mcp"
|
|
555
556
|
assert config["transport"] == "http"
|
|
556
557
|
assert "auth" in config
|
|
557
558
|
|
|
558
|
-
# Verify OAuth provider was called with
|
|
559
|
+
# Verify OAuth provider was called with function's workspace client
|
|
559
560
|
mock_provider_class.assert_called_once_with(mock_ws)
|
|
560
561
|
|
|
561
562
|
@patch("databricks_mcp.DatabricksOAuthClientProvider")
|
|
@@ -585,9 +586,9 @@ class TestBuildConnectionConfigWithApp:
|
|
|
585
586
|
function = McpFunctionModel(app=app_model)
|
|
586
587
|
config = _build_connection_config(function)
|
|
587
588
|
|
|
588
|
-
# Verify complete config structure
|
|
589
|
+
# Verify complete config structure - app URLs get /mcp suffix
|
|
589
590
|
assert config == {
|
|
590
|
-
"url": "https://test-app.azuredatabricks.net",
|
|
591
|
+
"url": "https://test-app.azuredatabricks.net/mcp",
|
|
591
592
|
"transport": "http",
|
|
592
593
|
"auth": mock_auth,
|
|
593
594
|
}
|
|
@@ -734,7 +735,7 @@ class TestBuildConnectionConfigUnifiedAuth:
|
|
|
734
735
|
|
|
735
736
|
@patch("databricks_mcp.DatabricksOAuthClientProvider")
|
|
736
737
|
def test_genie_room_uses_own_workspace_client(self, mock_provider_class):
|
|
737
|
-
"""Test that genie_room source uses its own workspace_client for auth."""
|
|
738
|
+
"""Test that genie_room source uses its own workspace_client for auth when auth is configured."""
|
|
738
739
|
from unittest.mock import PropertyMock
|
|
739
740
|
|
|
740
741
|
from dao_ai.config import GenieRoomModel
|
|
@@ -745,7 +746,10 @@ class TestBuildConnectionConfigUnifiedAuth:
|
|
|
745
746
|
# Create mock workspace client for genie room
|
|
746
747
|
mock_ws = Mock()
|
|
747
748
|
|
|
748
|
-
|
|
749
|
+
# Genie room must have auth configured to take priority
|
|
750
|
+
genie_room = GenieRoomModel(
|
|
751
|
+
name="test-genie", space_id="space_123", on_behalf_of_user=True
|
|
752
|
+
)
|
|
749
753
|
|
|
750
754
|
# Mock the workspace_client property
|
|
751
755
|
with patch.object(
|
|
@@ -766,9 +770,12 @@ class TestBuildConnectionConfigUnifiedAuth:
|
|
|
766
770
|
assert config["transport"] == "http"
|
|
767
771
|
assert config["auth"] == mock_auth
|
|
768
772
|
|
|
773
|
+
@patch("dao_ai.providers.databricks.VectorSearchClient")
|
|
769
774
|
@patch("databricks_mcp.DatabricksOAuthClientProvider")
|
|
770
|
-
def test_vector_search_uses_own_workspace_client(
|
|
771
|
-
|
|
775
|
+
def test_vector_search_uses_own_workspace_client(
|
|
776
|
+
self, mock_provider_class, mock_vsc_class
|
|
777
|
+
):
|
|
778
|
+
"""Test that vector_search source uses its own workspace_client for auth when auth is configured."""
|
|
772
779
|
from unittest.mock import PropertyMock
|
|
773
780
|
|
|
774
781
|
from dao_ai.config import IndexModel, SchemaModel, TableModel, VectorStoreModel
|
|
@@ -783,11 +790,13 @@ class TestBuildConnectionConfigUnifiedAuth:
|
|
|
783
790
|
table = TableModel(schema=schema, name="table")
|
|
784
791
|
index = IndexModel(schema=schema, name="index")
|
|
785
792
|
|
|
793
|
+
# Vector search must have auth configured to take priority
|
|
786
794
|
vector_search = VectorStoreModel(
|
|
787
795
|
source_table=table,
|
|
788
796
|
embedding_source_column="text",
|
|
789
797
|
index=index,
|
|
790
798
|
primary_key="id",
|
|
799
|
+
on_behalf_of_user=True,
|
|
791
800
|
)
|
|
792
801
|
|
|
793
802
|
# Mock the workspace_client property
|
|
@@ -902,7 +911,7 @@ class TestBuildConnectionConfigUnifiedAuth:
|
|
|
902
911
|
|
|
903
912
|
@patch("databricks_mcp.DatabricksOAuthClientProvider")
|
|
904
913
|
def test_connection_has_priority_over_mcpfunction_auth(self, mock_provider_class):
|
|
905
|
-
"""Test that connection's workspace_client takes priority over McpFunctionModel's."""
|
|
914
|
+
"""Test that connection's workspace_client takes priority over McpFunctionModel's when connection has auth."""
|
|
906
915
|
from unittest.mock import PropertyMock
|
|
907
916
|
|
|
908
917
|
mock_auth = Mock()
|
|
@@ -914,7 +923,8 @@ class TestBuildConnectionConfigUnifiedAuth:
|
|
|
914
923
|
connection_ws = Mock(name="connection_ws")
|
|
915
924
|
function_ws = Mock(name="function_ws")
|
|
916
925
|
|
|
917
|
-
|
|
926
|
+
# Connection must have auth configured to take priority
|
|
927
|
+
connection = ConnectionModel(name="test-connection", on_behalf_of_user=True)
|
|
918
928
|
function = McpFunctionModel(connection=connection)
|
|
919
929
|
|
|
920
930
|
# Mock both workspace_client properties
|
|
@@ -937,7 +947,7 @@ class TestBuildConnectionConfigUnifiedAuth:
|
|
|
937
947
|
|
|
938
948
|
@patch("databricks_mcp.DatabricksOAuthClientProvider")
|
|
939
949
|
def test_app_has_priority_over_mcpfunction_auth(self, mock_provider_class):
|
|
940
|
-
"""Test that app's workspace_client takes priority over McpFunctionModel's."""
|
|
950
|
+
"""Test that app's workspace_client takes priority over McpFunctionModel's when app has auth."""
|
|
941
951
|
from unittest.mock import PropertyMock
|
|
942
952
|
|
|
943
953
|
mock_auth = Mock()
|
|
@@ -952,7 +962,8 @@ class TestBuildConnectionConfigUnifiedAuth:
|
|
|
952
962
|
mock_app_instance.url = "https://my-app.databricks.com"
|
|
953
963
|
app_ws.apps.get.return_value = mock_app_instance
|
|
954
964
|
|
|
955
|
-
|
|
965
|
+
# App must have auth configured to take priority
|
|
966
|
+
app = DatabricksAppModel(name="my-app", on_behalf_of_user=True)
|
|
956
967
|
function = McpFunctionModel(app=app)
|
|
957
968
|
|
|
958
969
|
# Mock both workspace_client properties
|