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.
Files changed (305) hide show
  1. {dao_ai-0.1.16 → dao_ai-0.1.17}/PKG-INFO +2 -2
  2. {dao_ai-0.1.16 → dao_ai-0.1.17}/README.md +1 -1
  3. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/custom_mcp.yaml +1 -1
  4. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/filtered_mcp.yaml +1 -2
  5. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/managed_mcp.yaml +1 -1
  6. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/slack_integration.yaml +1 -1
  7. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/genie_lru_cache.yaml +1 -1
  8. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/genie_semantic_cache.yaml +1 -1
  9. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/genie_with_conversation_id.yaml +1 -1
  10. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/conversation_summarization.yaml +1 -1
  11. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/07_human_in_the_loop/human_in_the_loop.yaml +1 -1
  12. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/11_prompt_engineering/prompt_optimization.yaml +0 -1
  13. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/11_prompt_engineering/prompt_registry.yaml +0 -1
  14. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/13_orchestration/README.md +7 -5
  15. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/deep_research.yaml +0 -1
  16. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/hardware_store_swarm.yaml +0 -4
  17. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/quick_serve_restaurant.yaml +1 -1
  18. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/architecture.md +0 -1
  19. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/configuration-reference.md +0 -1
  20. {dao_ai-0.1.16 → dao_ai-0.1.17}/pyproject.toml +1 -1
  21. {dao_ai-0.1.16 → dao_ai-0.1.17}/schemas/model_config_schema.json +6 -7
  22. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/cli.py +4 -1
  23. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/config.py +57 -12
  24. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/orchestration/swarm.py +6 -1
  25. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/mcp.py +21 -10
  26. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_mcp.py +3 -2
  27. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_mcp_filtering_integration.py +30 -19
  28. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_mcp_function_model.py +23 -19
  29. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_swarm_middleware.py +0 -8
  30. dao_ai-0.1.17/tests/test_mcp_app_auth.py +114 -0
  31. {dao_ai-0.1.16 → dao_ai-0.1.17}/.gitignore +0 -0
  32. {dao_ai-0.1.16 → dao_ai-0.1.17}/.python-version +0 -0
  33. {dao_ai-0.1.16 → dao_ai-0.1.17}/CHANGELOG.md +0 -0
  34. {dao_ai-0.1.16 → dao_ai-0.1.17}/CONTRIBUTING.md +0 -0
  35. {dao_ai-0.1.16 → dao_ai-0.1.17}/LICENSE +0 -0
  36. {dao_ai-0.1.16 → dao_ai-0.1.17}/Makefile +0 -0
  37. {dao_ai-0.1.16 → dao_ai-0.1.17}/app.yaml +0 -0
  38. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/01_getting_started/README.md +0 -0
  39. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/01_getting_started/minimal.yaml +0 -0
  40. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/README.md +0 -0
  41. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/02_mcp/external_mcp.yaml +0 -0
  42. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/03_reranking/README.md +0 -0
  43. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/03_reranking/vector_search_with_reranking.yaml +0 -0
  44. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/README.md +0 -0
  45. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/04_genie/genie_basic.yaml +0 -0
  46. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/README.md +0 -0
  47. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/in_memory_basic.yaml +0 -0
  48. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/lakebase_persistence.yaml +0 -0
  49. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/05_memory/postgres_persistence.yaml +0 -0
  50. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/06_on_behalf_of_user/README.md +0 -0
  51. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/06_on_behalf_of_user/obo_basic.yaml +0 -0
  52. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/07_human_in_the_loop/README.md +0 -0
  53. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/08_guardrails/README.md +0 -0
  54. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/08_guardrails/guardrails_basic.yaml +0 -0
  55. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/09_structured_output/README.md +0 -0
  56. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/09_structured_output/structured_output.yaml +0 -0
  57. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/10_agent_integrations/README.md +0 -0
  58. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/10_agent_integrations/agent_bricks.yaml +0 -0
  59. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/10_agent_integrations/kasal.yaml +0 -0
  60. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/11_prompt_engineering/README.md +0 -0
  61. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/README.md +0 -0
  62. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/combined_middleware.yaml +0 -0
  63. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/context_management.yaml +0 -0
  64. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/custom_field_validation.yaml +0 -0
  65. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/limit_middleware.yaml +0 -0
  66. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/logging_middleware.yaml +0 -0
  67. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/pii_middleware.yaml +0 -0
  68. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/retry_middleware.yaml +0 -0
  69. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/12_middleware/tool_selector_middleware.yaml +0 -0
  70. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/13_orchestration/supervisor_pattern.yaml +0 -0
  71. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/13_orchestration/swarm_pattern.yaml +0 -0
  72. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/14_basic_tools/README.md +0 -0
  73. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/14_basic_tools/sql_tool_example.yaml +0 -0
  74. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/README.md +0 -0
  75. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/brick_store.yaml +0 -0
  76. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/executive_assistant.yaml +0 -0
  77. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/genie_and_genie_mcp.yaml +0 -0
  78. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/genie_vector_search_hybrid.yaml +0 -0
  79. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/hardware_store.yaml +0 -0
  80. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/hardware_store_lakebase.yaml +0 -0
  81. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/15_complete_applications/reservations_system.yaml +0 -0
  82. {dao_ai-0.1.16 → dao_ai-0.1.17}/config/examples/README.md +0 -0
  83. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/appointments.sql +0 -0
  84. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/appointments_data.sql +0 -0
  85. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/brand_rep_demo_data.sql +0 -0
  86. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/brand_rep_demo_queries.sql +0 -0
  87. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/brand_rep_demo_tables.sql +0 -0
  88. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/brand_rep_demo_validation.sql +0 -0
  89. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/customers.sql +0 -0
  90. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/customers_data.sql +0 -0
  91. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/dim_stores.sql +0 -0
  92. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/dim_stores_data.sql +0 -0
  93. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/employee_performance.sql +0 -0
  94. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/employee_performance_data.sql +0 -0
  95. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/employee_tasks.sql +0 -0
  96. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/employee_tasks_data.sql +0 -0
  97. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/inventory.sql +0 -0
  98. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/inventory_data.sql +0 -0
  99. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/managers.sql +0 -0
  100. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/managers_data.sql +0 -0
  101. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/product_data.sql +0 -0
  102. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/products.sql +0 -0
  103. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/dais2025/task_assignments.sql +0 -0
  104. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/hardware_store/inventory.snappy.parquet +0 -0
  105. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/hardware_store/inventory.sql +0 -0
  106. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/hardware_store/products.snappy.parquet +0 -0
  107. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/hardware_store/products.sql +0 -0
  108. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/.gitkeep +0 -0
  109. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/fulfil_item_orders.sql +0 -0
  110. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/items_description.csv +0 -0
  111. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/items_description.sql +0 -0
  112. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/items_raw.csv +0 -0
  113. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/items_raw.sql +0 -0
  114. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/orders_raw.csv +0 -0
  115. {dao_ai-0.1.16 → dao_ai-0.1.17}/data/quick_serve_restaurant/orders_raw.sql +0 -0
  116. {dao_ai-0.1.16 → dao_ai-0.1.17}/databricks.yaml.template +0 -0
  117. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/cli-reference.md +0 -0
  118. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/contributing.md +0 -0
  119. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/examples.md +0 -0
  120. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/faq.md +0 -0
  121. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/hardware_store/README.md +0 -0
  122. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/hardware_store/retail_supervisor.png +0 -0
  123. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/hardware_store/retail_swarm.png +0 -0
  124. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/images/genie.png +0 -0
  125. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/key-capabilities.md +0 -0
  126. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/python-api.md +0 -0
  127. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/quick_serve_restaurant/.gitkeep +0 -0
  128. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/quick_serve_restaurant/quick-serve-restaurant.png +0 -0
  129. {dao_ai-0.1.16 → dao_ai-0.1.17}/docs/why-dao.md +0 -0
  130. {dao_ai-0.1.16 → dao_ai-0.1.17}/environment.yaml +0 -0
  131. {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/dais2025/examples.yaml +0 -0
  132. {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/deep_research/examples.yaml +0 -0
  133. {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/executive_assistant/examples.yaml +0 -0
  134. {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/hardware_store/examples.yaml +0 -0
  135. {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/quick_serve_restaurant/.gitkeep +0 -0
  136. {dao_ai-0.1.16 → dao_ai-0.1.17}/examples/quick_serve_restaurant/examples.yaml +0 -0
  137. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/extract_store_numbers.sql +0 -0
  138. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_inventory_by_sku.sql +0 -0
  139. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_inventory_by_upc.sql +0 -0
  140. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_product_by_sku.sql +0 -0
  141. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_product_by_upc.sql +0 -0
  142. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_store_by_number.sql +0 -0
  143. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_store_inventory_by_sku.sql +0 -0
  144. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/dais2025/find_store_inventory_by_upc.sql +0 -0
  145. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_inventory_by_sku.sql +0 -0
  146. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_inventory_by_upc.sql +0 -0
  147. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_product_by_sku.sql +0 -0
  148. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_product_by_upc.sql +0 -0
  149. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_store_inventory_by_sku.sql +0 -0
  150. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/hardware_store/find_store_inventory_by_upc.sql +0 -0
  151. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/.gitkeep +0 -0
  152. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/insert_coffee_order.sql +0 -0
  153. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/lookup_items_by_descriptions.sql +0 -0
  154. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/match_historical_item_order_by_date.sql +0 -0
  155. {dao_ai-0.1.16 → dao_ai-0.1.17}/functions/quick_serve_restaurant/match_item_by_description_and_price.sql +0 -0
  156. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/01_ingest_and_transform.py +0 -0
  157. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/02_provision_vector_search.py +0 -0
  158. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/03_provision_lakebase.py +0 -0
  159. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/04_unity_catalog_tools.py +0 -0
  160. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/05_deploy_agent.py +0 -0
  161. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/06_generate_evaluation_data.py +0 -0
  162. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/07_run_evaluation.py +0 -0
  163. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/08_run_examples.py +0 -0
  164. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/09_evaluate_inferences.py +0 -0
  165. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/10_optimize_prompts.py +0 -0
  166. {dao_ai-0.1.16 → dao_ai-0.1.17}/notebooks/99_scratchpad.py +0 -0
  167. {dao_ai-0.1.16 → dao_ai-0.1.17}/requirements.txt +0 -0
  168. {dao_ai-0.1.16 → dao_ai-0.1.17}/schemas/bundle_config_schema.json +0 -0
  169. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/__init__.py +0 -0
  170. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/models.py +0 -0
  171. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/__init__.py +0 -0
  172. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/customer.py +0 -0
  173. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/employee.py +0 -0
  174. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/executive.py +0 -0
  175. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/genie.py +0 -0
  176. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/inventory.py +0 -0
  177. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/models.py +0 -0
  178. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dais2025/tools/store.py +0 -0
  179. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/__init__.py +0 -0
  180. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/__init__.py +0 -0
  181. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/handlers.py +0 -0
  182. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/model_serving.py +0 -0
  183. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/resources.py +0 -0
  184. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/apps/server.py +0 -0
  185. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/catalog.py +0 -0
  186. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/__init__.py +0 -0
  187. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/__init__.py +0 -0
  188. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/base.py +0 -0
  189. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/core.py +0 -0
  190. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/lru.py +0 -0
  191. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/cache/semantic.py +0 -0
  192. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/genie/core.py +0 -0
  193. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/graph.py +0 -0
  194. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/hooks/__init__.py +0 -0
  195. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/hooks/core.py +0 -0
  196. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/logging.py +0 -0
  197. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/__init__.py +0 -0
  198. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/base.py +0 -0
  199. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/core.py +0 -0
  200. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/databricks.py +0 -0
  201. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/memory/postgres.py +0 -0
  202. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/messages.py +0 -0
  203. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/__init__.py +0 -0
  204. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/assertions.py +0 -0
  205. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/base.py +0 -0
  206. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/context_editing.py +0 -0
  207. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/core.py +0 -0
  208. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/guardrails.py +0 -0
  209. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/human_in_the_loop.py +0 -0
  210. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/message_validation.py +0 -0
  211. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/model_call_limit.py +0 -0
  212. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/model_retry.py +0 -0
  213. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/pii.py +0 -0
  214. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/summarization.py +0 -0
  215. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/tool_call_limit.py +0 -0
  216. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/tool_retry.py +0 -0
  217. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/middleware/tool_selector.py +0 -0
  218. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/models.py +0 -0
  219. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/nodes.py +0 -0
  220. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/optimization.py +0 -0
  221. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/orchestration/__init__.py +0 -0
  222. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/orchestration/core.py +0 -0
  223. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/orchestration/supervisor.py +0 -0
  224. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/prompts.py +0 -0
  225. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/providers/__init__.py +0 -0
  226. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/providers/base.py +0 -0
  227. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/providers/databricks.py +0 -0
  228. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/state.py +0 -0
  229. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/__init__.py +0 -0
  230. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/agent.py +0 -0
  231. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/core.py +0 -0
  232. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/email.py +0 -0
  233. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/genie.py +0 -0
  234. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/memory.py +0 -0
  235. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/python.py +0 -0
  236. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/search.py +0 -0
  237. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/slack.py +0 -0
  238. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/sql.py +0 -0
  239. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/time.py +0 -0
  240. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/unity_catalog.py +0 -0
  241. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/tools/vector_search.py +0 -0
  242. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/types.py +0 -0
  243. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/utils.py +0 -0
  244. {dao_ai-0.1.16 → dao_ai-0.1.17}/src/dao_ai/vector_search.py +0 -0
  245. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/config/test_model_config.yaml +0 -0
  246. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/conftest.py +0 -0
  247. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_context_editing.py +0 -0
  248. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_model_call_limit.py +0 -0
  249. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_model_retry.py +0 -0
  250. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_pii.py +0 -0
  251. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_tool_call_limit.py +0 -0
  252. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_tool_retry.py +0 -0
  253. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/middleware/test_tool_selector.py +0 -0
  254. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_agent_response_format.py +0 -0
  255. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_assertions_middleware.py +0 -0
  256. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_catalog.py +0 -0
  257. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_chat_history.py +0 -0
  258. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_config.py +0 -0
  259. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_databricks.py +0 -0
  260. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_function_parsing.py +0 -0
  261. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_genie.py +0 -0
  262. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_genie_conversation_ids_in_outputs.py +0 -0
  263. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_genie_databricks_integration.py +0 -0
  264. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_genie_room_model.py +0 -0
  265. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_guardrail_retry.py +0 -0
  266. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_hitl_config_model.py +0 -0
  267. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_hitl_responses_agent.py +0 -0
  268. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_hooks.py +0 -0
  269. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_human_in_the_loop.py +0 -0
  270. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_inference.py +0 -0
  271. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_inference_integration.py +0 -0
  272. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_input_output_structure.py +0 -0
  273. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_interrupt_type.py +0 -0
  274. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_llm_interrupt_handling.py +0 -0
  275. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_mcp_filtering.py +0 -0
  276. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_message_validation_middleware.py +0 -0
  277. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_messages.py +0 -0
  278. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_models.py +0 -0
  279. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_optimization.py +0 -0
  280. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_postgres_integration.py +0 -0
  281. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_prompt_optimizations.py +0 -0
  282. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_prompts.py +0 -0
  283. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_reranking.py +0 -0
  284. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_reranking_integration.py +0 -0
  285. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_resources_model_genie_integration.py +0 -0
  286. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_response_format.py +0 -0
  287. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_responses_agent_structured_output_unit.py +0 -0
  288. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_semantic_cache_context.py +0 -0
  289. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_sql_tool.py +0 -0
  290. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_sql_tool_integration.py +0 -0
  291. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_state.py +0 -0
  292. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_summarization_inference.py +0 -0
  293. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_tools.py +0 -0
  294. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_types.py +0 -0
  295. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_unity_catalog.py +0 -0
  296. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_utils.py +0 -0
  297. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_utils_type_from_fqn.py +0 -0
  298. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_vector_search.py +0 -0
  299. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/test_warehouse_model.py +0 -0
  300. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/dao_ai/weather_server_mcp.py +0 -0
  301. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/hardware_store/.gitkeep +0 -0
  302. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/hardware_store/test_graph.py +0 -0
  303. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/images/doritos_upc.png +0 -0
  304. {dao_ai-0.1.16 → dao_ai-0.1.17}/tests/images/lays_upc.png +0 -0
  305. {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.16
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
- model: *default_llm
238
+ default_agent: *assistant
239
239
  ```
240
240
 
241
241
  **💡 What's happening here?**
@@ -156,7 +156,7 @@ app:
156
156
  - *assistant
157
157
  orchestration:
158
158
  swarm:
159
- model: *default_llm
159
+ default_agent: *assistant
160
160
  ```
161
161
 
162
162
  **💡 What's happening here?**
@@ -55,4 +55,4 @@ app:
55
55
  - *jira_agent # MCP agent
56
56
  orchestration: # Agent orchestration configuration
57
57
  swarm: # Supervisor orchestration pattern
58
- model: *default_llm # LLM for routing decisions
58
+ default_agent: *jira_agent # Default agent for routing
@@ -309,8 +309,7 @@ app:
309
309
  - *functions_agent # Functions agent
310
310
  orchestration: # Agent orchestration configuration
311
311
  swarm: # Supervisor orchestration pattern
312
- model: *default_llm # LLM for routing decisions
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
@@ -120,4 +120,4 @@ app:
120
120
  - *mcp_agent # MCP agent
121
121
  orchestration: # Agent orchestration configuration
122
122
  swarm: # Supervisor orchestration pattern
123
- model: *default_llm # LLM for routing decisions
123
+ default_agent: *mcp_agent # Default agent for routing
@@ -65,5 +65,5 @@ app:
65
65
  - *slack_agent # Slack notification agent
66
66
  orchestration: # Agent orchestration configuration
67
67
  swarm: # Swarm orchestration pattern
68
- model: *default_llm # LLM for routing decisions
68
+ default_agent: *slack_agent # Default agent for routing
69
69
 
@@ -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
- model: *default_llm # LLM for routing decisions
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
- model: *default_llm # LLM for routing decisions
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
- model: *default_llm # LLM for routing decisions
135
+ default_agent: *genie # Default agent for routing
136
136
 
137
137
 
138
138
 
@@ -135,7 +135,7 @@ app:
135
135
  orchestration:
136
136
  memory: *memory
137
137
  swarm:
138
- model: *default_llm
138
+ default_agent: *main_agent
139
139
 
140
140
  # ---------------------------------------------------------------------------
141
141
  # CHAT HISTORY / SUMMARIZATION CONFIGURATION
@@ -165,7 +165,7 @@ app:
165
165
 
166
166
  orchestration:
167
167
  swarm:
168
- model: *default_llm
168
+ default_agent: *main_agent
169
169
 
170
170
  memory: *memory # CRITICAL: Memory with checkpointer required for HITL
171
171
 
@@ -237,7 +237,6 @@ app:
237
237
  user_id: my_user_id
238
238
  store_num: 87887
239
239
  # swarm:
240
- # model: *tool_calling_llm
241
240
  # default_agent: *general
242
241
 
243
242
 
@@ -837,7 +837,6 @@ app:
837
837
  store_num: 87887
838
838
  session: {}
839
839
  # swarm:
840
- # model: *tool_calling_llm
841
840
  # default_agent: *general
842
841
 
843
842
  # =============================================================================
@@ -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
- tools:
109
- transfer_to_inventory:
110
- function: dao_ai.tools.agent.create_handoff_tool
111
- args:
112
- agent_name: inventory_agent
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.
@@ -388,7 +388,6 @@ app:
388
388
  - *strategy_synthesizer
389
389
  orchestration:
390
390
  swarm:
391
- model: *default_llm
392
391
  default_agent: research_lead
393
392
  handoffs:
394
393
  research_lead:
@@ -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
@@ -355,7 +355,7 @@ app:
355
355
  - *barista
356
356
  orchestration: # Agent orchestration configuration
357
357
  swarm: # Supervisor orchestration pattern
358
- model: *tool_calling_llm # LLM for routing decisions
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
@@ -152,7 +152,6 @@ app:
152
152
  model: *model_name
153
153
  prompt: string
154
154
  swarm:
155
- model: *model_name
156
155
  default_agent: *agent_name
157
156
  handoffs:
158
157
  agent_a: [agent_b, agent_c]
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dao-ai"
7
- version = "0.1.16"
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
- resolved_deployment_target = app_config.app.deployment_target.value
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(f"workspace_client_from called", context=context, on_behalf_of_user=self.on_behalf_of_user)
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("x-forwarded-access-token") or headers.get(
383
- "X-Forwarded-Access-Token"
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
- app_url = self.app.url.rstrip("/")
2096
- return f"{app_url}/mcp"
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 validate_mutually_exclusive(self) -> Self:
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
- else:
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. Explicit resource with auth (app, connection, genie_room, vector_search, functions)
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 in priority order
158
- # These resources may have their own auth configured
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
- if function.functions:
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 == "https://my-mcp-server.cloud.databricks.com"
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 app's workspace_client."""
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
- # Mock the workspace_client property
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(app_model),
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 app's workspace client
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
- genie_room = GenieRoomModel(name="test-genie", space_id="space_123")
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(self, mock_provider_class):
771
- """Test that vector_search source uses its own workspace_client for auth."""
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
- connection = ConnectionModel(name="test-connection")
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
- app = DatabricksAppModel(name="my-app")
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