databricks-tellr-app 0.4.2.dev3__tar.gz → 0.4.2.dev5__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.dev3 → databricks_tellr_app-0.4.2.dev5}/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/databricks_tellr_app.egg-info/SOURCES.txt +2 -16
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/pyproject.toml +1 -1
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/main.py +2 -17
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/mcp_server.py +12 -153
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/_authz.py +0 -36
- databricks_tellr_app-0.4.2.dev5/src/api/routes/agent_config.py +168 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/chat.py +10 -122
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/export.py +3 -18
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/google_slides.py +2 -21
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/profiles.py +7 -31
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/sessions.py +21 -30
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/settings/__init__.py +0 -2
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/slides.py +4 -4
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/verification.py +20 -41
- databricks_tellr_app-0.4.2.dev5/src/api/schemas/agent_config.py +116 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/services/chat_service.py +17 -180
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/services/export_job_queue.py +2 -7
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/services/session_manager.py +799 -65
- databricks_tellr_app-0.4.2.dev5/src/api/services/session_naming.py +61 -0
- databricks_tellr_app-0.4.2.dev5/src/api/services/slide_repository.py +378 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/database.py +67 -432
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/prompt_modules.py +3 -67
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/settings_db.py +1 -45
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/__init__.py +1 -12
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/profile.py +3 -6
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/session.py +90 -6
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/agent_factory.py +5 -132
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/tools/__init__.py +0 -4
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/html_safety.py +0 -18
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/image_utils.py +6 -21
- databricks_tellr_app-0.4.2.dev3/src/api/routes/agent_config.py +0 -310
- databricks_tellr_app-0.4.2.dev3/src/api/routes/settings/design_systems.py +0 -1289
- databricks_tellr_app-0.4.2.dev3/src/api/schemas/agent_config.py +0 -333
- databricks_tellr_app-0.4.2.dev3/src/api/services/session_naming.py +0 -134
- databricks_tellr_app-0.4.2.dev3/src/database/models/design_system.py +0 -426
- databricks_tellr_app-0.4.2.dev3/src/database/types.py +0 -155
- databricks_tellr_app-0.4.2.dev3/src/services/design_system_compiler.py +0 -2222
- databricks_tellr_app-0.4.2.dev3/src/services/design_system_service.py +0 -1315
- databricks_tellr_app-0.4.2.dev3/src/services/design_system_templates.py +0 -940
- databricks_tellr_app-0.4.2.dev3/src/services/tools/ds_asset_tool.py +0 -105
- databricks_tellr_app-0.4.2.dev3/src/utils/ds_asset_utils.py +0 -98
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/README.md +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/databricks_tellr_app/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/databricks_tellr_app/run.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/databricks_tellr_app.egg-info/requires.txt +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/databricks_tellr_app.egg-info/top_level.txt +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/setup.cfg +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/setup.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/_otel_bootstrap.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/fixtures/tour_demo_deck.json +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/mcp_auth.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/middleware/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/middleware/csrf.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/middleware/request_logging.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/middleware/security_headers.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/admin.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/admin_usage.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/deck_contributors.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/images.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/local_version.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/settings/contributors.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/settings/deck_prompts.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/settings/identities.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/settings/slide_styles.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/setup.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/tools.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/tour.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/version.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/schemas/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/schemas/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/schemas/requests.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/schemas/responses.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/schemas/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/schemas/settings/requests.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/schemas/settings/responses.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/schemas/streaming.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/services/feedback_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/services/job_queue.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/services/usage_events.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/services/usage_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/utils/validation.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/config_loader.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/context_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/databricks_client.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/encryption.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/init_default_profile.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/lakebase.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/migrate_profiles_to_agent_config.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/mlflow_agent_spans.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/mlflow_tracing.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/otel_logging.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/permission_context.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/core/user_context.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/deck_contributor.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/encryption_key.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/feedback.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/genie_space.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/google_global_credentials.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/google_oauth_token.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/identity.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/image.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/profile_contributor.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/prompts.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/request_log.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/slide_deck_prompt.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/slide_style_library.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/usage_event.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/database/models/user_preference.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/domain/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/domain/slide.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/domain/slide_deck.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/agent.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/config_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/config_validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/converter_jail/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/converter_jail/ast_guard.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/converter_jail/codeprep.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/converter_jail/gslides_runner.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/converter_jail/jail.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/converter_jail/pptx_runner.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/converter_jail/protocol.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/drive_uploader.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/evaluation/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/evaluation/llm_judge.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/genie_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/google_slides_auth.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/google_slides_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/html_to_google_slides.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/html_to_pptx.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/identity_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/identity_providers/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/identity_providers/account_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/identity_providers/local_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/identity_providers/workspace_provider.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/image_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/image_tools.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/permission_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/pptx_from_html_huashu.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/pptx_from_records.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/pptx_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/profile_service.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/streaming_callback.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/tools/agent_bricks_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/tools/genie_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/tools/mcp_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/tools/model_endpoint_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/tools/vector_tool.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/services/validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/css_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/error_handling.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/html_utils.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/js_validator.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/logging_config.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/pi_filter.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/slide_hash.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/spotlight.py +0 -0
- {databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/utils/text_caps.py +0 -0
|
@@ -37,7 +37,6 @@ 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
|
|
41
40
|
./src/api/routes/settings/identities.py
|
|
42
41
|
./src/api/routes/settings/slide_styles.py
|
|
43
42
|
./src/api/schemas/__init__.py
|
|
@@ -56,6 +55,7 @@ setup.py
|
|
|
56
55
|
./src/api/services/job_queue.py
|
|
57
56
|
./src/api/services/session_manager.py
|
|
58
57
|
./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
|
|
@@ -78,10 +78,8 @@ setup.py
|
|
|
78
78
|
./src/core/settings_db.py
|
|
79
79
|
./src/core/user_context.py
|
|
80
80
|
./src/database/__init__.py
|
|
81
|
-
./src/database/types.py
|
|
82
81
|
./src/database/models/__init__.py
|
|
83
82
|
./src/database/models/deck_contributor.py
|
|
84
|
-
./src/database/models/design_system.py
|
|
85
83
|
./src/database/models/encryption_key.py
|
|
86
84
|
./src/database/models/feedback.py
|
|
87
85
|
./src/database/models/genie_space.py
|
|
@@ -106,9 +104,6 @@ setup.py
|
|
|
106
104
|
./src/services/agent_factory.py
|
|
107
105
|
./src/services/config_service.py
|
|
108
106
|
./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
|
|
112
107
|
./src/services/drive_uploader.py
|
|
113
108
|
./src/services/genie_service.py
|
|
114
109
|
./src/services/google_slides_auth.py
|
|
@@ -140,14 +135,12 @@ setup.py
|
|
|
140
135
|
./src/services/identity_providers/workspace_provider.py
|
|
141
136
|
./src/services/tools/__init__.py
|
|
142
137
|
./src/services/tools/agent_bricks_tool.py
|
|
143
|
-
./src/services/tools/ds_asset_tool.py
|
|
144
138
|
./src/services/tools/genie_tool.py
|
|
145
139
|
./src/services/tools/mcp_tool.py
|
|
146
140
|
./src/services/tools/model_endpoint_tool.py
|
|
147
141
|
./src/services/tools/vector_tool.py
|
|
148
142
|
./src/utils/__init__.py
|
|
149
143
|
./src/utils/css_utils.py
|
|
150
|
-
./src/utils/ds_asset_utils.py
|
|
151
144
|
./src/utils/error_handling.py
|
|
152
145
|
./src/utils/html_safety.py
|
|
153
146
|
./src/utils/html_utils.py
|
|
@@ -199,7 +192,6 @@ src/api/routes/version.py
|
|
|
199
192
|
src/api/routes/settings/__init__.py
|
|
200
193
|
src/api/routes/settings/contributors.py
|
|
201
194
|
src/api/routes/settings/deck_prompts.py
|
|
202
|
-
src/api/routes/settings/design_systems.py
|
|
203
195
|
src/api/routes/settings/identities.py
|
|
204
196
|
src/api/routes/settings/slide_styles.py
|
|
205
197
|
src/api/schemas/__init__.py
|
|
@@ -218,6 +210,7 @@ src/api/services/feedback_service.py
|
|
|
218
210
|
src/api/services/job_queue.py
|
|
219
211
|
src/api/services/session_manager.py
|
|
220
212
|
src/api/services/session_naming.py
|
|
213
|
+
src/api/services/slide_repository.py
|
|
221
214
|
src/api/services/usage_events.py
|
|
222
215
|
src/api/services/usage_service.py
|
|
223
216
|
src/api/utils/__init__.py
|
|
@@ -240,10 +233,8 @@ src/core/prompt_modules.py
|
|
|
240
233
|
src/core/settings_db.py
|
|
241
234
|
src/core/user_context.py
|
|
242
235
|
src/database/__init__.py
|
|
243
|
-
src/database/types.py
|
|
244
236
|
src/database/models/__init__.py
|
|
245
237
|
src/database/models/deck_contributor.py
|
|
246
|
-
src/database/models/design_system.py
|
|
247
238
|
src/database/models/encryption_key.py
|
|
248
239
|
src/database/models/feedback.py
|
|
249
240
|
src/database/models/genie_space.py
|
|
@@ -268,9 +259,6 @@ src/services/agent.py
|
|
|
268
259
|
src/services/agent_factory.py
|
|
269
260
|
src/services/config_service.py
|
|
270
261
|
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
|
|
274
262
|
src/services/drive_uploader.py
|
|
275
263
|
src/services/genie_service.py
|
|
276
264
|
src/services/google_slides_auth.py
|
|
@@ -302,14 +290,12 @@ src/services/identity_providers/local_provider.py
|
|
|
302
290
|
src/services/identity_providers/workspace_provider.py
|
|
303
291
|
src/services/tools/__init__.py
|
|
304
292
|
src/services/tools/agent_bricks_tool.py
|
|
305
|
-
src/services/tools/ds_asset_tool.py
|
|
306
293
|
src/services/tools/genie_tool.py
|
|
307
294
|
src/services/tools/mcp_tool.py
|
|
308
295
|
src/services/tools/model_endpoint_tool.py
|
|
309
296
|
src/services/tools/vector_tool.py
|
|
310
297
|
src/utils/__init__.py
|
|
311
298
|
src/utils/css_utils.py
|
|
312
|
-
src/utils/ds_asset_utils.py
|
|
313
299
|
src/utils/error_handling.py
|
|
314
300
|
src/utils/html_safety.py
|
|
315
301
|
src/utils/html_utils.py
|
|
@@ -27,7 +27,6 @@ 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,
|
|
31
30
|
identities_router,
|
|
32
31
|
slide_styles_router,
|
|
33
32
|
)
|
|
@@ -485,7 +484,6 @@ app.include_router(contributors_router, prefix="/api/settings", tags=["settings"
|
|
|
485
484
|
app.include_router(deck_prompts_router, prefix="/api/settings", tags=["settings"])
|
|
486
485
|
app.include_router(identities_router, prefix="/api/settings", tags=["settings"])
|
|
487
486
|
app.include_router(slide_styles_router, prefix="/api/settings", tags=["settings"])
|
|
488
|
-
app.include_router(design_systems_router, prefix="/api/settings", tags=["settings"])
|
|
489
487
|
|
|
490
488
|
# MCP server — mount the FastMCP streamable-HTTP ASGI app at /mcp.
|
|
491
489
|
# Must be registered before the SPA catch-all (which is added lazily by
|
|
@@ -526,27 +524,16 @@ async def get_current_user():
|
|
|
526
524
|
|
|
527
525
|
Also includes the user's Databricks ID and group IDs from the permission
|
|
528
526
|
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.
|
|
535
527
|
"""
|
|
536
|
-
from src.api.routes._authz import is_caller_admin
|
|
537
528
|
from src.core.permission_context import get_permission_context
|
|
538
|
-
|
|
529
|
+
|
|
539
530
|
ctx_user = get_ctx_user()
|
|
540
531
|
perm_ctx = get_permission_context()
|
|
541
|
-
|
|
542
|
-
# Never raises (fails closed to False), so it cannot break identity resolution.
|
|
543
|
-
is_admin = is_caller_admin()
|
|
544
|
-
|
|
532
|
+
|
|
545
533
|
if ctx_user:
|
|
546
534
|
result = {
|
|
547
535
|
"username": ctx_user,
|
|
548
536
|
"display_name": ctx_user,
|
|
549
|
-
"is_admin": is_admin,
|
|
550
537
|
}
|
|
551
538
|
# Include permission context info if available
|
|
552
539
|
if perm_ctx:
|
|
@@ -564,14 +551,12 @@ async def get_current_user():
|
|
|
564
551
|
"username": user.user_name,
|
|
565
552
|
"display_name": user.display_name or user.user_name,
|
|
566
553
|
"user_id": user.id,
|
|
567
|
-
"is_admin": is_admin,
|
|
568
554
|
}
|
|
569
555
|
except Exception as e:
|
|
570
556
|
logger.warning(f"Failed to get current user: {e}")
|
|
571
557
|
return {
|
|
572
558
|
"username": "user",
|
|
573
559
|
"display_name": "User",
|
|
574
|
-
"is_admin": is_admin,
|
|
575
560
|
}
|
|
576
561
|
|
|
577
562
|
|
|
@@ -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
|
|
31
|
+
from src.core.settings_db import 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,106 +292,6 @@ 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
|
-
|
|
395
295
|
@mcp.tool(
|
|
396
296
|
name="create_deck",
|
|
397
297
|
description=(
|
|
@@ -401,10 +301,7 @@ def _resolve_template_name(design_system_id: int, template_name: str) -> Optiona
|
|
|
401
301
|
"appears in their tellr UI. v1 runs prompt-only: the agent does not "
|
|
402
302
|
"invoke Genie, Vector Search, or other tools. Callers that want data-"
|
|
403
303
|
"backed decks should gather the data themselves and include it in the "
|
|
404
|
-
"prompt.
|
|
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)."
|
|
304
|
+
"prompt."
|
|
408
305
|
),
|
|
409
306
|
)
|
|
410
307
|
async def create_deck(
|
|
@@ -412,8 +309,6 @@ async def create_deck(
|
|
|
412
309
|
prompt: str,
|
|
413
310
|
num_slides: Optional[int] = None,
|
|
414
311
|
slide_style_id: Optional[int] = None,
|
|
415
|
-
design_system_id: Optional[int] = None,
|
|
416
|
-
template_name: Optional[str] = None,
|
|
417
312
|
deck_prompt_id: Optional[int] = None,
|
|
418
313
|
correlation_id: Optional[str] = None,
|
|
419
314
|
) -> dict:
|
|
@@ -422,8 +317,6 @@ async def create_deck(
|
|
|
422
317
|
prompt=prompt,
|
|
423
318
|
num_slides=num_slides,
|
|
424
319
|
slide_style_id=slide_style_id,
|
|
425
|
-
design_system_id=design_system_id,
|
|
426
|
-
template_name=template_name,
|
|
427
320
|
deck_prompt_id=deck_prompt_id,
|
|
428
321
|
correlation_id=correlation_id,
|
|
429
322
|
)
|
|
@@ -434,8 +327,6 @@ async def _create_deck_impl(
|
|
|
434
327
|
prompt: str,
|
|
435
328
|
num_slides: Optional[int] = None,
|
|
436
329
|
slide_style_id: Optional[int] = None,
|
|
437
|
-
design_system_id: Optional[int] = None,
|
|
438
|
-
template_name: Optional[str] = None,
|
|
439
330
|
deck_prompt_id: Optional[int] = None,
|
|
440
331
|
correlation_id: Optional[str] = None,
|
|
441
332
|
) -> dict:
|
|
@@ -461,48 +352,16 @@ async def _create_deck_impl(
|
|
|
461
352
|
try:
|
|
462
353
|
with mcp_auth_scope(request) as identity:
|
|
463
354
|
agent_config: dict[str, Any] = {"tools": []}
|
|
464
|
-
#
|
|
465
|
-
#
|
|
466
|
-
#
|
|
467
|
-
#
|
|
468
|
-
#
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
if
|
|
473
|
-
|
|
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
|
-
)
|
|
355
|
+
# Mirror the browser chat flow: if the caller didn't specify a
|
|
356
|
+
# style, fall back to the tellr-configured default
|
|
357
|
+
# (slide_style_library.is_default=True) rather than the
|
|
358
|
+
# hardcoded DEFAULT_SLIDE_STYLE constant that agent_factory
|
|
359
|
+
# uses when agent_config.slide_style_id is absent.
|
|
360
|
+
effective_style_id = slide_style_id
|
|
361
|
+
if effective_style_id is None:
|
|
362
|
+
effective_style_id = get_default_slide_style_id()
|
|
363
|
+
if effective_style_id is not None:
|
|
364
|
+
agent_config["slide_style_id"] = effective_style_id
|
|
506
365
|
if deck_prompt_id is not None:
|
|
507
366
|
agent_config["deck_prompt_id"] = deck_prompt_id
|
|
508
367
|
if num_slides is not None:
|
{databricks_tellr_app-0.4.2.dev3 → databricks_tellr_app-0.4.2.dev5}/src/api/routes/_authz.py
RENAMED
|
@@ -372,42 +372,6 @@ 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
|
-
|
|
411
375
|
def reset_admin_cache() -> None:
|
|
412
376
|
"""Clear the admin-verdict cache (tests)."""
|
|
413
377
|
_ADMIN_CACHE.clear()
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""REST endpoints for reading and updating a session's agent configuration."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from fastapi import APIRouter, HTTPException
|
|
8
|
+
from pydantic import BaseModel, Field, ValidationError
|
|
9
|
+
|
|
10
|
+
from src.api.routes._authz import _check_deck_permission_for_session
|
|
11
|
+
from src.api.schemas.agent_config import AgentConfig, ToolEntry, resolve_agent_config
|
|
12
|
+
from src.api.services.session_manager import SessionNotFoundError, get_session_manager
|
|
13
|
+
from src.core.database import get_db_session
|
|
14
|
+
from src.database.models import UserSession
|
|
15
|
+
from src.database.models.profile_contributor import PermissionLevel
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
router = APIRouter(prefix="/api/sessions/{session_id}/agent-config", tags=["agent-config"])
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ── helpers ──────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _validate_references(config: AgentConfig) -> None:
|
|
26
|
+
"""Validate that slide_style_id and deck_prompt_id reference existing library entries."""
|
|
27
|
+
from src.database.models import SlideStyleLibrary, SlideDeckPromptLibrary
|
|
28
|
+
|
|
29
|
+
with get_db_session() as db:
|
|
30
|
+
if config.slide_style_id is not None:
|
|
31
|
+
style = (
|
|
32
|
+
db.query(SlideStyleLibrary)
|
|
33
|
+
.filter(
|
|
34
|
+
SlideStyleLibrary.id == config.slide_style_id,
|
|
35
|
+
SlideStyleLibrary.is_active == True, # noqa: E712
|
|
36
|
+
)
|
|
37
|
+
.first()
|
|
38
|
+
)
|
|
39
|
+
if not style:
|
|
40
|
+
raise HTTPException(
|
|
41
|
+
status_code=422,
|
|
42
|
+
detail=f"slide_style_id {config.slide_style_id} not found",
|
|
43
|
+
)
|
|
44
|
+
if config.deck_prompt_id is not None:
|
|
45
|
+
prompt = (
|
|
46
|
+
db.query(SlideDeckPromptLibrary)
|
|
47
|
+
.filter(
|
|
48
|
+
SlideDeckPromptLibrary.id == config.deck_prompt_id,
|
|
49
|
+
SlideDeckPromptLibrary.is_active == True, # noqa: E712
|
|
50
|
+
)
|
|
51
|
+
.first()
|
|
52
|
+
)
|
|
53
|
+
if not prompt:
|
|
54
|
+
raise HTTPException(
|
|
55
|
+
status_code=422,
|
|
56
|
+
detail=f"deck_prompt_id {config.deck_prompt_id} not found",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _save_agent_config(session_id: str, config: AgentConfig) -> dict:
|
|
61
|
+
"""Persist *config* onto the session row and return its dict representation."""
|
|
62
|
+
with get_db_session() as db:
|
|
63
|
+
session = (
|
|
64
|
+
db.query(UserSession)
|
|
65
|
+
.filter(UserSession.session_id == session_id)
|
|
66
|
+
.first()
|
|
67
|
+
)
|
|
68
|
+
if not session:
|
|
69
|
+
raise SessionNotFoundError(f"Session not found: {session_id}")
|
|
70
|
+
session.agent_config = config.model_dump()
|
|
71
|
+
return config.model_dump()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# ── request schemas ──────────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class PatchToolRequest(BaseModel):
|
|
78
|
+
action: Literal["add", "remove"]
|
|
79
|
+
tool: ToolEntry = Field(...)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# ── routes ───────────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@router.get("")
|
|
86
|
+
async def get_agent_config(session_id: str):
|
|
87
|
+
"""Return the current agent config for a session (defaults if null)."""
|
|
88
|
+
# SDR-4437 HIGH-1: reading a session's agent config requires CAN_VIEW.
|
|
89
|
+
_check_deck_permission_for_session(session_id, PermissionLevel.CAN_VIEW)
|
|
90
|
+
try:
|
|
91
|
+
mgr = get_session_manager()
|
|
92
|
+
session = await asyncio.to_thread(mgr.get_session, session_id)
|
|
93
|
+
except SessionNotFoundError:
|
|
94
|
+
raise HTTPException(status_code=404, detail=f"Session not found: {session_id}")
|
|
95
|
+
|
|
96
|
+
raw = session.get("agent_config")
|
|
97
|
+
config = resolve_agent_config(raw)
|
|
98
|
+
result = config.model_dump()
|
|
99
|
+
result["is_configured"] = raw is not None
|
|
100
|
+
return result
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@router.put("")
|
|
104
|
+
async def put_agent_config(session_id: str, config: AgentConfig):
|
|
105
|
+
"""Replace the full agent config for a session."""
|
|
106
|
+
# SDR-4437 HIGH-1: agent-config writes repoint the session's tools — CAN_MANAGE.
|
|
107
|
+
_check_deck_permission_for_session(session_id, PermissionLevel.CAN_MANAGE)
|
|
108
|
+
# Pydantic already validated duplicates via model_validator.
|
|
109
|
+
# Now validate foreign-key references.
|
|
110
|
+
_validate_references(config)
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
result = await asyncio.to_thread(_save_agent_config, session_id, config)
|
|
114
|
+
except SessionNotFoundError:
|
|
115
|
+
raise HTTPException(status_code=404, detail=f"Session not found: {session_id}")
|
|
116
|
+
|
|
117
|
+
return result
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@router.patch("/tools")
|
|
121
|
+
async def patch_tools(session_id: str, body: PatchToolRequest):
|
|
122
|
+
"""Add or remove a single tool from the session's agent config."""
|
|
123
|
+
# SDR-4437 HIGH-1: agent-config writes repoint the session's tools — CAN_MANAGE.
|
|
124
|
+
_check_deck_permission_for_session(session_id, PermissionLevel.CAN_MANAGE)
|
|
125
|
+
try:
|
|
126
|
+
mgr = get_session_manager()
|
|
127
|
+
session = await asyncio.to_thread(mgr.get_session, session_id)
|
|
128
|
+
except SessionNotFoundError:
|
|
129
|
+
raise HTTPException(status_code=404, detail=f"Session not found: {session_id}")
|
|
130
|
+
|
|
131
|
+
config = resolve_agent_config(session.get("agent_config"))
|
|
132
|
+
|
|
133
|
+
if body.action == "add":
|
|
134
|
+
config.tools.append(body.tool)
|
|
135
|
+
elif body.action == "remove":
|
|
136
|
+
# Match by discriminator key (e.g. genie:space_id, mcp:connection_name)
|
|
137
|
+
from src.api.schemas.agent_config import (
|
|
138
|
+
GenieTool, MCPTool, VectorIndexTool, ModelEndpointTool, AgentBricksTool,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def _key(t):
|
|
142
|
+
if isinstance(t, GenieTool):
|
|
143
|
+
return f"genie:{t.space_id}"
|
|
144
|
+
elif isinstance(t, MCPTool):
|
|
145
|
+
return f"mcp:{t.connection_name}"
|
|
146
|
+
elif isinstance(t, VectorIndexTool):
|
|
147
|
+
return f"vector_index:{t.endpoint_name}:{t.index_name}"
|
|
148
|
+
elif isinstance(t, ModelEndpointTool):
|
|
149
|
+
return f"model_endpoint:{t.endpoint_name}"
|
|
150
|
+
elif isinstance(t, AgentBricksTool):
|
|
151
|
+
return f"agent_bricks:{t.endpoint_name}"
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
remove_key = _key(body.tool)
|
|
155
|
+
config.tools = [t for t in config.tools if _key(t) != remove_key]
|
|
156
|
+
|
|
157
|
+
# Re-validate (catches duplicates on add)
|
|
158
|
+
try:
|
|
159
|
+
config = AgentConfig.model_validate(config.model_dump())
|
|
160
|
+
except ValidationError as exc:
|
|
161
|
+
raise HTTPException(status_code=422, detail=str(exc))
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
result = await asyncio.to_thread(_save_agent_config, session_id, config)
|
|
165
|
+
except SessionNotFoundError:
|
|
166
|
+
raise HTTPException(status_code=404, detail=f"Session not found: {session_id}")
|
|
167
|
+
|
|
168
|
+
return result
|