databricks-tellr-app 0.4.3.dev11__tar.gz → 0.4.3.dev13__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.3.dev11 → databricks_tellr_app-0.4.3.dev13}/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/pyproject.toml +1 -1
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/main.py +11 -5
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/middleware/security_headers.py +22 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/chat.py +2 -14
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/export.py +4 -4
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/google_slides.py +100 -51
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/sessions.py +4 -84
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/identities.py +3 -3
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/setup.py +2 -2
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/slides.py +13 -13
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/verification.py +3 -3
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/encryption.py +54 -32
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/encryption_key.py +6 -2
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/agent.py +17 -4
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/README.md +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app/run.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/SOURCES.txt +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/requires.txt +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/top_level.txt +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/setup.cfg +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/setup.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/_otel_bootstrap.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/fixtures/tour_demo_deck.json +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/mcp_auth.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/mcp_server.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/middleware/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/middleware/csrf.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/middleware/request_logging.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/_authz.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/admin.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/admin_usage.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/deck_contributors.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/images.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/local_version.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/profiles.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/contributors.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/deck_prompts.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/design_systems.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/slide_styles.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/tools.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/tour.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/version.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/requests.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/responses.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/settings/requests.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/settings/responses.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/streaming.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/chat_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/export_job_queue.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/feedback_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/job_queue.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/session_manager.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/session_naming.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/usage_events.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/usage_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/utils/validation.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/config_loader.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/context_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/database.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/databricks_client.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/init_default_profile.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/lakebase.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/migrate_profiles_to_agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/mlflow_agent_spans.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/mlflow_tracing.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/otel_logging.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/permission_context.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/prompt_modules.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/settings_db.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/user_context.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/deck_contributor.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/design_system.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/genie_space.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/google_global_credentials.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/google_oauth_token.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/identity.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/image.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/profile.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/profile_contributor.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/prompts.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/request_log.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/session.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/slide_deck_prompt.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/slide_style_library.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/usage_event.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/user_preference.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/types.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/domain/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/domain/slide.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/domain/slide_deck.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/agent_factory.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/config_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/config_validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/ast_guard.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/codeprep.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/gslides_runner.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/jail.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/pptx_runner.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/protocol.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/design_system_compiler.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/design_system_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/design_system_templates.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/drive_uploader.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/evaluation/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/evaluation/llm_judge.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/genie_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/google_slides_auth.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/google_slides_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/html_to_google_slides.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/html_to_pptx.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_providers/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_providers/account_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_providers/local_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_providers/workspace_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/image_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/image_tools.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/permission_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/pptx_from_html_huashu.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/pptx_from_records.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/pptx_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/profile_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/streaming_callback.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/agent_bricks_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/ds_asset_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/genie_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/mcp_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/model_endpoint_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/vector_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/css_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/ds_asset_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/error_handling.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/html_safety.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/html_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/image_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/js_validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/logging_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/pi_filter.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/slide_hash.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/spotlight.py +0 -0
- {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/text_caps.py +0 -0
|
@@ -321,14 +321,12 @@ async def user_auth_middleware(request: Request, call_next):
|
|
|
321
321
|
user_name = None
|
|
322
322
|
|
|
323
323
|
if token:
|
|
324
|
-
# Diagnostic logging:
|
|
325
|
-
|
|
324
|
+
# Diagnostic logging: flag SP-vs-user tokens. F-CR-9 (SDR-4437): never log
|
|
325
|
+
# any part of the bearer token (no prefix, no length) — only derived booleans.
|
|
326
326
|
is_sp_token = client_id and token.startswith(client_id)
|
|
327
327
|
logger.debug(
|
|
328
328
|
"OBO auth: extracted token from header",
|
|
329
329
|
extra={
|
|
330
|
-
"token_prefix": token_prefix,
|
|
331
|
-
"token_length": len(token),
|
|
332
330
|
"is_service_principal": is_sp_token,
|
|
333
331
|
"header_present": True,
|
|
334
332
|
},
|
|
@@ -491,11 +489,19 @@ logger.info("MCP server mounted at /mcp")
|
|
|
491
489
|
|
|
492
490
|
@app.get("/api/health")
|
|
493
491
|
async def health():
|
|
494
|
-
"""Health check endpoint.
|
|
492
|
+
"""Health check endpoint.
|
|
493
|
+
|
|
494
|
+
``encryption_key_source`` is load-bearing for deployment: ``tellr.update``
|
|
495
|
+
polls it to confirm a relocated app is reading the secret before it deletes
|
|
496
|
+
the Lakebase key row. Reports the source only — never the key.
|
|
497
|
+
"""
|
|
498
|
+
from src.core.encryption import key_source
|
|
499
|
+
|
|
495
500
|
return {
|
|
496
501
|
"status": "healthy",
|
|
497
502
|
"environment": ENVIRONMENT,
|
|
498
503
|
"version": "0.3.0",
|
|
504
|
+
"encryption_key_source": key_source(),
|
|
499
505
|
}
|
|
500
506
|
|
|
501
507
|
|
|
@@ -31,6 +31,28 @@ Content-Security-Policy differentiated by response type:
|
|
|
31
31
|
'none', no eval) plus the html_safety.py scanner, and any header at
|
|
32
32
|
all is a strict improvement over the previous no-CSP state.
|
|
33
33
|
|
|
34
|
+
SDR-4437 M-CSP — ACCEPTED RESIDUAL (pending SE sign-off). M-CSP asks
|
|
35
|
+
to move ``script-src`` off ``'unsafe-inline'`` to hashes/nonces. That
|
|
36
|
+
is infeasible here and was verified:
|
|
37
|
+
* The SPA's own document has NO inline <script> — index.html loads a
|
|
38
|
+
single external module (``/src/main.tsx``), already covered by
|
|
39
|
+
``'self'``. So the SPA itself does not need 'unsafe-inline'.
|
|
40
|
+
* The 'unsafe-inline' exists ONLY for the srcdoc slide iframes, whose
|
|
41
|
+
generated HTML contains arbitrary inline <script> (Chart.js init,
|
|
42
|
+
etc.) and which inherit THIS document policy in addition to their
|
|
43
|
+
own SLIDE_CSP meta (both enforce; most restrictive wins).
|
|
44
|
+
* Per CSP2+, adding any nonce or hash to ``script-src`` makes the
|
|
45
|
+
browser IGNORE 'unsafe-inline'. A nonce on the parent would
|
|
46
|
+
therefore disable inline execution for the inherited srcdoc slide
|
|
47
|
+
scripts and break slide rendering app-wide — you cannot have
|
|
48
|
+
"nonce + unsafe-inline" both take effect.
|
|
49
|
+
Removing it would require re-architecting slides away from srcdoc
|
|
50
|
+
(backend-served ``src`` iframes), which the frame-ancestors / no-src
|
|
51
|
+
design above deliberately avoids. The residual is bounded: slides stay
|
|
52
|
+
confined by SLIDE_CSP (an egress boundary) + the html_safety scanner,
|
|
53
|
+
and the DOCUMENT_CSP ⊇ SLIDE_CSP superset invariant is locked by
|
|
54
|
+
tests/unit/test_export_csp.py::test_document_csp_header_is_superset_of_slide_csp.
|
|
55
|
+
|
|
34
56
|
- Everything else (JSON APIs, assets, SSE) gets the deny-all
|
|
35
57
|
``API_CSP`` — nothing executes in a JSON response.
|
|
36
58
|
|
{databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/chat.py
RENAMED
|
@@ -384,7 +384,7 @@ async def send_message(
|
|
|
384
384
|
logger.error(f"Chat request failed: {e}", exc_info=True)
|
|
385
385
|
raise HTTPException(
|
|
386
386
|
status_code=500,
|
|
387
|
-
detail=
|
|
387
|
+
detail="Failed to process message",
|
|
388
388
|
) from e
|
|
389
389
|
finally:
|
|
390
390
|
await asyncio.to_thread(
|
|
@@ -543,18 +543,6 @@ async def send_message_streaming(
|
|
|
543
543
|
)
|
|
544
544
|
|
|
545
545
|
|
|
546
|
-
@router.get("/health")
|
|
547
|
-
async def health_check():
|
|
548
|
-
"""Health check endpoint.
|
|
549
|
-
|
|
550
|
-
Returns:
|
|
551
|
-
Status information
|
|
552
|
-
"""
|
|
553
|
-
return {
|
|
554
|
-
"status": "healthy",
|
|
555
|
-
"service": "AI Slide Generator",
|
|
556
|
-
}
|
|
557
|
-
|
|
558
546
|
|
|
559
547
|
@router.post("/chat/async")
|
|
560
548
|
async def submit_chat_async(
|
|
@@ -662,7 +650,7 @@ async def submit_chat_async(
|
|
|
662
650
|
session_manager.release_session_lock, request.session_id
|
|
663
651
|
)
|
|
664
652
|
logger.error(f"Failed to submit async chat: {e}")
|
|
665
|
-
raise HTTPException(status_code=500, detail=
|
|
653
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
666
654
|
|
|
667
655
|
|
|
668
656
|
@router.get("/chat/poll/{request_id}")
|
{databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/export.py
RENAMED
|
@@ -754,13 +754,13 @@ async def export_to_pptx(request: ExportPPTXRequest):
|
|
|
754
754
|
temp_dir.rmdir()
|
|
755
755
|
except Exception:
|
|
756
756
|
pass
|
|
757
|
-
raise HTTPException(status_code=500, detail=
|
|
757
|
+
raise HTTPException(status_code=500, detail="Export failed")
|
|
758
758
|
|
|
759
759
|
except HTTPException:
|
|
760
760
|
raise
|
|
761
761
|
except Exception as e:
|
|
762
762
|
logger.error("PPTX export failed", exc_info=True, extra={"error": str(e)})
|
|
763
|
-
raise HTTPException(status_code=500, detail=
|
|
763
|
+
raise HTTPException(status_code=500, detail="Export failed")
|
|
764
764
|
|
|
765
765
|
|
|
766
766
|
# =============================================================================
|
|
@@ -893,7 +893,7 @@ async def start_pptx_export_async(request: ExportPPTXRequest):
|
|
|
893
893
|
except Exception as e:
|
|
894
894
|
total_time = time.time() - start_time
|
|
895
895
|
logger.error(f"Failed to start async export after {total_time:.2f}s: {e}", exc_info=True)
|
|
896
|
-
raise HTTPException(status_code=500, detail=
|
|
896
|
+
raise HTTPException(status_code=500, detail="Failed to start export")
|
|
897
897
|
|
|
898
898
|
|
|
899
899
|
@router.get("/pptx/poll/{job_id}", response_model=ExportJobResponse)
|
|
@@ -1038,7 +1038,7 @@ async def export_pptx_editable_from_records(request: ExportPPTXFromRecordsReques
|
|
|
1038
1038
|
pptx_bytes = build_pptx(title, request.slides, font_mode=font_mode)
|
|
1039
1039
|
except Exception as e:
|
|
1040
1040
|
logger.exception(f"Editable PPTX emission failed: {e}")
|
|
1041
|
-
raise HTTPException(status_code=500, detail=
|
|
1041
|
+
raise HTTPException(status_code=500, detail="Editable PPTX export failed")
|
|
1042
1042
|
|
|
1043
1043
|
safe = "".join(c if c.isalnum() or c in "-_" else "_" for c in title).strip("_") or "slides"
|
|
1044
1044
|
from fastapi.responses import Response
|
|
@@ -10,9 +10,10 @@ user tokens are stored per-user in the ``google_oauth_tokens`` table.
|
|
|
10
10
|
import json
|
|
11
11
|
import logging
|
|
12
12
|
import os
|
|
13
|
+
import secrets
|
|
13
14
|
from typing import Any, Optional
|
|
14
15
|
|
|
15
|
-
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
|
16
|
+
from fastapi import APIRouter, Depends, HTTPException, Query, Request, Response
|
|
16
17
|
from fastapi.responses import HTMLResponse
|
|
17
18
|
from pydantic import BaseModel
|
|
18
19
|
from sqlalchemy.orm import Session
|
|
@@ -33,6 +34,12 @@ logger = logging.getLogger(__name__)
|
|
|
33
34
|
|
|
34
35
|
router = APIRouter(prefix="/api/export/google-slides", tags=["google-slides"])
|
|
35
36
|
|
|
37
|
+
# F-CR-3 (SDR-4437): the OAuth "state" carries an unguessable nonce that is also
|
|
38
|
+
# stored in this short-lived cookie; the callback requires them to match before
|
|
39
|
+
# exchanging the authorization code (anti-CSRF / anti-login-CSRF double-submit).
|
|
40
|
+
_OAUTH_STATE_COOKIE = "g_oauth_state"
|
|
41
|
+
_OAUTH_COOKIE_PATH = "/api/export/google-slides"
|
|
42
|
+
|
|
36
43
|
|
|
37
44
|
# -------------------------------------------------------------------------
|
|
38
45
|
# Helpers
|
|
@@ -98,32 +105,76 @@ class AuthUrlResponse(BaseModel):
|
|
|
98
105
|
# -------------------------------------------------------------------------
|
|
99
106
|
|
|
100
107
|
|
|
101
|
-
def
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
Google requires redirect URIs to match *exactly* what's registered in GCP,
|
|
105
|
-
with no query parameters.
|
|
108
|
+
def _build_app_origin(request: Request) -> str:
|
|
109
|
+
"""Return the public origin (``scheme://host``) serving the app.
|
|
106
110
|
|
|
107
111
|
Behind a reverse proxy (e.g. Databricks Apps), ``request.base_url``
|
|
108
112
|
returns the internal address (``http://localhost:8000``). We use the
|
|
109
113
|
``X-Forwarded-Host`` / ``X-Forwarded-Proto`` headers set by the proxy
|
|
110
|
-
to reconstruct the public URL instead.
|
|
111
|
-
|
|
112
|
-
For localhost, Google only allows ``http``.
|
|
114
|
+
to reconstruct the public URL instead. For localhost, force ``http``.
|
|
113
115
|
"""
|
|
114
116
|
forwarded_host = request.headers.get("x-forwarded-host")
|
|
115
117
|
forwarded_proto = request.headers.get("x-forwarded-proto")
|
|
116
118
|
|
|
117
119
|
if forwarded_host:
|
|
118
120
|
scheme = forwarded_proto or "https"
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
return f"{scheme}://{forwarded_host.split(',')[0].strip()}"
|
|
122
|
+
|
|
123
|
+
base = str(request.base_url).rstrip("/")
|
|
124
|
+
if "://localhost" in base or "://127.0.0.1" in base:
|
|
125
|
+
base = base.replace("https://", "http://")
|
|
126
|
+
return base
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _build_redirect_uri(request: Request) -> str:
|
|
130
|
+
"""Build the OAuth callback redirect URI from the current request.
|
|
131
|
+
|
|
132
|
+
Google requires redirect URIs to match *exactly* what's registered in GCP,
|
|
133
|
+
with no query parameters.
|
|
134
|
+
"""
|
|
135
|
+
return f"{_build_app_origin(request)}/api/export/google-slides/auth/callback"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# Callback page template. The JS object braces are intentionally literal; the
|
|
139
|
+
# %TOKENS% are substituted below so the postMessage targets the explicit app
|
|
140
|
+
# origin (F-CR-3) instead of the wildcard '*'.
|
|
141
|
+
_CALLBACK_TEMPLATE = """
|
|
142
|
+
<html><body>
|
|
143
|
+
<h2>%TITLE%</h2>
|
|
144
|
+
<p>%MESSAGE%</p>
|
|
145
|
+
<script>
|
|
146
|
+
if (window.opener) {
|
|
147
|
+
window.opener.postMessage({ type: 'google-slides-auth', success: %SUCCESS% }, %ORIGIN%);
|
|
148
|
+
}
|
|
149
|
+
setTimeout(() => window.close(), %DELAY%);
|
|
150
|
+
</script>
|
|
151
|
+
</body></html>
|
|
152
|
+
"""
|
|
125
153
|
|
|
126
|
-
|
|
154
|
+
|
|
155
|
+
def _callback_response(app_origin: str, *, success: bool) -> HTMLResponse:
|
|
156
|
+
"""Render the popup callback page and clear the anti-CSRF state cookie.
|
|
157
|
+
|
|
158
|
+
``postMessage`` targets ``app_origin`` explicitly (F-CR-3); ``json.dumps``
|
|
159
|
+
yields a safely-quoted JS string literal for the origin.
|
|
160
|
+
"""
|
|
161
|
+
if success:
|
|
162
|
+
title, message, delay = "Authorization Successful", "You can close this window.", "1500"
|
|
163
|
+
else:
|
|
164
|
+
title = "Authorization Failed"
|
|
165
|
+
message = "Authorization could not be completed. Please close this window and try again."
|
|
166
|
+
delay = "3000"
|
|
167
|
+
body = (
|
|
168
|
+
_CALLBACK_TEMPLATE
|
|
169
|
+
.replace("%TITLE%", title)
|
|
170
|
+
.replace("%MESSAGE%", message)
|
|
171
|
+
.replace("%SUCCESS%", "true" if success else "false")
|
|
172
|
+
.replace("%ORIGIN%", json.dumps(app_origin))
|
|
173
|
+
.replace("%DELAY%", delay)
|
|
174
|
+
)
|
|
175
|
+
resp = HTMLResponse(content=body, status_code=200)
|
|
176
|
+
resp.delete_cookie(_OAUTH_STATE_COOKIE, path=_OAUTH_COOKIE_PATH)
|
|
177
|
+
return resp
|
|
127
178
|
|
|
128
179
|
|
|
129
180
|
@router.get("/auth/status", response_model=AuthStatusResponse)
|
|
@@ -141,6 +192,7 @@ async def auth_status(db: Session = Depends(get_db)):
|
|
|
141
192
|
@router.get("/auth/url", response_model=AuthUrlResponse)
|
|
142
193
|
async def auth_url(
|
|
143
194
|
request: Request,
|
|
195
|
+
response: Response,
|
|
144
196
|
db: Session = Depends(get_db),
|
|
145
197
|
):
|
|
146
198
|
"""Generate the Google OAuth consent URL.
|
|
@@ -149,13 +201,26 @@ async def auth_url(
|
|
|
149
201
|
passed via the OAuth ``state`` parameter so the callback can persist the
|
|
150
202
|
token for the correct user — the redirect URI itself stays clean
|
|
151
203
|
(no query params) to satisfy Google's exact-match requirement.
|
|
204
|
+
|
|
205
|
+
F-CR-3: an unguessable nonce is bound into both the ``state`` and a
|
|
206
|
+
short-lived cookie; the callback requires them to match.
|
|
152
207
|
"""
|
|
153
208
|
try:
|
|
154
209
|
auth = _get_auth(db)
|
|
155
210
|
redirect_uri = _build_redirect_uri(request)
|
|
156
|
-
|
|
211
|
+
nonce = secrets.token_urlsafe(32)
|
|
212
|
+
state = json.dumps({"user": _get_user_identity(), "nonce": nonce})
|
|
157
213
|
url = auth.get_auth_url(redirect_uri=redirect_uri, state=state)
|
|
158
214
|
|
|
215
|
+
response.set_cookie(
|
|
216
|
+
key=_OAUTH_STATE_COOKIE,
|
|
217
|
+
value=nonce,
|
|
218
|
+
max_age=600,
|
|
219
|
+
httponly=True,
|
|
220
|
+
secure=True,
|
|
221
|
+
samesite="lax", # sent on Google's top-level redirect back to us
|
|
222
|
+
path=_OAUTH_COOKIE_PATH,
|
|
223
|
+
)
|
|
159
224
|
return AuthUrlResponse(url=url)
|
|
160
225
|
except GoogleSlidesAuthError as exc:
|
|
161
226
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
@@ -184,12 +249,22 @@ async def auth_callback(
|
|
|
184
249
|
them in the ``google_oauth_tokens`` table. Returns a small HTML page
|
|
185
250
|
that notifies the opener window and closes itself.
|
|
186
251
|
"""
|
|
252
|
+
app_origin = _build_app_origin(request)
|
|
253
|
+
cookie_nonce = request.cookies.get(_OAUTH_STATE_COOKIE)
|
|
187
254
|
try:
|
|
188
255
|
state_data = json.loads(state) if state else {}
|
|
189
256
|
user = state_data.get("user")
|
|
190
257
|
if not user:
|
|
191
258
|
raise ValueError("Missing user in OAuth state")
|
|
192
259
|
|
|
260
|
+
# F-CR-3: verify the anti-CSRF nonce BEFORE exchanging the code. The
|
|
261
|
+
# state nonce must match the cookie set when the auth URL was issued.
|
|
262
|
+
state_nonce = state_data.get("nonce")
|
|
263
|
+
if not cookie_nonce or not state_nonce or not secrets.compare_digest(
|
|
264
|
+
str(cookie_nonce), str(state_nonce)
|
|
265
|
+
):
|
|
266
|
+
raise ValueError("OAuth state nonce mismatch")
|
|
267
|
+
|
|
193
268
|
auth = _get_auth(db)
|
|
194
269
|
redirect_uri = _build_redirect_uri(request)
|
|
195
270
|
code_verifier = state_data.get("code_verifier")
|
|
@@ -198,39 +273,13 @@ async def auth_callback(
|
|
|
198
273
|
"Google Slides OAuth callback successful",
|
|
199
274
|
extra={"user": _get_user_identity()},
|
|
200
275
|
)
|
|
201
|
-
except Exception
|
|
276
|
+
except Exception:
|
|
277
|
+
# F-CR-2 (SDR-4437): never reflect the raw exception into the HTML page —
|
|
278
|
+
# it is logged server-side above. Show a static, generic failure message.
|
|
202
279
|
logger.error("OAuth callback failed", exc_info=True)
|
|
203
|
-
return
|
|
204
|
-
content=f"""
|
|
205
|
-
<html><body>
|
|
206
|
-
<h2>Authorization Failed</h2>
|
|
207
|
-
<p>{exc}</p>
|
|
208
|
-
<script>
|
|
209
|
-
if (window.opener) {{
|
|
210
|
-
window.opener.postMessage({{ type: 'google-slides-auth', success: false }}, '*');
|
|
211
|
-
}}
|
|
212
|
-
setTimeout(() => window.close(), 3000);
|
|
213
|
-
</script>
|
|
214
|
-
</body></html>
|
|
215
|
-
""",
|
|
216
|
-
status_code=200,
|
|
217
|
-
)
|
|
280
|
+
return _callback_response(app_origin, success=False)
|
|
218
281
|
|
|
219
|
-
return
|
|
220
|
-
content="""
|
|
221
|
-
<html><body>
|
|
222
|
-
<h2>Authorization Successful</h2>
|
|
223
|
-
<p>You can close this window.</p>
|
|
224
|
-
<script>
|
|
225
|
-
if (window.opener) {
|
|
226
|
-
window.opener.postMessage({ type: 'google-slides-auth', success: true }, '*');
|
|
227
|
-
}
|
|
228
|
-
setTimeout(() => window.close(), 1500);
|
|
229
|
-
</script>
|
|
230
|
-
</body></html>
|
|
231
|
-
""",
|
|
232
|
-
status_code=200,
|
|
233
|
-
)
|
|
282
|
+
return _callback_response(app_origin, success=True)
|
|
234
283
|
|
|
235
284
|
|
|
236
285
|
# -------------------------------------------------------------------------
|
|
@@ -284,7 +333,7 @@ async def start_google_slides_export(
|
|
|
284
333
|
slide_deck = chat_service.get_slides(request_body.session_id)
|
|
285
334
|
except Exception as exc:
|
|
286
335
|
logger.error("Failed to fetch slides", exc_info=True)
|
|
287
|
-
raise HTTPException(status_code=500, detail=
|
|
336
|
+
raise HTTPException(status_code=500, detail="Failed to fetch slides") from exc
|
|
288
337
|
|
|
289
338
|
if not slide_deck or not slide_deck.get("slides"):
|
|
290
339
|
raise HTTPException(status_code=404, detail="No slides available")
|
|
@@ -448,7 +497,7 @@ async def export_google_slides_from_records(
|
|
|
448
497
|
)
|
|
449
498
|
except Exception as exc:
|
|
450
499
|
logger.error("Drive upload failed", exc_info=True)
|
|
451
|
-
raise HTTPException(status_code=502, detail=
|
|
500
|
+
raise HTTPException(status_code=502, detail="Drive upload failed") from exc
|
|
452
501
|
|
|
453
502
|
session_manager.set_google_slides_info(
|
|
454
503
|
session_id=request.session_id,
|
|
@@ -598,7 +647,7 @@ async def export_google_slides_from_huashu(
|
|
|
598
647
|
logger.error("Drive upload failed (huashu path)", exc_info=True)
|
|
599
648
|
raise HTTPException(
|
|
600
649
|
status_code=502,
|
|
601
|
-
detail=
|
|
650
|
+
detail="Drive upload failed",
|
|
602
651
|
) from exc
|
|
603
652
|
|
|
604
653
|
session_manager.set_google_slides_info(
|
{databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/sessions.py
RENAMED
|
@@ -9,10 +9,7 @@ Session access is controlled by:
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import asyncio
|
|
12
|
-
import json
|
|
13
12
|
import logging
|
|
14
|
-
from datetime import datetime
|
|
15
|
-
from pathlib import Path
|
|
16
13
|
from typing import Optional
|
|
17
14
|
|
|
18
15
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
@@ -553,7 +550,7 @@ async def duplicate_session(
|
|
|
553
550
|
logger.error(f"Failed to duplicate session: {e}", exc_info=True)
|
|
554
551
|
raise HTTPException(
|
|
555
552
|
status_code=500,
|
|
556
|
-
detail=
|
|
553
|
+
detail="Failed to duplicate session",
|
|
557
554
|
) from e
|
|
558
555
|
|
|
559
556
|
|
|
@@ -769,86 +766,9 @@ async def cleanup_expired_sessions():
|
|
|
769
766
|
) from e
|
|
770
767
|
|
|
771
768
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
Exports:
|
|
777
|
-
- Session info (id, timestamps, profile)
|
|
778
|
-
- All chat messages (user + AI responses with full content)
|
|
779
|
-
- Full slide deck (HTML, scripts, slide count)
|
|
780
|
-
|
|
781
|
-
Args:
|
|
782
|
-
session_id: Session to export
|
|
783
|
-
|
|
784
|
-
Returns:
|
|
785
|
-
Export confirmation with file path
|
|
786
|
-
"""
|
|
787
|
-
try:
|
|
788
|
-
# Permission check: require CAN_VIEW on the deck
|
|
789
|
-
await asyncio.to_thread(
|
|
790
|
-
_check_deck_permission_for_session, session_id, PermissionLevel.CAN_VIEW
|
|
791
|
-
)
|
|
792
|
-
|
|
793
|
-
session_manager = get_session_manager()
|
|
794
|
-
|
|
795
|
-
# Get all session data
|
|
796
|
-
session = await asyncio.to_thread(session_manager.get_session, session_id)
|
|
797
|
-
messages = await asyncio.to_thread(session_manager.get_messages, session_id)
|
|
798
|
-
slide_deck = await asyncio.to_thread(session_manager.get_slide_deck, session_id)
|
|
799
|
-
|
|
800
|
-
# Build export data
|
|
801
|
-
export_data = {
|
|
802
|
-
"exported_at": datetime.utcnow().isoformat(),
|
|
803
|
-
"session": session,
|
|
804
|
-
"messages": messages,
|
|
805
|
-
"slide_deck": slide_deck,
|
|
806
|
-
"summary": {
|
|
807
|
-
"message_count": len(messages),
|
|
808
|
-
"slide_count": slide_deck.get("slide_count", 0) if slide_deck else 0,
|
|
809
|
-
"user_messages": sum(1 for m in messages if m.get("role") == "user"),
|
|
810
|
-
"ai_messages": sum(1 for m in messages if m.get("role") == "assistant"),
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
# Ensure logs/sessions directory exists
|
|
815
|
-
sessions_dir = Path("logs/sessions")
|
|
816
|
-
sessions_dir.mkdir(parents=True, exist_ok=True)
|
|
817
|
-
|
|
818
|
-
# Write to file
|
|
819
|
-
export_path = sessions_dir / f"{session_id}.json"
|
|
820
|
-
with open(export_path, "w", encoding="utf-8") as f:
|
|
821
|
-
json.dump(export_data, f, indent=2, default=str)
|
|
822
|
-
|
|
823
|
-
logger.info(
|
|
824
|
-
"Session exported",
|
|
825
|
-
extra={
|
|
826
|
-
"session_id": session_id,
|
|
827
|
-
"export_path": str(export_path),
|
|
828
|
-
"message_count": len(messages),
|
|
829
|
-
},
|
|
830
|
-
)
|
|
831
|
-
|
|
832
|
-
return {
|
|
833
|
-
"status": "exported",
|
|
834
|
-
"session_id": session_id,
|
|
835
|
-
"export_path": str(export_path),
|
|
836
|
-
"summary": export_data["summary"],
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
except SessionNotFoundError:
|
|
840
|
-
raise HTTPException(
|
|
841
|
-
status_code=404,
|
|
842
|
-
detail=f"Session not found: {session_id}",
|
|
843
|
-
)
|
|
844
|
-
except HTTPException:
|
|
845
|
-
raise
|
|
846
|
-
except Exception as e:
|
|
847
|
-
logger.error(f"Failed to export session: {e}", exc_info=True)
|
|
848
|
-
raise HTTPException(
|
|
849
|
-
status_code=500,
|
|
850
|
-
detail="Export failed",
|
|
851
|
-
) from e
|
|
769
|
+
# F-CR-10 (SDR-4437): the debug-only POST /{session_id}/export endpoint was
|
|
770
|
+
# removed — it was unused by the frontend and dumped full session data (all chat
|
|
771
|
+
# messages + deck) to logs/sessions/{id}.json.
|
|
852
772
|
|
|
853
773
|
|
|
854
774
|
# =========================================================================
|
|
@@ -109,7 +109,7 @@ def list_users(
|
|
|
109
109
|
logger.error(f"Failed to list users: {e}", exc_info=True)
|
|
110
110
|
raise HTTPException(
|
|
111
111
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
112
|
-
detail=
|
|
112
|
+
detail="Failed to list users",
|
|
113
113
|
)
|
|
114
114
|
|
|
115
115
|
|
|
@@ -149,7 +149,7 @@ def list_groups(
|
|
|
149
149
|
logger.error(f"Failed to list groups: {e}", exc_info=True)
|
|
150
150
|
raise HTTPException(
|
|
151
151
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
152
|
-
detail=
|
|
152
|
+
detail="Failed to list groups",
|
|
153
153
|
)
|
|
154
154
|
|
|
155
155
|
|
|
@@ -203,5 +203,5 @@ def search_identities(
|
|
|
203
203
|
logger.error(f"Failed to search identities: {e}", exc_info=True)
|
|
204
204
|
raise HTTPException(
|
|
205
205
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
206
|
-
detail=
|
|
206
|
+
detail="Failed to search identities",
|
|
207
207
|
)
|
{databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/setup.py
RENAMED
|
@@ -123,7 +123,7 @@ async def configure_workspace(request: ConfigureWorkspaceRequest):
|
|
|
123
123
|
logger.error(f"Failed to configure workspace: {e}")
|
|
124
124
|
raise HTTPException(
|
|
125
125
|
status_code=500,
|
|
126
|
-
detail=
|
|
126
|
+
detail="Failed to save configuration"
|
|
127
127
|
)
|
|
128
128
|
|
|
129
129
|
|
|
@@ -154,5 +154,5 @@ async def test_connection():
|
|
|
154
154
|
logger.error(f"Connection test failed: {e}")
|
|
155
155
|
raise HTTPException(
|
|
156
156
|
status_code=400,
|
|
157
|
-
detail=
|
|
157
|
+
detail="Connection failed"
|
|
158
158
|
)
|