dao-ai 0.1.10__tar.gz → 0.1.12__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.10 → dao_ai-0.1.12}/PKG-INFO +2 -2
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/07_human_in_the_loop/human_in_the_loop.yaml +14 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/pyproject.toml +2 -2
- {dao_ai-0.1.10 → dao_ai-0.1.12}/requirements.txt +1 -1
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/apps/handlers.py +1 -1
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/apps/resources.py +105 -12
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/apps/server.py +2 -2
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/providers/databricks.py +85 -21
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_databricks.py +34 -22
- {dao_ai-0.1.10 → dao_ai-0.1.12}/.gitignore +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/.python-version +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/CHANGELOG.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/CONTRIBUTING.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/LICENSE +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/Makefile +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/app.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/01_getting_started/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/01_getting_started/minimal.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/02_mcp/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/02_mcp/custom_mcp.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/02_mcp/external_mcp.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/02_mcp/filtered_mcp.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/02_mcp/managed_mcp.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/02_mcp/slack_integration.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/03_reranking/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/03_reranking/vector_search_with_reranking.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/04_genie/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/04_genie/genie_basic.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/04_genie/genie_lru_cache.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/04_genie/genie_semantic_cache.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/04_genie/genie_with_conversation_id.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/05_memory/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/05_memory/conversation_summarization.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/05_memory/in_memory_basic.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/05_memory/lakebase_persistence.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/05_memory/postgres_persistence.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/06_on_behalf_of_user/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/06_on_behalf_of_user/obo_basic.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/07_human_in_the_loop/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/08_guardrails/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/08_guardrails/guardrails_basic.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/09_structured_output/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/09_structured_output/structured_output.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/10_agent_integrations/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/10_agent_integrations/agent_bricks.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/10_agent_integrations/kasal.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/11_prompt_engineering/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/11_prompt_engineering/prompt_optimization.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/11_prompt_engineering/prompt_registry.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/combined_middleware.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/context_management.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/custom_field_validation.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/limit_middleware.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/logging_middleware.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/pii_middleware.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/retry_middleware.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/12_middleware/tool_selector_middleware.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/13_orchestration/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/13_orchestration/supervisor_pattern.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/13_orchestration/swarm_pattern.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/14_basic_tools/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/14_basic_tools/sql_tool_example.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/brick_store.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/deep_research.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/executive_assistant.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/genie_and_genie_mcp.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/genie_vector_search_hybrid.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/hardware_store.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/hardware_store_lakebase.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/hardware_store_swarm.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/quick_serve_restaurant.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/15_complete_applications/reservations_system.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/appointments.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/appointments_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/brand_rep_demo_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/brand_rep_demo_queries.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/brand_rep_demo_tables.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/brand_rep_demo_validation.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/customers.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/customers_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/dim_stores.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/dim_stores_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/employee_performance.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/employee_performance_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/employee_tasks.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/employee_tasks_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/inventory.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/inventory_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/managers.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/managers_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/product_data.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/products.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/dais2025/task_assignments.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/hardware_store/inventory.snappy.parquet +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/hardware_store/inventory.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/hardware_store/products.snappy.parquet +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/hardware_store/products.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/quick_serve_restaurant/.gitkeep +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/quick_serve_restaurant/fulfil_item_orders.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/quick_serve_restaurant/items_description.csv +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/quick_serve_restaurant/items_description.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/quick_serve_restaurant/items_raw.csv +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/quick_serve_restaurant/items_raw.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/quick_serve_restaurant/orders_raw.csv +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/data/quick_serve_restaurant/orders_raw.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/databricks.yaml.template +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/architecture.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/cli-reference.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/configuration-reference.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/contributing.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/examples.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/faq.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/hardware_store/README.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/hardware_store/retail_supervisor.png +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/hardware_store/retail_swarm.png +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/images/genie.png +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/key-capabilities.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/python-api.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/quick_serve_restaurant/.gitkeep +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/quick_serve_restaurant/quick-serve-restaurant.png +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/docs/why-dao.md +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/environment.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/examples/dais2025/examples.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/examples/deep_research/examples.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/examples/executive_assistant/examples.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/examples/hardware_store/examples.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/examples/quick_serve_restaurant/.gitkeep +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/examples/quick_serve_restaurant/examples.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/dais2025/extract_store_numbers.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/dais2025/find_inventory_by_sku.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/dais2025/find_inventory_by_upc.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/dais2025/find_product_by_sku.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/dais2025/find_product_by_upc.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/dais2025/find_store_by_number.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/dais2025/find_store_inventory_by_sku.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/dais2025/find_store_inventory_by_upc.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/hardware_store/find_inventory_by_sku.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/hardware_store/find_inventory_by_upc.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/hardware_store/find_product_by_sku.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/hardware_store/find_product_by_upc.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/hardware_store/find_store_inventory_by_sku.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/hardware_store/find_store_inventory_by_upc.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/quick_serve_restaurant/.gitkeep +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/quick_serve_restaurant/insert_coffee_order.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/quick_serve_restaurant/lookup_items_by_descriptions.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/quick_serve_restaurant/match_historical_item_order_by_date.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/functions/quick_serve_restaurant/match_item_by_description_and_price.sql +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/01_ingest_and_transform.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/02_provision_vector_search.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/03_provision_lakebase.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/04_unity_catalog_tools.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/05_deploy_agent.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/06_generate_evaluation_data.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/07_run_evaluation.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/08_run_examples.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/09_evaluate_inferences.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/10_optimize_prompts.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/notebooks/99_scratchpad.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/schemas/bundle_config_schema.json +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/schemas/model_config_schema.json +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/models.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/tools/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/tools/customer.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/tools/employee.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/tools/executive.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/tools/genie.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/tools/inventory.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/tools/models.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dais2025/tools/store.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/apps/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/apps/model_serving.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/catalog.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/cli.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/config.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/genie/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/genie/cache/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/genie/cache/base.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/genie/cache/core.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/genie/cache/lru.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/genie/cache/semantic.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/genie/core.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/graph.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/hooks/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/hooks/core.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/logging.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/memory/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/memory/base.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/memory/core.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/memory/databricks.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/memory/postgres.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/messages.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/assertions.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/base.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/context_editing.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/core.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/guardrails.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/human_in_the_loop.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/message_validation.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/model_call_limit.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/model_retry.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/pii.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/summarization.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/tool_call_limit.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/tool_retry.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/middleware/tool_selector.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/models.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/nodes.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/optimization.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/orchestration/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/orchestration/core.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/orchestration/supervisor.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/orchestration/swarm.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/prompts.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/providers/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/providers/base.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/state.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/__init__.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/agent.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/core.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/email.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/genie.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/mcp.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/memory.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/python.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/search.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/slack.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/sql.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/time.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/unity_catalog.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/tools/vector_search.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/types.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/utils.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/src/dao_ai/vector_search.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/config/test_model_config.yaml +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/conftest.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/middleware/test_context_editing.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/middleware/test_model_call_limit.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/middleware/test_model_retry.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/middleware/test_pii.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/middleware/test_tool_call_limit.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/middleware/test_tool_retry.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/middleware/test_tool_selector.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_agent_response_format.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_assertions_middleware.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_catalog.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_chat_history.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_config.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_function_parsing.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_genie.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_genie_conversation_ids_in_outputs.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_genie_databricks_integration.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_genie_room_model.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_guardrail_retry.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_hitl_config_model.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_hitl_responses_agent.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_hooks.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_human_in_the_loop.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_inference.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_inference_integration.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_input_output_structure.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_interrupt_type.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_llm_interrupt_handling.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_mcp.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_mcp_filtering.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_mcp_filtering_integration.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_mcp_function_model.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_message_validation_middleware.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_messages.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_models.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_optimization.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_postgres_integration.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_prompt_optimizations.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_prompts.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_reranking.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_reranking_integration.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_resources_model_genie_integration.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_response_format.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_responses_agent_structured_output_unit.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_semantic_cache_context.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_sql_tool.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_sql_tool_integration.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_state.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_summarization_inference.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_swarm_middleware.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_tools.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_types.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_unity_catalog.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_utils.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_utils_type_from_fqn.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_vector_search.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/test_warehouse_model.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/dao_ai/weather_server_mcp.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/hardware_store/.gitkeep +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/hardware_store/test_graph.py +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/images/doritos_upc.png +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/tests/images/lays_upc.png +0 -0
- {dao_ai-0.1.10 → dao_ai-0.1.12}/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.12
|
|
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
|
|
@@ -28,7 +28,7 @@ Requires-Python: >=3.11
|
|
|
28
28
|
Requires-Dist: databricks-agents>=1.9.0
|
|
29
29
|
Requires-Dist: databricks-langchain[memory]>=0.12.1
|
|
30
30
|
Requires-Dist: databricks-mcp>=0.5.0
|
|
31
|
-
Requires-Dist: databricks-sdk[openai]>=0.
|
|
31
|
+
Requires-Dist: databricks-sdk[openai]>=0.77.0
|
|
32
32
|
Requires-Dist: ddgs>=9.10.0
|
|
33
33
|
Requires-Dist: dspy>=2.6.27
|
|
34
34
|
Requires-Dist: flashrank>=0.2.10
|
|
@@ -26,6 +26,18 @@
|
|
|
26
26
|
# - Composite: { type: composite, options: [${VAR1}, ${VAR2}, default] }
|
|
27
27
|
# - Primitives: Just use the value directly
|
|
28
28
|
|
|
29
|
+
variables:
|
|
30
|
+
client_id: &client_id
|
|
31
|
+
options:
|
|
32
|
+
- env: RETAIL_AI_DATABRICKS_CLIENT_ID # Service principal client ID
|
|
33
|
+
- scope: retail_consumer_goods
|
|
34
|
+
secret: RETAIL_AI_DATABRICKS_CLIENT_ID
|
|
35
|
+
client_secret: &client_secret
|
|
36
|
+
options:
|
|
37
|
+
- env: RETAIL_AI_DATABRICKS_CLIENT_SECRET # Service principal secret
|
|
38
|
+
- scope: retail_consumer_goods
|
|
39
|
+
secret: RETAIL_AI_DATABRICKS_CLIENT_SECRET
|
|
40
|
+
|
|
29
41
|
schemas:
|
|
30
42
|
retail_schema: &retail_schema
|
|
31
43
|
catalog_name: nfleming
|
|
@@ -42,6 +54,8 @@ resources:
|
|
|
42
54
|
lakebase_db: &lakebase_db
|
|
43
55
|
name: retail-consumer-goods
|
|
44
56
|
instance_name: retail-consumer-goods
|
|
57
|
+
client_id: *client_id
|
|
58
|
+
client_secret: *client_secret
|
|
45
59
|
|
|
46
60
|
# =============================================================================
|
|
47
61
|
# TOOLS WITH HUMAN-IN-THE-LOOP CONFIGURATIONS
|
|
@@ -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.12"
|
|
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" }
|
|
@@ -46,7 +46,7 @@ dependencies = [
|
|
|
46
46
|
"databricks-agents>=1.9.0",
|
|
47
47
|
"databricks-langchain[memory]>=0.12.1",
|
|
48
48
|
"databricks-mcp>=0.5.0",
|
|
49
|
-
"databricks-sdk[openai]>=0.
|
|
49
|
+
"databricks-sdk[openai]>=0.77.0",
|
|
50
50
|
"ddgs>=9.10.0",
|
|
51
51
|
"dspy>=2.6.27",
|
|
52
52
|
"flashrank>=0.2.10",
|
|
@@ -34,7 +34,7 @@ mlflow.set_tracking_uri("databricks")
|
|
|
34
34
|
mlflow.langchain.autolog()
|
|
35
35
|
|
|
36
36
|
# Get config path from environment or use default
|
|
37
|
-
config_path: str = os.environ.get("DAO_AI_CONFIG_PATH", "
|
|
37
|
+
config_path: str = os.environ.get("DAO_AI_CONFIG_PATH", "dao_ai.yaml")
|
|
38
38
|
|
|
39
39
|
# Load configuration using AppConfig.from_file (consistent with CLI, notebook, builder)
|
|
40
40
|
config: AppConfig = AppConfig.from_file(config_path)
|
|
@@ -38,6 +38,8 @@ from databricks.sdk.service.apps import (
|
|
|
38
38
|
AppResource,
|
|
39
39
|
AppResourceDatabase,
|
|
40
40
|
AppResourceDatabaseDatabasePermission,
|
|
41
|
+
AppResourceExperiment,
|
|
42
|
+
AppResourceExperimentExperimentPermission,
|
|
41
43
|
AppResourceGenieSpace,
|
|
42
44
|
AppResourceGenieSpaceGenieSpacePermission,
|
|
43
45
|
AppResourceSecret,
|
|
@@ -308,6 +310,25 @@ def _extract_secrets_from_config(config: AppConfig) -> list[dict[str, Any]]:
|
|
|
308
310
|
A list of secret resource dictionaries with unique scope/key pairs
|
|
309
311
|
"""
|
|
310
312
|
secrets: dict[tuple[str, str], dict[str, Any]] = {}
|
|
313
|
+
used_names: set[str] = set()
|
|
314
|
+
|
|
315
|
+
def get_unique_resource_name(base_name: str) -> str:
|
|
316
|
+
"""Generate a unique resource name, adding suffix if needed."""
|
|
317
|
+
sanitized = _sanitize_resource_name(base_name)
|
|
318
|
+
if sanitized not in used_names:
|
|
319
|
+
used_names.add(sanitized)
|
|
320
|
+
return sanitized
|
|
321
|
+
# Name collision - add numeric suffix
|
|
322
|
+
counter = 1
|
|
323
|
+
while True:
|
|
324
|
+
# Leave room for suffix (e.g., "_1", "_2", etc.)
|
|
325
|
+
suffix = f"_{counter}"
|
|
326
|
+
max_base_len = 30 - len(suffix)
|
|
327
|
+
candidate = sanitized[:max_base_len] + suffix
|
|
328
|
+
if candidate not in used_names:
|
|
329
|
+
used_names.add(candidate)
|
|
330
|
+
return candidate
|
|
331
|
+
counter += 1
|
|
311
332
|
|
|
312
333
|
def extract_from_value(value: Any, path: str = "") -> None:
|
|
313
334
|
"""Recursively extract secrets from any value."""
|
|
@@ -315,9 +336,10 @@ def _extract_secrets_from_config(config: AppConfig) -> list[dict[str, Any]]:
|
|
|
315
336
|
secret_key = (value.scope, value.secret)
|
|
316
337
|
if secret_key not in secrets:
|
|
317
338
|
# Create a unique name for the secret resource
|
|
318
|
-
|
|
319
|
-
"
|
|
320
|
-
)
|
|
339
|
+
base_name = f"{value.scope}_{value.secret}".replace("-", "_").replace(
|
|
340
|
+
"/", "_"
|
|
341
|
+
)
|
|
342
|
+
resource_name = get_unique_resource_name(base_name)
|
|
321
343
|
secrets[secret_key] = {
|
|
322
344
|
"name": resource_name,
|
|
323
345
|
"type": "secret",
|
|
@@ -325,7 +347,9 @@ def _extract_secrets_from_config(config: AppConfig) -> list[dict[str, Any]]:
|
|
|
325
347
|
"key": value.secret,
|
|
326
348
|
"permissions": [{"level": "READ"}],
|
|
327
349
|
}
|
|
328
|
-
logger.debug(
|
|
350
|
+
logger.debug(
|
|
351
|
+
f"Found secret: {value.scope}/{value.secret} at {path} -> resource: {resource_name}"
|
|
352
|
+
)
|
|
329
353
|
elif isinstance(value, dict):
|
|
330
354
|
for k, v in value.items():
|
|
331
355
|
extract_from_value(v, f"{path}.{k}" if path else k)
|
|
@@ -518,7 +542,10 @@ def _sanitize_resource_name(name: str) -> str:
|
|
|
518
542
|
return sanitized
|
|
519
543
|
|
|
520
544
|
|
|
521
|
-
def generate_sdk_resources(
|
|
545
|
+
def generate_sdk_resources(
|
|
546
|
+
config: AppConfig,
|
|
547
|
+
experiment_id: str | None = None,
|
|
548
|
+
) -> list[AppResource]:
|
|
522
549
|
"""
|
|
523
550
|
Generate Databricks SDK AppResource objects from an AppConfig.
|
|
524
551
|
|
|
@@ -528,6 +555,9 @@ def generate_sdk_resources(config: AppConfig) -> list[AppResource]:
|
|
|
528
555
|
|
|
529
556
|
Args:
|
|
530
557
|
config: The AppConfig containing resource definitions
|
|
558
|
+
experiment_id: Optional MLflow experiment ID to add as a resource.
|
|
559
|
+
When provided, the experiment is added with CAN_EDIT permission,
|
|
560
|
+
allowing the app to log traces and runs.
|
|
531
561
|
|
|
532
562
|
Returns:
|
|
533
563
|
A list of AppResource objects for the Databricks SDK
|
|
@@ -536,13 +566,17 @@ def generate_sdk_resources(config: AppConfig) -> list[AppResource]:
|
|
|
536
566
|
>>> from databricks.sdk import WorkspaceClient
|
|
537
567
|
>>> from databricks.sdk.service.apps import App
|
|
538
568
|
>>> config = AppConfig.from_file("model_config.yaml")
|
|
539
|
-
>>> resources = generate_sdk_resources(config)
|
|
569
|
+
>>> resources = generate_sdk_resources(config, experiment_id="12345")
|
|
540
570
|
>>> w = WorkspaceClient()
|
|
541
571
|
>>> app = App(name="my-app", resources=resources)
|
|
542
572
|
>>> w.apps.create_and_wait(app=app)
|
|
543
573
|
"""
|
|
544
574
|
resources: list[AppResource] = []
|
|
545
575
|
|
|
576
|
+
# Add experiment resource if provided
|
|
577
|
+
if experiment_id:
|
|
578
|
+
resources.append(_extract_sdk_experiment_resource(experiment_id))
|
|
579
|
+
|
|
546
580
|
if config.resources is None:
|
|
547
581
|
logger.debug("No resources defined in config")
|
|
548
582
|
return resources
|
|
@@ -685,6 +719,36 @@ def _extract_sdk_volume_resources(
|
|
|
685
719
|
return resources
|
|
686
720
|
|
|
687
721
|
|
|
722
|
+
def _extract_sdk_experiment_resource(
|
|
723
|
+
experiment_id: str,
|
|
724
|
+
resource_name: str = "experiment",
|
|
725
|
+
) -> AppResource:
|
|
726
|
+
"""Create SDK AppResource for MLflow experiment.
|
|
727
|
+
|
|
728
|
+
This allows the Databricks App to log traces and runs to the specified
|
|
729
|
+
MLflow experiment. The experiment ID is exposed via the MLFLOW_EXPERIMENT_ID
|
|
730
|
+
environment variable using valueFrom: experiment in app.yaml.
|
|
731
|
+
|
|
732
|
+
Args:
|
|
733
|
+
experiment_id: The MLflow experiment ID
|
|
734
|
+
resource_name: The resource key name (default: "experiment")
|
|
735
|
+
|
|
736
|
+
Returns:
|
|
737
|
+
An AppResource for the MLflow experiment
|
|
738
|
+
"""
|
|
739
|
+
resource = AppResource(
|
|
740
|
+
name=resource_name,
|
|
741
|
+
experiment=AppResourceExperiment(
|
|
742
|
+
experiment_id=experiment_id,
|
|
743
|
+
permission=AppResourceExperimentExperimentPermission.CAN_EDIT,
|
|
744
|
+
),
|
|
745
|
+
)
|
|
746
|
+
logger.debug(
|
|
747
|
+
f"Extracted SDK experiment resource: {resource_name} -> {experiment_id}"
|
|
748
|
+
)
|
|
749
|
+
return resource
|
|
750
|
+
|
|
751
|
+
|
|
688
752
|
def _extract_sdk_secrets_from_config(config: AppConfig) -> list[AppResource]:
|
|
689
753
|
"""
|
|
690
754
|
Extract SDK AppResource objects for all secrets referenced in the config.
|
|
@@ -700,6 +764,25 @@ def _extract_sdk_secrets_from_config(config: AppConfig) -> list[AppResource]:
|
|
|
700
764
|
A list of AppResource objects for secrets
|
|
701
765
|
"""
|
|
702
766
|
secrets: dict[tuple[str, str], AppResource] = {}
|
|
767
|
+
used_names: set[str] = set()
|
|
768
|
+
|
|
769
|
+
def get_unique_resource_name(base_name: str) -> str:
|
|
770
|
+
"""Generate a unique resource name, adding suffix if needed."""
|
|
771
|
+
sanitized = _sanitize_resource_name(base_name)
|
|
772
|
+
if sanitized not in used_names:
|
|
773
|
+
used_names.add(sanitized)
|
|
774
|
+
return sanitized
|
|
775
|
+
# Name collision - add numeric suffix
|
|
776
|
+
counter = 1
|
|
777
|
+
while True:
|
|
778
|
+
# Leave room for suffix (e.g., "_1", "_2", etc.)
|
|
779
|
+
suffix = f"_{counter}"
|
|
780
|
+
max_base_len = 30 - len(suffix)
|
|
781
|
+
candidate = sanitized[:max_base_len] + suffix
|
|
782
|
+
if candidate not in used_names:
|
|
783
|
+
used_names.add(candidate)
|
|
784
|
+
return candidate
|
|
785
|
+
counter += 1
|
|
703
786
|
|
|
704
787
|
def extract_from_value(value: Any) -> None:
|
|
705
788
|
"""Recursively extract secrets from any value."""
|
|
@@ -707,10 +790,10 @@ def _extract_sdk_secrets_from_config(config: AppConfig) -> list[AppResource]:
|
|
|
707
790
|
secret_key = (value.scope, value.secret)
|
|
708
791
|
if secret_key not in secrets:
|
|
709
792
|
# Create a unique name for the secret resource
|
|
710
|
-
|
|
711
|
-
"
|
|
712
|
-
)
|
|
713
|
-
resource_name =
|
|
793
|
+
base_name = f"{value.scope}_{value.secret}".replace("-", "_").replace(
|
|
794
|
+
"/", "_"
|
|
795
|
+
)
|
|
796
|
+
resource_name = get_unique_resource_name(base_name)
|
|
714
797
|
|
|
715
798
|
resource = AppResource(
|
|
716
799
|
name=resource_name,
|
|
@@ -722,7 +805,7 @@ def _extract_sdk_secrets_from_config(config: AppConfig) -> list[AppResource]:
|
|
|
722
805
|
)
|
|
723
806
|
secrets[secret_key] = resource
|
|
724
807
|
logger.debug(
|
|
725
|
-
f"Found secret for SDK resource: {value.scope}/{value.secret}"
|
|
808
|
+
f"Found secret for SDK resource: {value.scope}/{value.secret} -> resource: {resource_name}"
|
|
726
809
|
)
|
|
727
810
|
elif isinstance(value, dict):
|
|
728
811
|
for v in value.values():
|
|
@@ -926,12 +1009,22 @@ def generate_app_yaml(
|
|
|
926
1009
|
env_vars: list[dict[str, str]] = [
|
|
927
1010
|
{"name": "MLFLOW_TRACKING_URI", "value": "databricks"},
|
|
928
1011
|
{"name": "MLFLOW_REGISTRY_URI", "value": "databricks-uc"},
|
|
929
|
-
{"name": "
|
|
1012
|
+
{"name": "MLFLOW_EXPERIMENT_ID", "valueFrom": "experiment"},
|
|
1013
|
+
{"name": "DAO_AI_CONFIG_PATH", "value": "dao_ai.yaml"},
|
|
930
1014
|
]
|
|
931
1015
|
|
|
932
1016
|
# Extract environment variables from config.app.environment_vars
|
|
933
1017
|
config_env_vars = _extract_env_vars_from_config(config)
|
|
934
1018
|
|
|
1019
|
+
# Environment variables that are automatically provided by Databricks Apps
|
|
1020
|
+
# and should not be included in app.yaml
|
|
1021
|
+
platform_provided_env_vars = {"DATABRICKS_HOST"}
|
|
1022
|
+
|
|
1023
|
+
# Filter out platform-provided env vars from config
|
|
1024
|
+
config_env_vars = [
|
|
1025
|
+
e for e in config_env_vars if e["name"] not in platform_provided_env_vars
|
|
1026
|
+
]
|
|
1027
|
+
|
|
935
1028
|
# Merge config env vars, avoiding duplicates (config takes precedence)
|
|
936
1029
|
base_env_names = {e["name"] for e in env_vars}
|
|
937
1030
|
for config_env in config_env_vars:
|
|
@@ -7,13 +7,13 @@ uses the AgentServer for the Databricks Apps runtime.
|
|
|
7
7
|
|
|
8
8
|
Configuration Loading:
|
|
9
9
|
The config path is specified via the DAO_AI_CONFIG_PATH environment variable,
|
|
10
|
-
or defaults to
|
|
10
|
+
or defaults to dao_ai.yaml in the current directory.
|
|
11
11
|
|
|
12
12
|
Usage:
|
|
13
13
|
# With environment variable
|
|
14
14
|
DAO_AI_CONFIG_PATH=/path/to/config.yaml python -m dao_ai.apps.server
|
|
15
15
|
|
|
16
|
-
# With default
|
|
16
|
+
# With default dao_ai.yaml in current directory
|
|
17
17
|
python -m dao_ai.apps.server
|
|
18
18
|
"""
|
|
19
19
|
|
|
@@ -152,25 +152,77 @@ class DatabricksProvider(ServiceProvider):
|
|
|
152
152
|
client_secret: str | None = None,
|
|
153
153
|
workspace_host: str | None = None,
|
|
154
154
|
) -> None:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
# Store credentials for lazy initialization
|
|
156
|
+
self._pat = pat
|
|
157
|
+
self._client_id = client_id
|
|
158
|
+
self._client_secret = client_secret
|
|
159
|
+
self._workspace_host = workspace_host
|
|
160
|
+
|
|
161
|
+
# Lazy initialization for WorkspaceClient
|
|
162
|
+
self._w: WorkspaceClient | None = w
|
|
163
|
+
self._w_initialized = w is not None
|
|
164
|
+
|
|
165
|
+
# Lazy initialization for VectorSearchClient - only create when needed
|
|
166
|
+
# This avoids authentication errors in Databricks Apps where VSC
|
|
167
|
+
# requires explicit credentials but the platform uses ambient auth
|
|
168
|
+
self._vsc: VectorSearchClient | None = vsc
|
|
169
|
+
self._vsc_initialized = vsc is not None
|
|
170
|
+
|
|
171
|
+
# Lazy initialization for DatabricksFunctionClient
|
|
172
|
+
self._dfs: DatabricksFunctionClient | None = dfs
|
|
173
|
+
self._dfs_initialized = dfs is not None
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def w(self) -> WorkspaceClient:
|
|
177
|
+
"""Lazy initialization of WorkspaceClient."""
|
|
178
|
+
if not self._w_initialized:
|
|
179
|
+
self._w = _workspace_client(
|
|
180
|
+
pat=self._pat,
|
|
181
|
+
client_id=self._client_id,
|
|
182
|
+
client_secret=self._client_secret,
|
|
183
|
+
workspace_host=self._workspace_host,
|
|
161
184
|
)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
185
|
+
self._w_initialized = True
|
|
186
|
+
return self._w # type: ignore[return-value]
|
|
187
|
+
|
|
188
|
+
@w.setter
|
|
189
|
+
def w(self, value: WorkspaceClient) -> None:
|
|
190
|
+
"""Set WorkspaceClient and mark as initialized."""
|
|
191
|
+
self._w = value
|
|
192
|
+
self._w_initialized = True
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def vsc(self) -> VectorSearchClient:
|
|
196
|
+
"""Lazy initialization of VectorSearchClient."""
|
|
197
|
+
if not self._vsc_initialized:
|
|
198
|
+
self._vsc = _vector_search_client(
|
|
199
|
+
pat=self._pat,
|
|
200
|
+
client_id=self._client_id,
|
|
201
|
+
client_secret=self._client_secret,
|
|
202
|
+
workspace_host=self._workspace_host,
|
|
168
203
|
)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
204
|
+
self._vsc_initialized = True
|
|
205
|
+
return self._vsc # type: ignore[return-value]
|
|
206
|
+
|
|
207
|
+
@vsc.setter
|
|
208
|
+
def vsc(self, value: VectorSearchClient) -> None:
|
|
209
|
+
"""Set VectorSearchClient and mark as initialized."""
|
|
210
|
+
self._vsc = value
|
|
211
|
+
self._vsc_initialized = True
|
|
212
|
+
|
|
213
|
+
@property
|
|
214
|
+
def dfs(self) -> DatabricksFunctionClient:
|
|
215
|
+
"""Lazy initialization of DatabricksFunctionClient."""
|
|
216
|
+
if not self._dfs_initialized:
|
|
217
|
+
self._dfs = _function_client(w=self.w)
|
|
218
|
+
self._dfs_initialized = True
|
|
219
|
+
return self._dfs # type: ignore[return-value]
|
|
220
|
+
|
|
221
|
+
@dfs.setter
|
|
222
|
+
def dfs(self, value: DatabricksFunctionClient) -> None:
|
|
223
|
+
"""Set DatabricksFunctionClient and mark as initialized."""
|
|
224
|
+
self._dfs = value
|
|
225
|
+
self._dfs_initialized = True
|
|
174
226
|
|
|
175
227
|
def experiment_name(self, config: AppConfig) -> str:
|
|
176
228
|
current_user: User = self.w.current_user.me()
|
|
@@ -558,11 +610,21 @@ class DatabricksProvider(ServiceProvider):
|
|
|
558
610
|
|
|
559
611
|
logger.info("Using workspace source path", source_path=source_path)
|
|
560
612
|
|
|
613
|
+
# Get or create experiment for this app (for tracing and tracking)
|
|
614
|
+
from mlflow.entities import Experiment
|
|
615
|
+
|
|
616
|
+
experiment: Experiment = self.get_or_create_experiment(config)
|
|
617
|
+
logger.info(
|
|
618
|
+
"Using MLflow experiment for app",
|
|
619
|
+
experiment_name=experiment.name,
|
|
620
|
+
experiment_id=experiment.experiment_id,
|
|
621
|
+
)
|
|
622
|
+
|
|
561
623
|
# Upload the configuration file to the workspace
|
|
562
624
|
source_config_path: str | None = config.source_config_path
|
|
563
625
|
if source_config_path:
|
|
564
626
|
# Read the config file and upload to workspace
|
|
565
|
-
config_file_name: str = "
|
|
627
|
+
config_file_name: str = "dao_ai.yaml"
|
|
566
628
|
workspace_config_path: str = f"{source_path}/{config_file_name}"
|
|
567
629
|
|
|
568
630
|
logger.info(
|
|
@@ -593,7 +655,7 @@ class DatabricksProvider(ServiceProvider):
|
|
|
593
655
|
logger.warning(
|
|
594
656
|
"No source config path available. "
|
|
595
657
|
"Ensure DAO_AI_CONFIG_PATH is set in the app environment or "
|
|
596
|
-
"
|
|
658
|
+
"dao_ai.yaml exists in the app source directory."
|
|
597
659
|
)
|
|
598
660
|
|
|
599
661
|
# Generate and upload app.yaml with dynamically discovered resources
|
|
@@ -618,13 +680,15 @@ class DatabricksProvider(ServiceProvider):
|
|
|
618
680
|
)
|
|
619
681
|
logger.info("app.yaml with resources uploaded", path=app_yaml_path)
|
|
620
682
|
|
|
621
|
-
# Generate SDK resources from the config
|
|
683
|
+
# Generate SDK resources from the config (including experiment)
|
|
622
684
|
from dao_ai.apps.resources import (
|
|
623
685
|
generate_sdk_resources,
|
|
624
686
|
generate_user_api_scopes,
|
|
625
687
|
)
|
|
626
688
|
|
|
627
|
-
sdk_resources = generate_sdk_resources(
|
|
689
|
+
sdk_resources = generate_sdk_resources(
|
|
690
|
+
config, experiment_id=experiment.experiment_id
|
|
691
|
+
)
|
|
628
692
|
if sdk_resources:
|
|
629
693
|
logger.info(
|
|
630
694
|
"Discovered app resources from config",
|
|
@@ -684,22 +684,28 @@ def test_deploy_apps_agent_creates_new_app():
|
|
|
684
684
|
# Mock current user
|
|
685
685
|
provider.w.current_user.me.return_value = mock_user
|
|
686
686
|
|
|
687
|
-
#
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
687
|
+
# Mock MLflow experiment
|
|
688
|
+
mock_experiment = MagicMock()
|
|
689
|
+
mock_experiment.experiment_id = "12345"
|
|
690
|
+
with patch.object(
|
|
691
|
+
provider, "get_or_create_experiment", return_value=mock_experiment
|
|
692
|
+
):
|
|
693
|
+
# Simulate app doesn't exist
|
|
694
|
+
provider.w.apps.get.side_effect = NotFound("App not found")
|
|
695
|
+
provider.w.apps.create_and_wait.return_value = mock_created_app
|
|
696
|
+
provider.w.apps.deploy_and_wait.return_value = mock_deployment
|
|
691
697
|
|
|
692
|
-
|
|
698
|
+
provider.deploy_apps_agent(mock_config)
|
|
693
699
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
700
|
+
# Verify create_and_wait was called with an App object
|
|
701
|
+
provider.w.apps.create_and_wait.assert_called_once()
|
|
702
|
+
call_args = provider.w.apps.create_and_wait.call_args
|
|
703
|
+
app_arg = call_args.kwargs.get("app")
|
|
704
|
+
assert app_arg is not None
|
|
705
|
+
assert app_arg.name == "test-app" # Normalized: underscores become dashes
|
|
706
|
+
assert app_arg.description == "Test app description"
|
|
707
|
+
# Verify deploy_and_wait was called
|
|
708
|
+
provider.w.apps.deploy_and_wait.assert_called_once()
|
|
703
709
|
|
|
704
710
|
|
|
705
711
|
@pytest.mark.unit
|
|
@@ -746,16 +752,22 @@ def test_deploy_apps_agent_updates_existing_app():
|
|
|
746
752
|
# Mock current user
|
|
747
753
|
provider.w.current_user.me.return_value = mock_user
|
|
748
754
|
|
|
749
|
-
#
|
|
750
|
-
|
|
751
|
-
|
|
755
|
+
# Mock MLflow experiment
|
|
756
|
+
mock_experiment = MagicMock()
|
|
757
|
+
mock_experiment.experiment_id = "12345"
|
|
758
|
+
with patch.object(
|
|
759
|
+
provider, "get_or_create_experiment", return_value=mock_experiment
|
|
760
|
+
):
|
|
761
|
+
# Simulate app already exists
|
|
762
|
+
provider.w.apps.get.return_value = mock_existing_app
|
|
763
|
+
provider.w.apps.deploy_and_wait.return_value = mock_deployment
|
|
752
764
|
|
|
753
|
-
|
|
765
|
+
provider.deploy_apps_agent(mock_config)
|
|
754
766
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
767
|
+
# Verify create_and_wait was NOT called (app already exists)
|
|
768
|
+
provider.w.apps.create_and_wait.assert_not_called()
|
|
769
|
+
# Verify deploy_and_wait was called
|
|
770
|
+
provider.w.apps.deploy_and_wait.assert_called_once()
|
|
759
771
|
|
|
760
772
|
|
|
761
773
|
@pytest.mark.unit
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/03_reranking/vector_search_with_reranking.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dao_ai-0.1.10 → dao_ai-0.1.12}/config/examples/11_prompt_engineering/prompt_optimization.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|