databricks-tellr-app 0.4.2.dev7__tar.gz → 0.4.2.dev8__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.dev7 → databricks_tellr_app-0.4.2.dev8}/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/databricks_tellr_app.egg-info/SOURCES.txt +16 -4
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/pyproject.toml +1 -1
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/main.py +17 -13
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/mcp_server.py +153 -12
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/_authz.py +36 -0
- databricks_tellr_app-0.4.2.dev8/src/api/routes/agent_config.py +310 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/chat.py +122 -10
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/export.py +18 -3
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/google_slides.py +21 -2
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/profiles.py +31 -7
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/sessions.py +30 -21
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/settings/__init__.py +2 -0
- databricks_tellr_app-0.4.2.dev8/src/api/routes/settings/design_systems.py +1289 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/slides.py +4 -4
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/verification.py +42 -21
- databricks_tellr_app-0.4.2.dev8/src/api/schemas/agent_config.py +333 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/services/chat_service.py +180 -17
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/services/export_job_queue.py +7 -2
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/services/session_manager.py +65 -799
- databricks_tellr_app-0.4.2.dev8/src/api/services/session_naming.py +134 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/database.py +432 -67
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/prompt_modules.py +67 -3
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/settings_db.py +45 -1
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/__init__.py +12 -1
- databricks_tellr_app-0.4.2.dev8/src/database/models/design_system.py +426 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/profile.py +6 -3
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/session.py +6 -90
- databricks_tellr_app-0.4.2.dev8/src/database/types.py +155 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/domain/slide_deck.py +2 -2
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/agent.py +13 -9
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/agent_factory.py +132 -5
- databricks_tellr_app-0.4.2.dev8/src/services/design_system_compiler.py +2222 -0
- databricks_tellr_app-0.4.2.dev8/src/services/design_system_service.py +1315 -0
- databricks_tellr_app-0.4.2.dev8/src/services/design_system_templates.py +940 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/tools/__init__.py +4 -0
- databricks_tellr_app-0.4.2.dev8/src/services/tools/ds_asset_tool.py +105 -0
- databricks_tellr_app-0.4.2.dev8/src/utils/ds_asset_utils.py +98 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/html_safety.py +18 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/html_utils.py +58 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/image_utils.py +21 -6
- databricks_tellr_app-0.4.2.dev7/src/api/routes/agent_config.py +0 -168
- databricks_tellr_app-0.4.2.dev7/src/api/schemas/agent_config.py +0 -116
- databricks_tellr_app-0.4.2.dev7/src/api/services/session_naming.py +0 -61
- databricks_tellr_app-0.4.2.dev7/src/api/services/slide_repository.py +0 -378
- databricks_tellr_app-0.4.2.dev7/src/core/backfill_session_slides_startup.py +0 -311
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/README.md +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/databricks_tellr_app/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/databricks_tellr_app/run.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/databricks_tellr_app.egg-info/requires.txt +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/databricks_tellr_app.egg-info/top_level.txt +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/setup.cfg +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/setup.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/_otel_bootstrap.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/fixtures/tour_demo_deck.json +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/mcp_auth.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/middleware/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/middleware/csrf.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/middleware/request_logging.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/middleware/security_headers.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/admin.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/admin_usage.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/deck_contributors.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/images.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/local_version.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/settings/contributors.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/settings/deck_prompts.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/settings/identities.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/settings/slide_styles.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/setup.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/tools.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/tour.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/version.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/schemas/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/schemas/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/schemas/requests.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/schemas/responses.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/schemas/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/schemas/settings/requests.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/schemas/settings/responses.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/schemas/streaming.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/services/feedback_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/services/job_queue.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/services/usage_events.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/services/usage_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/utils/validation.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/config_loader.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/context_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/databricks_client.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/encryption.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/init_default_profile.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/lakebase.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/migrate_profiles_to_agent_config.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/mlflow_agent_spans.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/mlflow_tracing.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/otel_logging.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/permission_context.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/core/user_context.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/deck_contributor.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/encryption_key.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/genie_space.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/google_global_credentials.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/google_oauth_token.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/identity.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/image.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/profile_contributor.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/prompts.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/request_log.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/slide_deck_prompt.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/slide_style_library.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/usage_event.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/database/models/user_preference.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/domain/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/domain/slide.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/config_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/config_validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/converter_jail/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/converter_jail/ast_guard.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/converter_jail/codeprep.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/converter_jail/gslides_runner.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/converter_jail/jail.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/converter_jail/pptx_runner.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/converter_jail/protocol.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/drive_uploader.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/evaluation/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/evaluation/llm_judge.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/genie_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/google_slides_auth.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/google_slides_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/html_to_google_slides.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/html_to_pptx.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/identity_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/identity_providers/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/identity_providers/account_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/identity_providers/local_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/identity_providers/workspace_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/image_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/image_tools.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/permission_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/pptx_from_html_huashu.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/pptx_from_records.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/pptx_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/profile_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/streaming_callback.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/tools/agent_bricks_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/tools/genie_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/tools/mcp_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/tools/model_endpoint_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/tools/vector_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/services/validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/css_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/error_handling.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/js_validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/logging_config.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/pi_filter.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/slide_hash.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/spotlight.py +0 -0
- {databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/utils/text_caps.py +0 -0
|
@@ -37,6 +37,7 @@ setup.py
|
|
|
37
37
|
./src/api/routes/settings/__init__.py
|
|
38
38
|
./src/api/routes/settings/contributors.py
|
|
39
39
|
./src/api/routes/settings/deck_prompts.py
|
|
40
|
+
./src/api/routes/settings/design_systems.py
|
|
40
41
|
./src/api/routes/settings/identities.py
|
|
41
42
|
./src/api/routes/settings/slide_styles.py
|
|
42
43
|
./src/api/schemas/__init__.py
|
|
@@ -55,13 +56,11 @@ setup.py
|
|
|
55
56
|
./src/api/services/job_queue.py
|
|
56
57
|
./src/api/services/session_manager.py
|
|
57
58
|
./src/api/services/session_naming.py
|
|
58
|
-
./src/api/services/slide_repository.py
|
|
59
59
|
./src/api/services/usage_events.py
|
|
60
60
|
./src/api/services/usage_service.py
|
|
61
61
|
./src/api/utils/__init__.py
|
|
62
62
|
./src/api/utils/validation.py
|
|
63
63
|
./src/core/__init__.py
|
|
64
|
-
./src/core/backfill_session_slides_startup.py
|
|
65
64
|
./src/core/config_loader.py
|
|
66
65
|
./src/core/context_utils.py
|
|
67
66
|
./src/core/database.py
|
|
@@ -79,8 +78,10 @@ setup.py
|
|
|
79
78
|
./src/core/settings_db.py
|
|
80
79
|
./src/core/user_context.py
|
|
81
80
|
./src/database/__init__.py
|
|
81
|
+
./src/database/types.py
|
|
82
82
|
./src/database/models/__init__.py
|
|
83
83
|
./src/database/models/deck_contributor.py
|
|
84
|
+
./src/database/models/design_system.py
|
|
84
85
|
./src/database/models/encryption_key.py
|
|
85
86
|
./src/database/models/feedback.py
|
|
86
87
|
./src/database/models/genie_space.py
|
|
@@ -105,6 +106,9 @@ setup.py
|
|
|
105
106
|
./src/services/agent_factory.py
|
|
106
107
|
./src/services/config_service.py
|
|
107
108
|
./src/services/config_validator.py
|
|
109
|
+
./src/services/design_system_compiler.py
|
|
110
|
+
./src/services/design_system_service.py
|
|
111
|
+
./src/services/design_system_templates.py
|
|
108
112
|
./src/services/drive_uploader.py
|
|
109
113
|
./src/services/genie_service.py
|
|
110
114
|
./src/services/google_slides_auth.py
|
|
@@ -136,12 +140,14 @@ setup.py
|
|
|
136
140
|
./src/services/identity_providers/workspace_provider.py
|
|
137
141
|
./src/services/tools/__init__.py
|
|
138
142
|
./src/services/tools/agent_bricks_tool.py
|
|
143
|
+
./src/services/tools/ds_asset_tool.py
|
|
139
144
|
./src/services/tools/genie_tool.py
|
|
140
145
|
./src/services/tools/mcp_tool.py
|
|
141
146
|
./src/services/tools/model_endpoint_tool.py
|
|
142
147
|
./src/services/tools/vector_tool.py
|
|
143
148
|
./src/utils/__init__.py
|
|
144
149
|
./src/utils/css_utils.py
|
|
150
|
+
./src/utils/ds_asset_utils.py
|
|
145
151
|
./src/utils/error_handling.py
|
|
146
152
|
./src/utils/html_safety.py
|
|
147
153
|
./src/utils/html_utils.py
|
|
@@ -193,6 +199,7 @@ src/api/routes/version.py
|
|
|
193
199
|
src/api/routes/settings/__init__.py
|
|
194
200
|
src/api/routes/settings/contributors.py
|
|
195
201
|
src/api/routes/settings/deck_prompts.py
|
|
202
|
+
src/api/routes/settings/design_systems.py
|
|
196
203
|
src/api/routes/settings/identities.py
|
|
197
204
|
src/api/routes/settings/slide_styles.py
|
|
198
205
|
src/api/schemas/__init__.py
|
|
@@ -211,13 +218,11 @@ src/api/services/feedback_service.py
|
|
|
211
218
|
src/api/services/job_queue.py
|
|
212
219
|
src/api/services/session_manager.py
|
|
213
220
|
src/api/services/session_naming.py
|
|
214
|
-
src/api/services/slide_repository.py
|
|
215
221
|
src/api/services/usage_events.py
|
|
216
222
|
src/api/services/usage_service.py
|
|
217
223
|
src/api/utils/__init__.py
|
|
218
224
|
src/api/utils/validation.py
|
|
219
225
|
src/core/__init__.py
|
|
220
|
-
src/core/backfill_session_slides_startup.py
|
|
221
226
|
src/core/config_loader.py
|
|
222
227
|
src/core/context_utils.py
|
|
223
228
|
src/core/database.py
|
|
@@ -235,8 +240,10 @@ src/core/prompt_modules.py
|
|
|
235
240
|
src/core/settings_db.py
|
|
236
241
|
src/core/user_context.py
|
|
237
242
|
src/database/__init__.py
|
|
243
|
+
src/database/types.py
|
|
238
244
|
src/database/models/__init__.py
|
|
239
245
|
src/database/models/deck_contributor.py
|
|
246
|
+
src/database/models/design_system.py
|
|
240
247
|
src/database/models/encryption_key.py
|
|
241
248
|
src/database/models/feedback.py
|
|
242
249
|
src/database/models/genie_space.py
|
|
@@ -261,6 +268,9 @@ src/services/agent.py
|
|
|
261
268
|
src/services/agent_factory.py
|
|
262
269
|
src/services/config_service.py
|
|
263
270
|
src/services/config_validator.py
|
|
271
|
+
src/services/design_system_compiler.py
|
|
272
|
+
src/services/design_system_service.py
|
|
273
|
+
src/services/design_system_templates.py
|
|
264
274
|
src/services/drive_uploader.py
|
|
265
275
|
src/services/genie_service.py
|
|
266
276
|
src/services/google_slides_auth.py
|
|
@@ -292,12 +302,14 @@ src/services/identity_providers/local_provider.py
|
|
|
292
302
|
src/services/identity_providers/workspace_provider.py
|
|
293
303
|
src/services/tools/__init__.py
|
|
294
304
|
src/services/tools/agent_bricks_tool.py
|
|
305
|
+
src/services/tools/ds_asset_tool.py
|
|
295
306
|
src/services/tools/genie_tool.py
|
|
296
307
|
src/services/tools/mcp_tool.py
|
|
297
308
|
src/services/tools/model_endpoint_tool.py
|
|
298
309
|
src/services/tools/vector_tool.py
|
|
299
310
|
src/utils/__init__.py
|
|
300
311
|
src/utils/css_utils.py
|
|
312
|
+
src/utils/ds_asset_utils.py
|
|
301
313
|
src/utils/error_handling.py
|
|
302
314
|
src/utils/html_safety.py
|
|
303
315
|
src/utils/html_utils.py
|
|
@@ -27,6 +27,7 @@ from src.core.permission_context import (
|
|
|
27
27
|
from src.api.routes.settings import (
|
|
28
28
|
contributors_router,
|
|
29
29
|
deck_prompts_router,
|
|
30
|
+
design_systems_router,
|
|
30
31
|
identities_router,
|
|
31
32
|
slide_styles_router,
|
|
32
33
|
)
|
|
@@ -40,7 +41,6 @@ from src.core.database import (
|
|
|
40
41
|
stop_token_refresh,
|
|
41
42
|
)
|
|
42
43
|
from src.core.migrate_profiles_to_agent_config import migrate_profiles, backfill_sessions
|
|
43
|
-
from src.core.backfill_session_slides_startup import backfill_unmigrated_decks
|
|
44
44
|
|
|
45
45
|
logger = logging.getLogger(__name__)
|
|
46
46
|
|
|
@@ -115,16 +115,6 @@ async def lifespan(app: FastAPI):
|
|
|
115
115
|
backfilled = backfill_sessions(get_session_local())
|
|
116
116
|
if backfilled:
|
|
117
117
|
logger.info(f"Backfilled {backfilled} sessions with agent_config")
|
|
118
|
-
|
|
119
|
-
# Row-per-slide: migrate historical deck_json blobs into session_slides
|
|
120
|
-
# rows. Guarded by a NOT EXISTS anti-join, so this is a no-op scan once
|
|
121
|
-
# every deck has rows. Runs here rather than as a manual script so an
|
|
122
|
-
# upgrade cannot leave decks half-migrated (a deck edited before a
|
|
123
|
-
# hand-run backfill acquires rows without its verdicts, and the
|
|
124
|
-
# idempotency guard then skips it permanently).
|
|
125
|
-
slide_decks = backfill_unmigrated_decks(get_session_local())
|
|
126
|
-
if slide_decks:
|
|
127
|
-
logger.info(f"Backfilled {slide_decks} deck(s) into session_slides rows")
|
|
128
118
|
except Exception as e:
|
|
129
119
|
logger.error(f"Failed to initialize database: {e}")
|
|
130
120
|
raise
|
|
@@ -495,6 +485,7 @@ app.include_router(contributors_router, prefix="/api/settings", tags=["settings"
|
|
|
495
485
|
app.include_router(deck_prompts_router, prefix="/api/settings", tags=["settings"])
|
|
496
486
|
app.include_router(identities_router, prefix="/api/settings", tags=["settings"])
|
|
497
487
|
app.include_router(slide_styles_router, prefix="/api/settings", tags=["settings"])
|
|
488
|
+
app.include_router(design_systems_router, prefix="/api/settings", tags=["settings"])
|
|
498
489
|
|
|
499
490
|
# MCP server — mount the FastMCP streamable-HTTP ASGI app at /mcp.
|
|
500
491
|
# Must be registered before the SPA catch-all (which is added lazily by
|
|
@@ -535,16 +526,27 @@ async def get_current_user():
|
|
|
535
526
|
|
|
536
527
|
Also includes the user's Databricks ID and group IDs from the permission
|
|
537
528
|
context, which are used for profile permission checks.
|
|
529
|
+
|
|
530
|
+
``is_admin`` is a UX-only signal so the frontend can hide admin surfaces
|
|
531
|
+
the caller cannot use; it is NOT authorization. Every admin route keeps
|
|
532
|
+
``Depends(require_admin)`` and those 403s remain the real protection. It
|
|
533
|
+
is derived from that same primitive (``is_caller_admin``), so it cannot
|
|
534
|
+
advertise access the server would refuse, and it fails closed.
|
|
538
535
|
"""
|
|
536
|
+
from src.api.routes._authz import is_caller_admin
|
|
539
537
|
from src.core.permission_context import get_permission_context
|
|
540
|
-
|
|
538
|
+
|
|
541
539
|
ctx_user = get_ctx_user()
|
|
542
540
|
perm_ctx = get_permission_context()
|
|
543
|
-
|
|
541
|
+
|
|
542
|
+
# Never raises (fails closed to False), so it cannot break identity resolution.
|
|
543
|
+
is_admin = is_caller_admin()
|
|
544
|
+
|
|
544
545
|
if ctx_user:
|
|
545
546
|
result = {
|
|
546
547
|
"username": ctx_user,
|
|
547
548
|
"display_name": ctx_user,
|
|
549
|
+
"is_admin": is_admin,
|
|
548
550
|
}
|
|
549
551
|
# Include permission context info if available
|
|
550
552
|
if perm_ctx:
|
|
@@ -562,12 +564,14 @@ async def get_current_user():
|
|
|
562
564
|
"username": user.user_name,
|
|
563
565
|
"display_name": user.display_name or user.user_name,
|
|
564
566
|
"user_id": user.id,
|
|
567
|
+
"is_admin": is_admin,
|
|
565
568
|
}
|
|
566
569
|
except Exception as e:
|
|
567
570
|
logger.warning(f"Failed to get current user: {e}")
|
|
568
571
|
return {
|
|
569
572
|
"username": "user",
|
|
570
573
|
"display_name": "User",
|
|
574
|
+
"is_admin": is_admin,
|
|
571
575
|
}
|
|
572
576
|
|
|
573
577
|
|
|
@@ -28,7 +28,7 @@ from src.api.services.job_queue import enqueue_job, get_job_status
|
|
|
28
28
|
from src.api.services.session_manager import get_session_manager
|
|
29
29
|
from src.core.database import get_db_session
|
|
30
30
|
from src.core.permission_context import get_permission_context
|
|
31
|
-
from src.core.settings_db import get_default_slide_style_id
|
|
31
|
+
from src.core.settings_db import get_default_design_system_id, get_default_slide_style_id
|
|
32
32
|
from src.domain.slide_deck import SlideDeck
|
|
33
33
|
from src.services.permission_service import get_permission_service
|
|
34
34
|
|
|
@@ -292,6 +292,106 @@ def _request_from_context(ctx: Context) -> Request:
|
|
|
292
292
|
return req
|
|
293
293
|
|
|
294
294
|
|
|
295
|
+
def _template_names_and_ids(design_system_id: int) -> list[tuple[str, int]]:
|
|
296
|
+
"""The ACTIVE design system's ``(template name, template id)`` pairs.
|
|
297
|
+
|
|
298
|
+
Eagerly materialized to PLAIN values while the DB session is still OPEN.
|
|
299
|
+
This replaces a helper that returned the ``DesignSystem`` ORM instance
|
|
300
|
+
itself: ``get_db_session()`` commits and closes on exit, and the
|
|
301
|
+
sessionmaker uses SQLAlchemy's default ``expire_on_commit=True``, so that
|
|
302
|
+
instance was detached with its ``templates`` relationship expired. Reading
|
|
303
|
+
it raised ``DetachedInstanceError``, which the resolver caught and reported
|
|
304
|
+
as "name matched nothing" — silently ignoring every valid production
|
|
305
|
+
``template_name``. Returning plain values makes that class of bug
|
|
306
|
+
unavailable rather than merely fixed.
|
|
307
|
+
|
|
308
|
+
Returns an empty list when the design system is missing or inactive, so the
|
|
309
|
+
caller's "no match -> no pin" path is unchanged. Scoped to the ONE design
|
|
310
|
+
system, so a name can never pin another system's template.
|
|
311
|
+
"""
|
|
312
|
+
from src.core.database import get_db_session
|
|
313
|
+
from src.database.models import DesignSystem
|
|
314
|
+
from src.services.design_system_templates import materialize_templates
|
|
315
|
+
|
|
316
|
+
with get_db_session() as db:
|
|
317
|
+
design_system = (
|
|
318
|
+
db.query(DesignSystem)
|
|
319
|
+
.filter_by(id=design_system_id, is_active=True)
|
|
320
|
+
.first()
|
|
321
|
+
)
|
|
322
|
+
if design_system is None:
|
|
323
|
+
return []
|
|
324
|
+
# Same idempotent derivation the generation path uses, for systems
|
|
325
|
+
# imported before the templates table existed.
|
|
326
|
+
materialize_templates(design_system)
|
|
327
|
+
db.flush() # newly materialized rows need ids before we read them
|
|
328
|
+
return [
|
|
329
|
+
(str(getattr(template, "name", None) or ""), int(template.id))
|
|
330
|
+
for template in (getattr(design_system, "templates", None) or [])
|
|
331
|
+
if getattr(template, "id", None) is not None
|
|
332
|
+
]
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _normalized_template_name(value: Optional[str]) -> str:
|
|
336
|
+
"""The comparison key for template-name matching: casefolded, with all
|
|
337
|
+
whitespace runs collapsed to a single space.
|
|
338
|
+
|
|
339
|
+
Applied to BOTH sides so the notion of "the same name" is defined in exactly
|
|
340
|
+
one place — which is also what makes ambiguity detectable rather than
|
|
341
|
+
order-dependent.
|
|
342
|
+
"""
|
|
343
|
+
return " ".join((value or "").split()).casefold()
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _resolve_template_name(design_system_id: int, template_name: str) -> Optional[int]:
|
|
347
|
+
"""Resolve a template NAME to its id within *design_system_id*.
|
|
348
|
+
|
|
349
|
+
MCP callers have no template ids — they see names (the compiler injects
|
|
350
|
+
the name+description catalog as soft-pick guidance), so a caller that
|
|
351
|
+
wants a specific layout pins it by name. Matching is case- and
|
|
352
|
+
whitespace-insensitive.
|
|
353
|
+
|
|
354
|
+
Because matching is insensitive, two DISTINCT rows can both match one query
|
|
355
|
+
("Two Column" and "two column"). That is AMBIGUOUS, and returning the first
|
|
356
|
+
hit made the winner depend on relationship load order — a caller could
|
|
357
|
+
silently get the other layout, and which one could change between requests.
|
|
358
|
+
An ambiguous name is therefore UNRESOLVED: treated exactly like a name that
|
|
359
|
+
matches nothing, and logged so the duplicate rows are discoverable.
|
|
360
|
+
|
|
361
|
+
Returns ``None`` — never raises — when the design system is missing, the
|
|
362
|
+
name matches nothing, the name is ambiguous, or the lookup fails. An
|
|
363
|
+
unresolvable name must degrade to "no pin" (the model then soft-picks as
|
|
364
|
+
usual), never a 500.
|
|
365
|
+
"""
|
|
366
|
+
wanted = _normalized_template_name(template_name)
|
|
367
|
+
if not wanted:
|
|
368
|
+
return None
|
|
369
|
+
try:
|
|
370
|
+
matches = [
|
|
371
|
+
template_id
|
|
372
|
+
for name, template_id in _template_names_and_ids(design_system_id)
|
|
373
|
+
if _normalized_template_name(name) == wanted
|
|
374
|
+
]
|
|
375
|
+
if len(matches) == 1:
|
|
376
|
+
return matches[0]
|
|
377
|
+
if matches:
|
|
378
|
+
logger.warning(
|
|
379
|
+
"MCP template_name %r is ambiguous in design system %s: it matches "
|
|
380
|
+
"%d templates (ids %s). Ignoring the pin — the model soft-picks a "
|
|
381
|
+
"layout instead. Rename the duplicates to make the name unique.",
|
|
382
|
+
template_name,
|
|
383
|
+
design_system_id,
|
|
384
|
+
len(matches),
|
|
385
|
+
", ".join(str(template_id) for template_id in sorted(matches)),
|
|
386
|
+
)
|
|
387
|
+
except Exception:
|
|
388
|
+
logger.exception(
|
|
389
|
+
"Failed to resolve MCP template_name against design system %s",
|
|
390
|
+
design_system_id,
|
|
391
|
+
)
|
|
392
|
+
return None
|
|
393
|
+
|
|
394
|
+
|
|
295
395
|
@mcp.tool(
|
|
296
396
|
name="create_deck",
|
|
297
397
|
description=(
|
|
@@ -301,7 +401,10 @@ def _request_from_context(ctx: Context) -> Request:
|
|
|
301
401
|
"appears in their tellr UI. v1 runs prompt-only: the agent does not "
|
|
302
402
|
"invoke Genie, Vector Search, or other tools. Callers that want data-"
|
|
303
403
|
"backed decks should gather the data themselves and include it in the "
|
|
304
|
-
"prompt."
|
|
404
|
+
"prompt. The deck uses the org-default design system unless "
|
|
405
|
+
"design_system_id or slide_style_id says otherwise; pass template_name "
|
|
406
|
+
"to pin one of that design system's named templates (otherwise the "
|
|
407
|
+
"model picks the best-matching one)."
|
|
305
408
|
),
|
|
306
409
|
)
|
|
307
410
|
async def create_deck(
|
|
@@ -309,6 +412,8 @@ async def create_deck(
|
|
|
309
412
|
prompt: str,
|
|
310
413
|
num_slides: Optional[int] = None,
|
|
311
414
|
slide_style_id: Optional[int] = None,
|
|
415
|
+
design_system_id: Optional[int] = None,
|
|
416
|
+
template_name: Optional[str] = None,
|
|
312
417
|
deck_prompt_id: Optional[int] = None,
|
|
313
418
|
correlation_id: Optional[str] = None,
|
|
314
419
|
) -> dict:
|
|
@@ -317,6 +422,8 @@ async def create_deck(
|
|
|
317
422
|
prompt=prompt,
|
|
318
423
|
num_slides=num_slides,
|
|
319
424
|
slide_style_id=slide_style_id,
|
|
425
|
+
design_system_id=design_system_id,
|
|
426
|
+
template_name=template_name,
|
|
320
427
|
deck_prompt_id=deck_prompt_id,
|
|
321
428
|
correlation_id=correlation_id,
|
|
322
429
|
)
|
|
@@ -327,6 +434,8 @@ async def _create_deck_impl(
|
|
|
327
434
|
prompt: str,
|
|
328
435
|
num_slides: Optional[int] = None,
|
|
329
436
|
slide_style_id: Optional[int] = None,
|
|
437
|
+
design_system_id: Optional[int] = None,
|
|
438
|
+
template_name: Optional[str] = None,
|
|
330
439
|
deck_prompt_id: Optional[int] = None,
|
|
331
440
|
correlation_id: Optional[str] = None,
|
|
332
441
|
) -> dict:
|
|
@@ -352,16 +461,48 @@ async def _create_deck_impl(
|
|
|
352
461
|
try:
|
|
353
462
|
with mcp_auth_scope(request) as identity:
|
|
354
463
|
agent_config: dict[str, Any] = {"tools": []}
|
|
355
|
-
#
|
|
356
|
-
#
|
|
357
|
-
#
|
|
358
|
-
#
|
|
359
|
-
#
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if
|
|
364
|
-
|
|
464
|
+
# Resolve the style SOURCE exactly as the browser chat flow does
|
|
465
|
+
# (see routes/chat.py::_apply_org_default_style_source): a design
|
|
466
|
+
# system outranks a slide style, an explicit choice always wins,
|
|
467
|
+
# and only ONE source is ever seeded so the prompt never carries
|
|
468
|
+
# two competing style authorities. Before this, MCP decks could not
|
|
469
|
+
# reach a design system at all — only slide_style_id was ever set,
|
|
470
|
+
# so they always got the default slide style.
|
|
471
|
+
effective_ds_id = design_system_id
|
|
472
|
+
if effective_ds_id is None and slide_style_id is None:
|
|
473
|
+
effective_ds_id = get_default_design_system_id()
|
|
474
|
+
|
|
475
|
+
if effective_ds_id is not None:
|
|
476
|
+
agent_config["design_system_id"] = effective_ds_id
|
|
477
|
+
# Templates belong to a design system, so a name is only
|
|
478
|
+
# meaningful here. Unresolvable -> no pin (logged), and the
|
|
479
|
+
# model soft-picks from the catalog the compiler injects.
|
|
480
|
+
if template_name and template_name.strip():
|
|
481
|
+
template_id = _resolve_template_name(effective_ds_id, template_name)
|
|
482
|
+
if template_id is not None:
|
|
483
|
+
agent_config["template_id"] = template_id
|
|
484
|
+
else:
|
|
485
|
+
logger.warning(
|
|
486
|
+
"MCP create_deck: template_name %r matched no template "
|
|
487
|
+
"on design system %s; generating without a pin",
|
|
488
|
+
template_name,
|
|
489
|
+
effective_ds_id,
|
|
490
|
+
)
|
|
491
|
+
else:
|
|
492
|
+
# No design system in play: fall back to the tellr-configured
|
|
493
|
+
# default slide style rather than the hardcoded
|
|
494
|
+
# DEFAULT_SLIDE_STYLE constant agent_factory would otherwise use.
|
|
495
|
+
effective_style_id = slide_style_id
|
|
496
|
+
if effective_style_id is None:
|
|
497
|
+
effective_style_id = get_default_slide_style_id()
|
|
498
|
+
if effective_style_id is not None:
|
|
499
|
+
agent_config["slide_style_id"] = effective_style_id
|
|
500
|
+
if template_name and template_name.strip():
|
|
501
|
+
logger.warning(
|
|
502
|
+
"MCP create_deck: template_name %r ignored — templates "
|
|
503
|
+
"require a design system and none is selected",
|
|
504
|
+
template_name,
|
|
505
|
+
)
|
|
365
506
|
if deck_prompt_id is not None:
|
|
366
507
|
agent_config["deck_prompt_id"] = deck_prompt_id
|
|
367
508
|
if num_slides is not None:
|
{databricks_tellr_app-0.4.2.dev7 → databricks_tellr_app-0.4.2.dev8}/src/api/routes/_authz.py
RENAMED
|
@@ -372,6 +372,42 @@ def require_admin() -> None:
|
|
|
372
372
|
raise HTTPException(status_code=403, detail="Admin access required")
|
|
373
373
|
|
|
374
374
|
|
|
375
|
+
def is_caller_admin() -> bool:
|
|
376
|
+
"""Return the admin verdict for the current caller as a boolean.
|
|
377
|
+
|
|
378
|
+
UX-ONLY signal, for hiding admin surfaces the caller cannot use. This is
|
|
379
|
+
NOT authorization: every admin route keeps ``Depends(require_admin)`` and
|
|
380
|
+
those 403s remain the real protection. A caller who forges this flag
|
|
381
|
+
client-side gains nothing but a page whose every request 403s.
|
|
382
|
+
|
|
383
|
+
Deliberately implemented by *delegating to* ``require_admin`` and mapping
|
|
384
|
+
its 403 to ``False`` rather than re-deriving the verdict. The flag then
|
|
385
|
+
cannot drift from the gate it advertises, and there is exactly one
|
|
386
|
+
group-lookup, cache and fail-closed policy in the codebase.
|
|
387
|
+
|
|
388
|
+
Consequently the non-production bypass is inherited too: in local dev/test
|
|
389
|
+
this returns ``True`` for everyone, matching the routes that also allow
|
|
390
|
+
everyone there, so devloop testing of admin surfaces is not obstructed.
|
|
391
|
+
In production the verdict is real workspace ``admins`` group membership.
|
|
392
|
+
|
|
393
|
+
Never raises: unlike the dependency form, a caller asking "am I admin?"
|
|
394
|
+
must always get an answer, so any unexpected error degrades to ``False``
|
|
395
|
+
(fail closed) instead of failing the endpoint that embeds it.
|
|
396
|
+
"""
|
|
397
|
+
try:
|
|
398
|
+
require_admin()
|
|
399
|
+
return True
|
|
400
|
+
except HTTPException:
|
|
401
|
+
return False
|
|
402
|
+
except Exception:
|
|
403
|
+
logger.warning(
|
|
404
|
+
"is_caller_admin: admin check raised unexpectedly; reporting "
|
|
405
|
+
"non-admin",
|
|
406
|
+
exc_info=True,
|
|
407
|
+
)
|
|
408
|
+
return False
|
|
409
|
+
|
|
410
|
+
|
|
375
411
|
def reset_admin_cache() -> None:
|
|
376
412
|
"""Clear the admin-verdict cache (tests)."""
|
|
377
413
|
_ADMIN_CACHE.clear()
|