databricks-tellr-app 0.4.2.dev8__tar.gz → 0.4.2.dev9__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.
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/pyproject.toml +1 -1
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/mcp_server.py +21 -2
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/settings/design_systems.py +26 -6
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/database.py +153 -1
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/design_system.py +46 -8
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/design_system_compiler.py +374 -10
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/design_system_service.py +18 -3
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/README.md +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/databricks_tellr_app/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/databricks_tellr_app/run.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/databricks_tellr_app.egg-info/SOURCES.txt +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/databricks_tellr_app.egg-info/requires.txt +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/databricks_tellr_app.egg-info/top_level.txt +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/setup.cfg +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/setup.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/_otel_bootstrap.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/fixtures/tour_demo_deck.json +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/main.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/mcp_auth.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/middleware/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/middleware/csrf.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/middleware/request_logging.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/middleware/security_headers.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/_authz.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/admin.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/admin_usage.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/agent_config.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/chat.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/deck_contributors.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/export.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/google_slides.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/images.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/local_version.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/profiles.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/sessions.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/settings/contributors.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/settings/deck_prompts.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/settings/identities.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/settings/slide_styles.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/setup.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/slides.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/tools.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/tour.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/verification.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/routes/version.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/agent_config.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/requests.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/responses.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/settings/requests.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/settings/responses.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/schemas/streaming.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/chat_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/export_job_queue.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/feedback_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/job_queue.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/session_manager.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/session_naming.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/usage_events.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/services/usage_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/api/utils/validation.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/config_loader.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/context_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/databricks_client.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/encryption.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/init_default_profile.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/lakebase.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/migrate_profiles_to_agent_config.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/mlflow_agent_spans.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/mlflow_tracing.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/otel_logging.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/permission_context.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/prompt_modules.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/settings_db.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/core/user_context.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/deck_contributor.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/encryption_key.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/genie_space.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/google_global_credentials.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/google_oauth_token.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/identity.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/image.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/profile.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/profile_contributor.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/prompts.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/request_log.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/session.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/slide_deck_prompt.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/slide_style_library.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/usage_event.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/models/user_preference.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/database/types.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/domain/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/domain/slide.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/domain/slide_deck.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/agent.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/agent_factory.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/config_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/config_validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/converter_jail/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/converter_jail/ast_guard.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/converter_jail/codeprep.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/converter_jail/gslides_runner.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/converter_jail/jail.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/converter_jail/pptx_runner.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/converter_jail/protocol.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/design_system_templates.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/drive_uploader.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/evaluation/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/evaluation/llm_judge.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/genie_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/google_slides_auth.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/google_slides_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/html_to_google_slides.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/html_to_pptx.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/identity_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/identity_providers/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/identity_providers/account_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/identity_providers/local_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/identity_providers/workspace_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/image_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/image_tools.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/permission_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/pptx_from_html_huashu.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/pptx_from_records.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/pptx_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/profile_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/streaming_callback.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/tools/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/tools/agent_bricks_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/tools/ds_asset_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/tools/genie_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/tools/mcp_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/tools/model_endpoint_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/tools/vector_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/services/validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/css_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/ds_asset_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/error_handling.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/html_safety.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/html_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/image_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/js_validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/logging_config.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/pi_filter.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/slide_hash.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/spotlight.py +0 -0
- {databricks_tellr_app-0.4.2.dev8 → databricks_tellr_app-0.4.2.dev9}/src/utils/text_caps.py +0 -0
|
@@ -586,10 +586,30 @@ def _render_deck_response(
|
|
|
586
586
|
base_url: Public app URL prefix for building deck URLs. Empty
|
|
587
587
|
string yields relative URLs.
|
|
588
588
|
|
|
589
|
-
|
|
589
|
+
Image and design-system asset placeholders are substituted at this shared
|
|
590
|
+
response boundary so both MCP deck-returning tools emit standalone data
|
|
591
|
+
without expanding the persisted snapshot. Design-system assets are scoped
|
|
592
|
+
to the session's active design system and fail closed when it has none.
|
|
593
|
+
|
|
594
|
+
``SlideDeck.from_dict`` rebuilds the deck from the substituted snapshot,
|
|
590
595
|
including per-slide scripts/metadata and head metadata.
|
|
591
596
|
"""
|
|
592
597
|
deck_dict = deck_dict or {}
|
|
598
|
+
session_id = session["session_id"]
|
|
599
|
+
|
|
600
|
+
from src.api.services.chat_service import resolve_active_design_system_id
|
|
601
|
+
from src.utils.ds_asset_utils import substitute_deck_dict_ds_assets
|
|
602
|
+
from src.utils.image_utils import substitute_deck_dict_images
|
|
603
|
+
|
|
604
|
+
design_system_id = resolve_active_design_system_id(session_id)
|
|
605
|
+
with get_db_session() as db:
|
|
606
|
+
substitute_deck_dict_images(deck_dict, db)
|
|
607
|
+
substitute_deck_dict_ds_assets(
|
|
608
|
+
deck_dict,
|
|
609
|
+
db,
|
|
610
|
+
design_system_id=design_system_id,
|
|
611
|
+
)
|
|
612
|
+
|
|
593
613
|
if deck_dict:
|
|
594
614
|
deck = SlideDeck.from_dict(
|
|
595
615
|
deck_dict,
|
|
@@ -598,7 +618,6 @@ def _render_deck_response(
|
|
|
598
618
|
else:
|
|
599
619
|
deck = SlideDeck(title=session.get("title"))
|
|
600
620
|
|
|
601
|
-
session_id = session["session_id"]
|
|
602
621
|
deck_url = (
|
|
603
622
|
f"{base_url}/sessions/{session_id}/edit"
|
|
604
623
|
if base_url
|
|
@@ -8,10 +8,16 @@ the drop-in equivalent of ``slide_style_library.style_content`` — so it flows
|
|
|
8
8
|
through the existing generation seam (see ``agent_factory._get_prompt_content``).
|
|
9
9
|
|
|
10
10
|
Name uniqueness: creation/import return **409 Conflict** on a duplicate name
|
|
11
|
-
(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
(spec §6), matching the slide-styles convention. This is deliberately
|
|
12
|
+
non-destructive — an org-shared asset is never silently overwritten; the caller
|
|
13
|
+
supplies a different name (import accepts a ``name`` form field) to import a copy.
|
|
14
|
+
|
|
15
|
+
Uniqueness is scoped to **LIVE** rows, at both layers: the pre-checks here filter
|
|
16
|
+
``is_active``, and the database enforces the partial unique index
|
|
17
|
+
``uq_design_system_name_active`` (``WHERE is_active``). A whole-table rule made the
|
|
18
|
+
soft DELETE below reserve the name FOREVER — the tombstone is hidden from the list
|
|
19
|
+
endpoint, so a user who deleted a design system could never re-import under the same
|
|
20
|
+
name and had nothing left to delete. A name held only by a tombstone is free.
|
|
15
21
|
"""
|
|
16
22
|
import logging
|
|
17
23
|
import os
|
|
@@ -548,7 +554,14 @@ def create_design_system(
|
|
|
548
554
|
):
|
|
549
555
|
"""Create a design system from structured input (assets arrive via /import)."""
|
|
550
556
|
try:
|
|
551
|
-
|
|
557
|
+
# LIVE rows only, matching the partial unique index
|
|
558
|
+
# ``uq_design_system_name_active``. A soft-deleted system's name is free to
|
|
559
|
+
# reuse — see the DesignSystem model's note on the name column.
|
|
560
|
+
existing = (
|
|
561
|
+
db.query(DesignSystem)
|
|
562
|
+
.filter(DesignSystem.name == request.name, DesignSystem.is_active == True) # noqa: E712
|
|
563
|
+
.first()
|
|
564
|
+
)
|
|
552
565
|
if existing:
|
|
553
566
|
raise HTTPException(
|
|
554
567
|
status_code=status.HTTP_409_CONFLICT,
|
|
@@ -638,9 +651,16 @@ def update_design_system(
|
|
|
638
651
|
_require_creator_or_admin(ds)
|
|
639
652
|
|
|
640
653
|
if request.name and request.name != ds.name:
|
|
654
|
+
# LIVE rows only, matching the partial unique index
|
|
655
|
+
# ``uq_design_system_name_active`` — the same reason as create/import: a
|
|
656
|
+
# tombstone must not reserve a name the picker no longer shows.
|
|
641
657
|
clash = (
|
|
642
658
|
db.query(DesignSystem)
|
|
643
|
-
.filter(
|
|
659
|
+
.filter(
|
|
660
|
+
DesignSystem.name == request.name,
|
|
661
|
+
DesignSystem.id != ds_id,
|
|
662
|
+
DesignSystem.is_active == True, # noqa: E712
|
|
663
|
+
)
|
|
644
664
|
.first()
|
|
645
665
|
)
|
|
646
666
|
if clash:
|
|
@@ -549,7 +549,15 @@ def _run_migrations(engine, schema: str | None = None):
|
|
|
549
549
|
# deleted, so a reader of this list can see what happened to them.
|
|
550
550
|
_migrate_uncap_brand_text_columns(conn, inspector, schema, _qual, is_sqlite)
|
|
551
551
|
|
|
552
|
+
# --- design system: name uniqueness scoped to LIVE rows, so a soft delete
|
|
553
|
+
# --- stops reserving the name forever (partial unique index) ---
|
|
554
|
+
_migrate_design_system_partial_name_index(
|
|
555
|
+
conn, inspector, schema, _qual, is_sqlite
|
|
556
|
+
)
|
|
557
|
+
|
|
552
558
|
# --- keep newly created objects owned by the shared role (prod forks) ---
|
|
559
|
+
# Runs LAST so every object created above — including the partial name index
|
|
560
|
+
# — is re-homed onto the shared owner.
|
|
553
561
|
_reassign_new_objects_to_shared_owner(conn, is_sqlite)
|
|
554
562
|
|
|
555
563
|
|
|
@@ -763,7 +771,9 @@ def _migrate_uncap_brand_text_columns(
|
|
|
763
771
|
``VARCHAR(n)`` is a no-rewrite change — ``text`` and ``varchar`` share a
|
|
764
772
|
storage representation, so Postgres only updates the catalog. Existing values
|
|
765
773
|
are preserved exactly; ``text`` has no length limit to violate.
|
|
766
|
-
``design_system.name``
|
|
774
|
+
``design_system.name`` is covered by a unique index — the PARTIAL
|
|
775
|
+
``uq_design_system_name_active``, see
|
|
776
|
+
:func:`_migrate_design_system_partial_name_index` — which is unaffected: a
|
|
767
777
|
unique btree index over ``text`` is normal, bounded only by the ~2704-byte
|
|
768
778
|
index-tuple maximum that a design-system name does not approach. If one ever
|
|
769
779
|
did, the INSERT would fail loudly rather than truncate — so no prefix or
|
|
@@ -832,6 +842,148 @@ def _migrate_uncap_brand_text_columns(
|
|
|
832
842
|
)
|
|
833
843
|
|
|
834
844
|
|
|
845
|
+
#: Name of the partial unique index that scopes design-system name uniqueness to
|
|
846
|
+
#: LIVE rows. Must match the ``Index(...)`` declared in
|
|
847
|
+
#: ``src/database/models/design_system.py`` — ``create_all`` builds it under this
|
|
848
|
+
#: name on fresh installs and this migration builds it under the same name on
|
|
849
|
+
#: already-provisioned ones, so the two paths converge on one schema.
|
|
850
|
+
_DS_NAME_ACTIVE_INDEX = "uq_design_system_name_active"
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
def _migrate_design_system_partial_name_index(
|
|
854
|
+
conn, inspector, schema, _qual, is_sqlite
|
|
855
|
+
) -> None:
|
|
856
|
+
"""Scope ``design_system.name`` uniqueness to LIVE rows (idempotent).
|
|
857
|
+
|
|
858
|
+
``design_system.name`` originally carried a whole-table UNIQUE constraint. That
|
|
859
|
+
made the soft delete leak the name PERMANENTLY: ``DELETE`` tombstones the row
|
|
860
|
+
(``is_active = False``), the list endpoint hides it, and the tombstone then held
|
|
861
|
+
its name against every subsequent import — a name the user could no longer see,
|
|
862
|
+
delete, or reuse. The reported symptom was an unfixable
|
|
863
|
+
"A design system named 'X' already exists (id=N)" on re-importing a corrected
|
|
864
|
+
bundle under the name the user had just deleted.
|
|
865
|
+
|
|
866
|
+
Filtering only the application-side name pre-checks would NOT have fixed it: it
|
|
867
|
+
converts the clean 409 into an ``IntegrityError`` at commit, i.e. an HTTP 500 on
|
|
868
|
+
a legitimate upload. The uniqueness RULE itself is what was wrong, so this
|
|
869
|
+
replaces the whole-table constraint with a PARTIAL unique index over
|
|
870
|
+
``WHERE is_active``. Tombstones are then unconstrained — many may share one name,
|
|
871
|
+
which is what lets a delete/re-import cycle repeat indefinitely instead of
|
|
872
|
+
working exactly once — while two LIVE rows still cannot.
|
|
873
|
+
|
|
874
|
+
Ordering is deliberate: the replacement index is CREATED FIRST and the old
|
|
875
|
+
constraint is dropped ONLY IF that succeeded. The database is therefore never
|
|
876
|
+
left with no uniqueness enforcement at all — including on a database where the
|
|
877
|
+
constraint was already dropped but duplicate live names somehow exist, in which
|
|
878
|
+
case the CREATE fails, the DROP is skipped, and the existing constraint stays.
|
|
879
|
+
|
|
880
|
+
Idempotent: returns early once the partial index is present, so repeat startups
|
|
881
|
+
and a fresh ``create_all`` database (where the ORM already declares the index)
|
|
882
|
+
are both no-ops. Each statement runs in its OWN SAVEPOINT so a failure — e.g.
|
|
883
|
+
insufficient privileges on a locked-down deploy, or an inherited foreign-owned
|
|
884
|
+
table on a copy-on-write branch fork — cannot poison the outer migration
|
|
885
|
+
transaction.
|
|
886
|
+
|
|
887
|
+
Discovery, not assumption: the old constraint's name is REFLECTED rather than
|
|
888
|
+
hardcoded to Postgres's ``design_system_name_key`` default, and both shapes are
|
|
889
|
+
handled — a UNIQUE *constraint* (what a column-level ``unique=True`` emits, and
|
|
890
|
+
what needs ``DROP CONSTRAINT``) and a bare unique *index* (which needs
|
|
891
|
+
``DROP INDEX``).
|
|
892
|
+
|
|
893
|
+
No-op on SQLite. It is not a deployment target (``_get_database_url`` only ever
|
|
894
|
+
returns PostgreSQL unless ``DATABASE_URL`` is set explicitly), and the tests
|
|
895
|
+
build their schema with ``create_all``, which emits the partial index directly —
|
|
896
|
+
SQLite has supported partial indexes since 3.8, so the unit suite exercises the
|
|
897
|
+
SAME rule as Lakebase. An explicitly-configured pre-existing SQLite file would
|
|
898
|
+
keep its inline table-level UNIQUE, which SQLite cannot drop without rebuilding
|
|
899
|
+
the table; rebuilding a table of brand blobs is not worth doing for a
|
|
900
|
+
configuration nothing deploys, so it is left alone rather than silently rewritten.
|
|
901
|
+
"""
|
|
902
|
+
from sqlalchemy import inspect, text
|
|
903
|
+
|
|
904
|
+
if is_sqlite:
|
|
905
|
+
return
|
|
906
|
+
|
|
907
|
+
# Reflect LIVE, with a fresh inspector: the shared one caches its reflection
|
|
908
|
+
# from before the design_system table may have been created earlier in this same
|
|
909
|
+
# migration transaction.
|
|
910
|
+
try:
|
|
911
|
+
insp = inspect(conn)
|
|
912
|
+
indexes = insp.get_indexes("design_system", schema=schema)
|
|
913
|
+
unique_constraints = insp.get_unique_constraints("design_system", schema=schema)
|
|
914
|
+
except Exception:
|
|
915
|
+
return # table absent on this deploy
|
|
916
|
+
|
|
917
|
+
if any(ix.get("name") == _DS_NAME_ACTIVE_INDEX for ix in indexes):
|
|
918
|
+
return # already scoped
|
|
919
|
+
|
|
920
|
+
logger.info(
|
|
921
|
+
"Migration: scoping design_system.name uniqueness to active rows (%s)",
|
|
922
|
+
_DS_NAME_ACTIVE_INDEX,
|
|
923
|
+
)
|
|
924
|
+
try:
|
|
925
|
+
with conn.begin_nested():
|
|
926
|
+
conn.execute(text(
|
|
927
|
+
f"CREATE UNIQUE INDEX {_DS_NAME_ACTIVE_INDEX} "
|
|
928
|
+
f'ON {_qual("design_system")} (name) WHERE is_active'
|
|
929
|
+
))
|
|
930
|
+
except Exception:
|
|
931
|
+
logger.warning(
|
|
932
|
+
"Migration: could not create %s; design_system.name keeps its existing "
|
|
933
|
+
"whole-table uniqueness and a soft-deleted name stays reserved",
|
|
934
|
+
_DS_NAME_ACTIVE_INDEX,
|
|
935
|
+
exc_info=True,
|
|
936
|
+
)
|
|
937
|
+
return
|
|
938
|
+
|
|
939
|
+
# Only now is it safe to remove the whole-table rule the new index replaces.
|
|
940
|
+
# A column-level ``unique=True`` emits a UNIQUE CONSTRAINT; some databases may
|
|
941
|
+
# instead carry a bare unique index. Drop whichever is actually there, and only
|
|
942
|
+
# when it covers exactly ``(name)`` — a composite unique over more columns is a
|
|
943
|
+
# different rule this migration has no business removing.
|
|
944
|
+
for constraint in unique_constraints:
|
|
945
|
+
if list(constraint.get("column_names") or []) != ["name"]:
|
|
946
|
+
continue
|
|
947
|
+
name = constraint.get("name")
|
|
948
|
+
if not name:
|
|
949
|
+
continue
|
|
950
|
+
try:
|
|
951
|
+
with conn.begin_nested():
|
|
952
|
+
conn.execute(text(
|
|
953
|
+
f'ALTER TABLE {_qual("design_system")} DROP CONSTRAINT "{name}"'
|
|
954
|
+
))
|
|
955
|
+
logger.info("Migration: dropped whole-table unique constraint %s", name)
|
|
956
|
+
except Exception:
|
|
957
|
+
logger.warning(
|
|
958
|
+
"Migration: could not drop unique constraint %s; a soft-deleted "
|
|
959
|
+
"design-system name stays reserved until it is removed",
|
|
960
|
+
name,
|
|
961
|
+
exc_info=True,
|
|
962
|
+
)
|
|
963
|
+
|
|
964
|
+
constraint_names = {c.get("name") for c in unique_constraints}
|
|
965
|
+
for index in indexes:
|
|
966
|
+
if not index.get("unique") or list(index.get("column_names") or []) != ["name"]:
|
|
967
|
+
continue
|
|
968
|
+
name = index.get("name")
|
|
969
|
+
# A constraint-backing index is dropped with its constraint above; issuing
|
|
970
|
+
# DROP INDEX for it would fail.
|
|
971
|
+
if not name or name in constraint_names:
|
|
972
|
+
continue
|
|
973
|
+
try:
|
|
974
|
+
with conn.begin_nested():
|
|
975
|
+
qualified = f'"{schema}"."{name}"' if schema else f'"{name}"'
|
|
976
|
+
conn.execute(text(f"DROP INDEX {qualified}"))
|
|
977
|
+
logger.info("Migration: dropped whole-table unique index %s", name)
|
|
978
|
+
except Exception:
|
|
979
|
+
logger.warning(
|
|
980
|
+
"Migration: could not drop unique index %s; a soft-deleted "
|
|
981
|
+
"design-system name stays reserved until it is removed",
|
|
982
|
+
name,
|
|
983
|
+
exc_info=True,
|
|
984
|
+
)
|
|
985
|
+
|
|
986
|
+
|
|
835
987
|
def _reassign_new_objects_to_shared_owner(
|
|
836
988
|
conn, is_sqlite: bool, owning_role: str = "tellr_app_owners"
|
|
837
989
|
) -> None:
|
|
@@ -69,6 +69,7 @@ from sqlalchemy import (
|
|
|
69
69
|
Column,
|
|
70
70
|
DateTime,
|
|
71
71
|
ForeignKey,
|
|
72
|
+
Index,
|
|
72
73
|
Integer,
|
|
73
74
|
LargeBinary,
|
|
74
75
|
String,
|
|
@@ -124,14 +125,19 @@ class DesignSystem(Base):
|
|
|
124
125
|
# here silently TRUNCATED an imported name to 255 characters, storing the brand
|
|
125
126
|
# under a name it never chose.
|
|
126
127
|
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
|
|
128
|
+
# Uniqueness is enforced, but only over LIVE rows, by the partial unique index
|
|
129
|
+
# ``uq_design_system_name_active`` declared below — NOT by a column-level
|
|
130
|
+
# ``unique=True``. A whole-table UNIQUE constraint made a soft delete leak the
|
|
131
|
+
# name permanently: DELETE tombstones the row (``is_active = False``), the list
|
|
132
|
+
# endpoint hides it, and the tombstone then held its name against every later
|
|
133
|
+
# import — a name the user could no longer see, delete, or reuse. Scoping the
|
|
134
|
+
# index to ``WHERE is_active`` is what makes the tombstone stop owning the name,
|
|
135
|
+
# and it is the DATABASE half of the fix: the application pre-checks in
|
|
136
|
+
# ``design_system_service.import_bundle`` and the create/rename routes filter
|
|
137
|
+
# ``is_active`` to fail fast with a 409, but this index is what actually decides.
|
|
138
|
+
# Both halves must move together — filtering the pre-checks alone converts the
|
|
139
|
+
# clean 409 into an IntegrityError 500 at commit.
|
|
140
|
+
name = Column(Text, nullable=False)
|
|
135
141
|
description = Column(Text, nullable=True)
|
|
136
142
|
|
|
137
143
|
# Authorship + org-default flags (org-shared visibility; no per-user isolation)
|
|
@@ -195,6 +201,38 @@ class DesignSystem(Base):
|
|
|
195
201
|
passive_deletes=True,
|
|
196
202
|
)
|
|
197
203
|
|
|
204
|
+
# Name uniqueness scoped to LIVE rows. See the ``name`` column note for why a
|
|
205
|
+
# whole-table UNIQUE constraint was wrong.
|
|
206
|
+
#
|
|
207
|
+
# Deliberately a partial unique INDEX rather than a UNIQUE constraint: Postgres
|
|
208
|
+
# has no partial unique constraints, only partial unique indexes, and a
|
|
209
|
+
# column-level ``unique=True`` would emit exactly the whole-table constraint this
|
|
210
|
+
# replaces. Declared here so ``create_all`` builds it on fresh installs;
|
|
211
|
+
# ``_migrate_design_system_partial_name_index`` converts already-provisioned
|
|
212
|
+
# databases.
|
|
213
|
+
#
|
|
214
|
+
# ``WHERE is_active`` means MANY tombstones may share one name — intended, so a
|
|
215
|
+
# delete/re-import cycle can repeat indefinitely rather than working exactly once.
|
|
216
|
+
#
|
|
217
|
+
# Emitted identically on both dialects (verified): SQLite has supported partial
|
|
218
|
+
# indexes since 3.8, so the SQLite used in tests enforces the SAME rule as
|
|
219
|
+
# PostgreSQL/Lakebase and the behaviour is actually covered by the unit suite —
|
|
220
|
+
# it would not be under a ``postgresql_where``-only declaration. On
|
|
221
|
+
# PostgreSQL/Lakebase this is a unique btree index over ``text``, bounded only by
|
|
222
|
+
# the ~2704-byte index-tuple maximum a design-system name does not approach; an
|
|
223
|
+
# over-long name still fails loudly and is still translated by
|
|
224
|
+
# ``translate_name_index_limit_error``, so the uncapped-brand-text guarantee is
|
|
225
|
+
# unchanged.
|
|
226
|
+
__table_args__ = (
|
|
227
|
+
Index(
|
|
228
|
+
"uq_design_system_name_active",
|
|
229
|
+
"name",
|
|
230
|
+
unique=True,
|
|
231
|
+
postgresql_where=text("is_active"),
|
|
232
|
+
sqlite_where=text("is_active"),
|
|
233
|
+
),
|
|
234
|
+
)
|
|
235
|
+
|
|
198
236
|
def __repr__(self):
|
|
199
237
|
return (
|
|
200
238
|
f"<DesignSystem(id={self.id}, name='{self.name}', "
|