databricks-tellr-app 0.4.3.dev3462__tar.gz → 0.4.3.dev3463__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.
Files changed (246) hide show
  1. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/PKG-INFO +1 -1
  2. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/databricks_tellr_app/run.py +0 -17
  3. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
  4. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/databricks_tellr_app.egg-info/SOURCES.txt +0 -8
  5. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/pyproject.toml +1 -1
  6. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/main.py +1 -25
  7. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/mcp_server.py +6 -17
  8. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/chat.py +99 -13
  9. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/settings/slide_styles.py +0 -201
  10. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/tour.py +5 -6
  11. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/requests.py +8 -1
  12. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/chat_service.py +40 -130
  13. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/session_manager.py +222 -67
  14. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/database.py +48 -70
  15. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/__init__.py +0 -2
  16. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/session.py +4 -0
  17. databricks_tellr_app-0.4.3.dev3463/src/database/models/slide_style_library.py +47 -0
  18. databricks_tellr_app-0.4.3.dev3463/src/domain/conversation_engine.py +36 -0
  19. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/conversation_pins.py +2 -76
  20. databricks_tellr_app-0.4.3.dev3462/src/api/services/slide_style_preview_queue.py +0 -583
  21. databricks_tellr_app-0.4.3.dev3462/src/database/models/slide_style_library.py +0 -79
  22. databricks_tellr_app-0.4.3.dev3462/src/database/models/slide_style_preview.py +0 -55
  23. databricks_tellr_app-0.4.3.dev3462/src/domain/conversation_engine.py +0 -57
  24. databricks_tellr_app-0.4.3.dev3462/src/services/slide_style_preview_fixture.py +0 -204
  25. databricks_tellr_app-0.4.3.dev3462/src/services/slide_style_preview_storage.py +0 -119
  26. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/README.md +0 -0
  27. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/databricks_tellr_app/__init__.py +0 -0
  28. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
  29. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/databricks_tellr_app.egg-info/requires.txt +0 -0
  30. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/databricks_tellr_app.egg-info/top_level.txt +0 -0
  31. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/setup.cfg +0 -0
  32. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/setup.py +0 -0
  33. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/__init__.py +0 -0
  34. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/__init__.py +0 -0
  35. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/_otel_bootstrap.py +0 -0
  36. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/fixtures/tour_demo_deck.json +0 -0
  37. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/mcp_auth.py +0 -0
  38. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/middleware/__init__.py +0 -0
  39. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/middleware/csrf.py +0 -0
  40. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/middleware/request_logging.py +0 -0
  41. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/middleware/security_headers.py +0 -0
  42. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/__init__.py +0 -0
  43. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/_authz.py +0 -0
  44. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/admin.py +0 -0
  45. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/admin_usage.py +0 -0
  46. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/agent_config.py +0 -0
  47. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/agent_definitions.py +0 -0
  48. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/deck_contributors.py +0 -0
  49. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/export.py +0 -0
  50. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/feedback.py +0 -0
  51. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/google_slides.py +0 -0
  52. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/images.py +0 -0
  53. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/local_version.py +0 -0
  54. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/profiles.py +0 -0
  55. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/sessions.py +0 -0
  56. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/settings/__init__.py +0 -0
  57. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/settings/contributors.py +0 -0
  58. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/settings/deck_prompts.py +0 -0
  59. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/settings/design_systems.py +0 -0
  60. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/settings/identities.py +0 -0
  61. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/setup.py +0 -0
  62. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/slides.py +0 -0
  63. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/tools.py +0 -0
  64. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/verification.py +0 -0
  65. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/routes/version.py +0 -0
  66. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/__init__.py +0 -0
  67. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/agent_config.py +0 -0
  68. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/agent_definitions.py +0 -0
  69. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/feedback.py +0 -0
  70. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/graph_release_history.py +0 -0
  71. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/graph_releases.py +0 -0
  72. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/responses.py +0 -0
  73. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/settings/__init__.py +0 -0
  74. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/settings/requests.py +0 -0
  75. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/settings/responses.py +0 -0
  76. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/schemas/streaming.py +0 -0
  77. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/__init__.py +0 -0
  78. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/deck_level_writer.py +0 -0
  79. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/export_job_queue.py +0 -0
  80. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/feedback_service.py +0 -0
  81. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/job_queue.py +0 -0
  82. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/session_naming.py +0 -0
  83. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/slide_repository.py +0 -0
  84. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/usage_events.py +0 -0
  85. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/services/usage_service.py +0 -0
  86. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/utils/__init__.py +0 -0
  87. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/api/utils/validation.py +0 -0
  88. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/__init__.py +0 -0
  89. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/backfill_session_slides_startup.py +0 -0
  90. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/checkpointer.py +0 -0
  91. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/config_loader.py +0 -0
  92. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/context_utils.py +0 -0
  93. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/databricks_client.py +0 -0
  94. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/defaults.py +0 -0
  95. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/encryption.py +0 -0
  96. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/init_default_profile.py +0 -0
  97. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/lakebase.py +0 -0
  98. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/migrate_profiles_to_agent_config.py +0 -0
  99. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/mlflow_agent_spans.py +0 -0
  100. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/mlflow_tracing.py +0 -0
  101. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/otel_logging.py +0 -0
  102. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/permission_context.py +0 -0
  103. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/prompt_modules.py +0 -0
  104. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/settings_db.py +0 -0
  105. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/skills/__init__.py +0 -0
  106. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/skills/architect.py +0 -0
  107. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/skills/build_reviewer.py +0 -0
  108. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/skills/builder.py +0 -0
  109. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/skills/data_analyst.py +0 -0
  110. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/skills/deck_reviewer.py +0 -0
  111. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/skills/fix_reviewer.py +0 -0
  112. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/skills/fixer.py +0 -0
  113. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/strip_retired_prompt_keys.py +0 -0
  114. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/core/user_context.py +0 -0
  115. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/__init__.py +0 -0
  116. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/data_migration.py +0 -0
  117. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/deck_contributor.py +0 -0
  118. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/deck_review.py +0 -0
  119. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/design_system.py +0 -0
  120. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/encryption_key.py +0 -0
  121. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/feedback.py +0 -0
  122. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/genie_space.py +0 -0
  123. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/google_global_credentials.py +0 -0
  124. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/google_oauth_token.py +0 -0
  125. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/graph_checkpoint.py +0 -0
  126. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/graph_configuration.py +0 -0
  127. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/identity.py +0 -0
  128. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/image.py +0 -0
  129. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/profile.py +0 -0
  130. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/profile_contributor.py +0 -0
  131. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/prompts.py +0 -0
  132. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/request_log.py +0 -0
  133. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/slide_deck_prompt.py +0 -0
  134. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/usage_event.py +0 -0
  135. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/models/user_preference.py +0 -0
  136. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/database/types.py +0 -0
  137. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/__init__.py +0 -0
  138. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/conversation_turns.py +0 -0
  139. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/deck_spec.py +0 -0
  140. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/deck_spec_slides.py +0 -0
  141. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/finding.py +0 -0
  142. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/finding_copy.py +0 -0
  143. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/skill_io.py +0 -0
  144. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/slide.py +0 -0
  145. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/slide_alignment.py +0 -0
  146. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/slide_deck.py +0 -0
  147. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/domain/slide_numbering.py +0 -0
  148. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/__init__.py +0 -0
  149. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent.py +0 -0
  150. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_definition_manifest_v1.py +0 -0
  151. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_factory.py +0 -0
  152. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_model_payload.py +0 -0
  153. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_resolution.py +0 -0
  154. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_runtime.py +0 -0
  155. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_runtime_identity.py +0 -0
  156. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_schema_registry.py +0 -0
  157. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_schema_types.py +0 -0
  158. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/agent_test_workbench.py +0 -0
  159. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/collaboration_history.py +0 -0
  160. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/config_service.py +0 -0
  161. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/config_validator.py +0 -0
  162. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/converter_jail/__init__.py +0 -0
  163. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/converter_jail/ast_guard.py +0 -0
  164. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/converter_jail/codeprep.py +0 -0
  165. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/converter_jail/gslides_runner.py +0 -0
  166. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/converter_jail/jail.py +0 -0
  167. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/converter_jail/pptx_runner.py +0 -0
  168. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/converter_jail/protocol.py +0 -0
  169. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/deck_css_aggregator.py +0 -0
  170. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/deck_review_store.py +0 -0
  171. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/design_system_compiler.py +0 -0
  172. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/design_system_service.py +0 -0
  173. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/design_system_templates.py +0 -0
  174. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/drive_uploader.py +0 -0
  175. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/evaluation/__init__.py +0 -0
  176. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/evaluation/llm_judge.py +0 -0
  177. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/foreman_service.py +0 -0
  178. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/gateway_openai.py +0 -0
  179. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/genie_service.py +0 -0
  180. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/google_slides_auth.py +0 -0
  181. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/google_slides_prompts_defaults.py +0 -0
  182. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph/__init__.py +0 -0
  183. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph/builder.py +0 -0
  184. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph/event_emitter.py +0 -0
  185. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph/nodes.py +0 -0
  186. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph/progress.py +0 -0
  187. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph/routers.py +0 -0
  188. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph/state.py +0 -0
  189. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph/user_notices.py +0 -0
  190. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_configuration.py +0 -0
  191. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_configuration_bootstrap.py +0 -0
  192. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_configuration_content.py +0 -0
  193. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_configuration_draft.py +0 -0
  194. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_configuration_publication.py +0 -0
  195. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_configuration_rollback.py +0 -0
  196. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_configuration_seed.py +0 -0
  197. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_configuration_workbench.py +0 -0
  198. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_definition_manifest.py +0 -0
  199. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_release_evidence.py +0 -0
  200. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/graph_release_history.py +0 -0
  201. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/html_to_google_slides.py +0 -0
  202. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/html_to_pptx.py +0 -0
  203. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/identity_provider.py +0 -0
  204. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/identity_providers/__init__.py +0 -0
  205. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/identity_providers/account_provider.py +0 -0
  206. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/identity_providers/local_provider.py +0 -0
  207. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/identity_providers/scim_filter.py +0 -0
  208. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/identity_providers/workspace_provider.py +0 -0
  209. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/image_service.py +0 -0
  210. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/image_tools.py +0 -0
  211. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/model_endpoint_catalog.py +0 -0
  212. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/model_endpoint_probe.py +0 -0
  213. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/permission_service.py +0 -0
  214. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/persisted_graph_release.py +0 -0
  215. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/pptx_from_html_huashu.py +0 -0
  216. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/pptx_from_records.py +0 -0
  217. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/pptx_prompts_defaults.py +0 -0
  218. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/profile_service.py +0 -0
  219. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/prompt_assembler.py +0 -0
  220. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/shared_deck_attribution.py +0 -0
  221. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/spec_sync.py +0 -0
  222. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/streaming_callback.py +0 -0
  223. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/svg_sanitizer.py +0 -0
  224. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/template_sections.py +0 -0
  225. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/tools/__init__.py +0 -0
  226. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/tools/agent_bricks_tool.py +0 -0
  227. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/tools/ds_asset_tool.py +0 -0
  228. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/tools/genie_tool.py +0 -0
  229. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/tools/mcp_tool.py +0 -0
  230. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/tools/model_endpoint_tool.py +0 -0
  231. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/tools/vector_tool.py +0 -0
  232. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/services/validator.py +0 -0
  233. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/__init__.py +0 -0
  234. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/css_utils.py +0 -0
  235. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/ds_asset_utils.py +0 -0
  236. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/error_handling.py +0 -0
  237. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/graph_safety.py +0 -0
  238. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/html_safety.py +0 -0
  239. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/html_utils.py +0 -0
  240. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/image_utils.py +0 -0
  241. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/js_validator.py +0 -0
  242. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/logging_config.py +0 -0
  243. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/pi_filter.py +0 -0
  244. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/slide_hash.py +0 -0
  245. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/spotlight.py +0 -0
  246. {databricks_tellr_app-0.4.3.dev3462 → databricks_tellr_app-0.4.3.dev3463}/src/utils/text_caps.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-tellr-app
3
- Version: 0.4.3.dev3462
3
+ Version: 0.4.3.dev3463
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -68,23 +68,6 @@ def init_database(seed_databricks_defaults: bool = False) -> None:
68
68
  logger.error(f"Failed to bootstrap Graph Configuration: {e}\n{tb}")
69
69
  raise SystemExit(1) from e
70
70
 
71
- logger.info("Backfilling Conversation Pins...")
72
- try:
73
- from src.core.database import get_session_local
74
- from src.services.conversation_pins import backfill_conversation_pins
75
-
76
- result = backfill_conversation_pins(get_session_local())
77
- logger.info(
78
- "Conversation Pins ready: release_id=%s version=%s pinned=%s",
79
- result.graph_release_id,
80
- result.graph_version,
81
- result.pinned_count,
82
- )
83
- except Exception as e:
84
- tb = traceback.format_exc()
85
- logger.error(f"Failed to backfill Conversation Pins: {e}\n{tb}")
86
- raise SystemExit(1) from e
87
-
88
71
  # Data migrations/backfills that used to run in the FastAPI lifespan now run
89
72
  # HERE, once, before the server forks its workers — the uvicorn workers must
90
73
  # never execute migration code (4 of them racing the migration chain on boot
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-tellr-app
3
- Version: 0.4.3.dev3462
3
+ Version: 0.4.3.dev3463
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -62,7 +62,6 @@ setup.py
62
62
  ./src/api/services/session_manager.py
63
63
  ./src/api/services/session_naming.py
64
64
  ./src/api/services/slide_repository.py
65
- ./src/api/services/slide_style_preview_queue.py
66
65
  ./src/api/services/usage_events.py
67
66
  ./src/api/services/usage_service.py
68
67
  ./src/api/utils/__init__.py
@@ -118,7 +117,6 @@ setup.py
118
117
  ./src/database/models/session.py
119
118
  ./src/database/models/slide_deck_prompt.py
120
119
  ./src/database/models/slide_style_library.py
121
- ./src/database/models/slide_style_preview.py
122
120
  ./src/database/models/usage_event.py
123
121
  ./src/database/models/user_preference.py
124
122
  ./src/domain/__init__.py
@@ -185,8 +183,6 @@ setup.py
185
183
  ./src/services/profile_service.py
186
184
  ./src/services/prompt_assembler.py
187
185
  ./src/services/shared_deck_attribution.py
188
- ./src/services/slide_style_preview_fixture.py
189
- ./src/services/slide_style_preview_storage.py
190
186
  ./src/services/spec_sync.py
191
187
  ./src/services/streaming_callback.py
192
188
  ./src/services/svg_sanitizer.py
@@ -301,7 +297,6 @@ src/api/services/job_queue.py
301
297
  src/api/services/session_manager.py
302
298
  src/api/services/session_naming.py
303
299
  src/api/services/slide_repository.py
304
- src/api/services/slide_style_preview_queue.py
305
300
  src/api/services/usage_events.py
306
301
  src/api/services/usage_service.py
307
302
  src/api/utils/__init__.py
@@ -357,7 +352,6 @@ src/database/models/request_log.py
357
352
  src/database/models/session.py
358
353
  src/database/models/slide_deck_prompt.py
359
354
  src/database/models/slide_style_library.py
360
- src/database/models/slide_style_preview.py
361
355
  src/database/models/usage_event.py
362
356
  src/database/models/user_preference.py
363
357
  src/domain/__init__.py
@@ -424,8 +418,6 @@ src/services/pptx_prompts_defaults.py
424
418
  src/services/profile_service.py
425
419
  src/services/prompt_assembler.py
426
420
  src/services/shared_deck_attribution.py
427
- src/services/slide_style_preview_fixture.py
428
- src/services/slide_style_preview_storage.py
429
421
  src/services/spec_sync.py
430
422
  src/services/streaming_callback.py
431
423
  src/services/svg_sanitizer.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "databricks-tellr-app"
7
- version = "0.4.3.dev3462"
7
+ version = "0.4.3.dev3463"
8
8
  description = "Tellr application package for Databricks Apps"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -49,7 +49,6 @@ from src.api.services.export_job_queue import (
49
49
  start_export_worker,
50
50
  )
51
51
  from src.api.services.job_queue import recover_stuck_requests, start_worker
52
- from src.api.services.slide_style_preview_queue import start_preview_worker
53
52
  from src.core.database import (
54
53
  is_lakebase_environment,
55
54
  start_token_refresh,
@@ -71,7 +70,6 @@ IS_TESTING = ENVIRONMENT == "test"
71
70
  _worker_task = None
72
71
  _export_worker_task = None
73
72
  _export_cleanup_task: asyncio.Task | None = None
74
- _preview_worker_task = None
75
73
  _cleanup_task = None
76
74
  _timeout_task = None
77
75
  _spec_sweeper_task = None
@@ -81,7 +79,7 @@ _frontend_assets_stack: ExitStack | None = None
81
79
  @asynccontextmanager
82
80
  async def lifespan(app: FastAPI):
83
81
  """Lifespan context manager for startup/shutdown events."""
84
- global _worker_task, _export_worker_task, _export_cleanup_task, _preview_worker_task
82
+ global _worker_task, _export_worker_task, _export_cleanup_task
85
83
  global _cleanup_task, _timeout_task, _spec_sweeper_task, _frontend_assets_stack
86
84
 
87
85
  # Startup
@@ -153,20 +151,6 @@ async def lifespan(app: FastAPI):
153
151
  _export_cleanup_task = await start_export_cleanup_worker()
154
152
  logger.info("Export job cleanup worker started")
155
153
 
156
- # Start the slide-style preview generation worker
157
- _preview_worker_task = await start_preview_worker()
158
- logger.info("Slide-style preview worker started")
159
-
160
- # Pre-warm previews for active styles so viewers hit a warm cache instead
161
- # of a cold LLM generation. Bounded + deduplicated; runs off the event loop.
162
- try:
163
- from src.api.services.slide_style_preview_queue import warm_missing_previews
164
-
165
- warmed = await asyncio.to_thread(warm_missing_previews)
166
- logger.info("Slide-style preview warm backfill enqueued", extra={"enqueued": warmed})
167
- except Exception: # noqa: BLE001 — warming must never block startup
168
- logger.warning("Slide-style preview warm backfill failed", exc_info=True)
169
-
170
154
  # Start the MCP job timeout sweeper
171
155
  from src.api.services.job_queue import mark_timed_out_jobs_loop
172
156
  _timeout_task = asyncio.create_task(mark_timed_out_jobs_loop())
@@ -230,14 +214,6 @@ async def lifespan(app: FastAPI):
230
214
  pass
231
215
  logger.info("Export job cleanup worker stopped")
232
216
 
233
- if _preview_worker_task:
234
- _preview_worker_task.cancel()
235
- try:
236
- await _preview_worker_task
237
- except asyncio.CancelledError:
238
- pass
239
- logger.info("Slide-style preview worker stopped")
240
-
241
217
  if _cleanup_task:
242
218
  _cleanup_task.cancel()
243
219
  try:
@@ -33,7 +33,6 @@ from src.core.settings_db import (
33
33
  get_default_slide_style_id,
34
34
  get_default_template_id,
35
35
  )
36
- from src.domain.conversation_engine import with_legacy_marker
37
36
  from src.domain.slide_deck import SlideDeck
38
37
  from src.services.permission_service import get_permission_service
39
38
 
@@ -238,23 +237,14 @@ async def enqueue_create_job(
238
237
  #
239
238
  # MCP stays on the legacy monolith (its worker payload carries no engine
240
239
  # key, and the graph's one-shot path, spec §6.4, is not built).
241
- # Since 2026-10-12 the graph is the DEFAULT engine, derived from the
242
- # deck's first user message -- so a create_deck deck whose transcript
243
- # did not say otherwise would resolve to the graph the first time
244
- # someone chatted on it in the browser, and fail there
245
- # (ConversationPinMissingError: MCP sessions are unpinned). The
246
- # persisted first message therefore carries the LEGACY opt-out; the
247
- # prompt the worker runs (payload "message" below) is untouched.
248
- persisted_prompt = (
249
- with_legacy_marker(prompt)
250
- if mode == "generate" and is_first_message
251
- else prompt
252
- )
240
+ # create_deck stores that on the session it creates (deck_mode="legacy"),
241
+ # so no prompt has to say it: every prompt, create or edit, is persisted
242
+ # verbatim.
253
243
  await asyncio.to_thread(
254
244
  session_manager.add_message,
255
245
  session_id=session_id,
256
246
  role="user",
257
- content=persisted_prompt,
247
+ content=prompt,
258
248
  message_type="user_query",
259
249
  request_id=request_id,
260
250
  )
@@ -536,10 +526,9 @@ async def _create_deck_impl(
536
526
  session = session_manager.create_session(
537
527
  created_by=identity.user_name,
538
528
  agent_config=agent_config,
539
- # Legacy deck: unpinned, and enqueue_create_job persists the
540
- # first message with the USE LEGACY MODE opt-out so the
541
- # transcript-derived engine agrees in every surface.
529
+ # Legacy deck: unpinned, and locked to the monolith from creation.
542
530
  graph_capable=False,
531
+ deck_mode="legacy",
543
532
  )
544
533
  # create_session returns a dict (see SessionManager.create_session);
545
534
  # guard against a model-object return defensively so this stays
@@ -37,7 +37,11 @@ from src.api.services.job_queue import (
37
37
  is_pinned_graph_configuration_error_event,
38
38
  pinned_graph_configuration_error_event_payload,
39
39
  )
40
- from src.api.services.session_manager import SessionNotFoundError, get_session_manager
40
+ from src.api.services.session_manager import (
41
+ DeckModeLockedError,
42
+ SessionNotFoundError,
43
+ get_session_manager,
44
+ )
41
45
  from src.core.context_utils import run_in_thread_with_context
42
46
  from src.core.database import get_db
43
47
  from src.core.permission_context import get_permission_context
@@ -48,7 +52,6 @@ from src.core.settings_db import (
48
52
  )
49
53
  from src.core.user_context import get_current_user
50
54
  from src.database.models.profile_contributor import PermissionLevel
51
- from src.domain.conversation_engine import selects_graph_engine
52
55
  from src.services.agent import UnsafeContentError
53
56
  from src.services.conversation_pins import ActiveGraphReleaseUnavailableError
54
57
  from src.services.permission_service import PERMISSION_PRIORITY, get_permission_service
@@ -75,6 +78,34 @@ class _EngineModeUnresolvedError(Exception):
75
78
  """The async route's engine-mode resolution (and nothing else) failed closed."""
76
79
 
77
80
 
81
+ DECK_MODE_LOCKED_CODE = "deck_mode_locked"
82
+
83
+ _DECK_MODE_LABELS = {"agent": "Agent mode", "legacy": "Legacy mode"}
84
+
85
+
86
+ def _deck_mode_locked(exc: DeckModeLockedError) -> HTTPException:
87
+ """The 409 for a message asking for a Deck Mode other than the deck's locked one."""
88
+ label = _DECK_MODE_LABELS.get(exc.deck_mode, exc.deck_mode)
89
+ return HTTPException(
90
+ status_code=409,
91
+ detail={
92
+ "code": DECK_MODE_LOCKED_CODE,
93
+ "message": f"This deck's mode is already set to {label}, and it can't be changed.",
94
+ "deck_mode": exc.deck_mode,
95
+ },
96
+ )
97
+
98
+
99
+ async def _mark_chat_request_error(session_manager, request_id: str, code: str) -> None:
100
+ """Best effort: a failed status write must never mask the 409/503 being raised."""
101
+ try:
102
+ await asyncio.to_thread(
103
+ session_manager.update_chat_request_status, request_id, "error", code
104
+ )
105
+ except Exception:
106
+ logger.warning("Failed to mark chat request %s as errored", request_id, exc_info=True)
107
+
108
+
78
109
  def _engine_mode_unavailable() -> HTTPException:
79
110
  return HTTPException(status_code=503, detail=dict(ENGINE_MODE_UNAVAILABLE_DETAIL))
80
111
 
@@ -344,7 +375,7 @@ def _maybe_create_session(request: ChatRequest, session_manager) -> bool:
344
375
  _without_template_pin(_seeded_for_new_session(agent_config_data))
345
376
  ),
346
377
  created_by=current_user,
347
- graph_capable=selects_graph_engine(request.message),
378
+ graph_capable=True,
348
379
  )
349
380
  logger.info(
350
381
  "Created session from client-generated ID",
@@ -382,7 +413,7 @@ def _maybe_create_session(request: ChatRequest, session_manager) -> bool:
382
413
  _without_template_pin(_seeded_for_new_session(agent_config_data))
383
414
  ),
384
415
  created_by=current_user,
385
- graph_capable=selects_graph_engine(request.message),
416
+ graph_capable=True,
386
417
  )
387
418
  request.session_id = session["session_id"]
388
419
  return True
@@ -555,6 +586,42 @@ async def send_message_streaming(
555
586
  detail="Session is currently processing another request. Please wait.",
556
587
  )
557
588
 
589
+ # The user message is saved BEFORE the engine is resolved: the resolver
590
+ # reads the deck's owner column, which this save locks atomically with the
591
+ # message. Nothing has started streaming yet, so every failure here must
592
+ # release the lock taken above itself.
593
+ try:
594
+ session_data = await asyncio.to_thread(
595
+ session_manager.get_session, request.session_id
596
+ )
597
+ is_first_message = session_data.get("message_count", 0) == 0
598
+ await asyncio.to_thread(
599
+ session_manager.add_user_message,
600
+ request.session_id,
601
+ request.message,
602
+ message_type="user_input",
603
+ requested_deck_mode=request.deck_mode,
604
+ )
605
+ except SessionNotFoundError as e:
606
+ await asyncio.to_thread(session_manager.release_session_lock, request.session_id)
607
+ raise HTTPException(
608
+ status_code=404,
609
+ detail=f"Session not found: {request.session_id}",
610
+ ) from e
611
+ except DeckModeLockedError as e:
612
+ await asyncio.to_thread(session_manager.release_session_lock, request.session_id)
613
+ raise _deck_mode_locked(e) from e
614
+ except ActiveGraphReleaseUnavailableError as e:
615
+ await asyncio.to_thread(session_manager.release_session_lock, request.session_id)
616
+ raise HTTPException(
617
+ status_code=503,
618
+ detail="No active Graph Release available",
619
+ ) from e
620
+ except Exception as e:
621
+ await asyncio.to_thread(session_manager.release_session_lock, request.session_id)
622
+ logger.error(f"Failed to save streaming chat message: {e}")
623
+ raise HTTPException(status_code=500, detail="Internal server error") from e
624
+
558
625
  # ws4d D2 — the engine for this turn is resolved HERE, in the chat route,
559
626
  # and passed down. Not in send_message_streaming and not in the job queue:
560
627
  # MCP's enqueue_create_job drains through the same worker as POST
@@ -606,6 +673,8 @@ async def send_message_streaming(
606
673
  else None,
607
674
  image_ids=request.image_ids,
608
675
  engine_mode=engine_mode,
676
+ is_first_message_override=is_first_message,
677
+ user_message_persisted=True,
609
678
  ):
610
679
  event_queue.put(event)
611
680
  except Exception as e:
@@ -746,26 +815,26 @@ async def submit_chat_async(
746
815
  )
747
816
 
748
817
  # Capture first-message flag BEFORE persisting the user message,
749
- # because add_message increments message_count.
818
+ # because saving the message increments message_count.
750
819
  session_data = await asyncio.to_thread(
751
820
  session_manager.get_session, request.session_id
752
821
  )
753
822
  is_first_message = session_data.get("message_count", 0) == 0
754
823
 
755
- # Persist user message
824
+ # Persist user message (locks the deck's mode atomically with it)
756
825
  await asyncio.to_thread(
757
- session_manager.add_message,
758
- session_id=request.session_id,
759
- role="user",
760
- content=request.message,
826
+ session_manager.add_user_message,
827
+ request.session_id,
828
+ request.message,
761
829
  message_type="user_query",
762
830
  request_id=request_id,
831
+ requested_deck_mode=request.deck_mode,
763
832
  )
764
833
 
765
834
  # ws4d D2 — resolved AFTER the user message is persisted just above,
766
- # because resolve_engine_mode reads the deck's EARLIEST role='user'
767
- # message: on turn 1 that row has to exist already or a USE LEGACY MODE
768
- # opt-out in the very first message would resolve to the default
835
+ # because resolve_engine_mode reads the deck owner's `deck_mode`
836
+ # column, which that save locks: on turn 1 the column has to be set
837
+ # already or a legacy first message would resolve to the NULL default
769
838
  # (graph) engine.
770
839
  #
771
840
  # FAIL CLOSED (#271 C24/C47): a failure of THIS call (and only this call)
@@ -815,6 +884,23 @@ async def submit_chat_async(
815
884
  session_manager.release_session_lock, request.session_id
816
885
  )
817
886
  raise _engine_mode_unavailable() from e.__cause__
887
+ except DeckModeLockedError as e:
888
+ await asyncio.to_thread(
889
+ session_manager.release_session_lock, request.session_id
890
+ )
891
+ await _mark_chat_request_error(session_manager, request_id, DECK_MODE_LOCKED_CODE)
892
+ raise _deck_mode_locked(e) from e
893
+ except ActiveGraphReleaseUnavailableError as e:
894
+ await asyncio.to_thread(
895
+ session_manager.release_session_lock, request.session_id
896
+ )
897
+ await _mark_chat_request_error(
898
+ session_manager, request_id, "no_active_graph_release"
899
+ )
900
+ raise HTTPException(
901
+ status_code=503,
902
+ detail="No active Graph Release available",
903
+ ) from e
818
904
  except Exception as e:
819
905
  # Release lock on failure
820
906
  await asyncio.to_thread(
@@ -16,14 +16,9 @@ from sqlalchemy.orm import Session
16
16
  from src.api.routes._authz import require_admin
17
17
  from src.core.database import get_db, get_db_session
18
18
  from src.database.models import SlideStyleLibrary
19
- from src.services import slide_style_preview_fixture as preview_fixture
20
- from src.services import slide_style_preview_storage as preview_storage
21
19
 
22
20
  logger = logging.getLogger(__name__)
23
21
 
24
- # Fields whose change invalidates a generated preview (see cache-invalidation).
25
- _PREVIEW_AFFECTING_FIELDS = ("style_content", "image_guidelines")
26
-
27
22
  router = APIRouter(prefix="/slide-styles", tags=["slide-styles"])
28
23
 
29
24
 
@@ -73,26 +68,6 @@ class SlideStyleListResponse(BaseModel):
73
68
  total: int
74
69
 
75
70
 
76
- class SlideStylePreviewResponse(BaseModel):
77
- """Read-only preview state for a slide style.
78
-
79
- ``status`` drives the client: ``ready`` (current), ``stale`` (a usable but
80
- out-of-date copy while regeneration runs), ``queued``/``generating`` (in
81
- flight), ``failed`` (with optional last-known-good copy), ``missing`` (never
82
- generated). HTTP is always 200; the client polls on ``status`` rather than
83
- on status codes.
84
- """
85
- style_id: int
86
- status: str
87
- fingerprint: Optional[str] = None
88
- slides: Optional[List[str]] = None
89
- css: Optional[str] = None
90
- assets: Optional[List[dict]] = None
91
- generated_at: Optional[str] = None
92
- error_code: Optional[str] = None
93
- stale: bool = False
94
-
95
-
96
71
  # API endpoints
97
72
 
98
73
  @router.get("", response_model=SlideStyleListResponse)
@@ -263,15 +238,6 @@ def create_slide_style(
263
238
  db.refresh(style)
264
239
 
265
240
  logger.info(f"Created slide style: {style.name} (id={style.id})")
266
-
267
- # Warm the visual preview immediately so the first viewer gets a cache
268
- # hit instead of waiting on a cold generation. Deduplicated + best-effort.
269
- try:
270
- from src.api.services.slide_style_preview_queue import try_enqueue
271
-
272
- try_enqueue(style.id)
273
- except Exception: # noqa: BLE001 — warming must never fail the create
274
- logger.warning("Preview warm-on-create failed", exc_info=True)
275
241
 
276
242
  return SlideStyleResponse(
277
243
  id=style.id,
@@ -355,38 +321,11 @@ def update_slide_style(
355
321
  style.description = request.description
356
322
  if request.category is not None:
357
323
  style.category = request.category
358
-
359
- # Detect preview-affecting changes BEFORE mutating, so we can invalidate
360
- # the cached preview in the SAME transaction as the edit (cache-invalidation).
361
- preview_affected = False
362
- if request.style_content is not None and request.style_content != style.style_content:
363
- preview_affected = True
364
- if (
365
- request.image_guidelines is not None
366
- and request.image_guidelines != style.image_guidelines
367
- ):
368
- preview_affected = True
369
-
370
324
  if request.style_content is not None:
371
325
  style.style_content = request.style_content
372
326
  if request.image_guidelines is not None:
373
327
  style.image_guidelines = request.image_guidelines
374
328
 
375
- if preview_affected:
376
- # Bump the revision (the generation write-back guard) and reset the
377
- # cached preview to 'missing' so it regenerates. The last-known-good
378
- # payload row is left in storage until the next successful prune.
379
- style.style_revision = (style.style_revision or 0) + 1
380
- style.preview_status = "missing"
381
- style.preview_fingerprint = None
382
- style.preview_payload_id = None
383
- style.preview_error_code = None
384
- style.preview_error_message = None
385
- logger.info(
386
- "Invalidated slide-style preview after edit",
387
- extra={"style_id": style.id, "style_revision": style.style_revision},
388
- )
389
-
390
329
  # Update the user (skip Databricks call in test/dev to avoid network timeout)
391
330
  if os.getenv("ENVIRONMENT") in ("development", "test"):
392
331
  style.updated_by = "system"
@@ -405,16 +344,6 @@ def update_slide_style(
405
344
  db.refresh(style)
406
345
 
407
346
  logger.info(f"Updated slide style: {style.name} (id={style.id})")
408
-
409
- # If the edit invalidated the preview, warm it right away (against the
410
- # now-committed new revision) so viewers don't hit a cold regeneration.
411
- if preview_affected:
412
- try:
413
- from src.api.services.slide_style_preview_queue import try_enqueue
414
-
415
- try_enqueue(style.id)
416
- except Exception: # noqa: BLE001 — warming must never fail the update
417
- logger.warning("Preview warm-on-update failed", exc_info=True)
418
347
 
419
348
  return SlideStyleResponse(
420
349
  id=style.id,
@@ -581,133 +510,3 @@ def set_default_slide_style(style_id: int):
581
510
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
582
511
  detail="Failed to set default slide style",
583
512
  )
584
-
585
-
586
- @router.get("/{style_id}/preview", response_model=SlideStylePreviewResponse)
587
- def get_slide_style_preview(
588
- style_id: int,
589
- db: Session = Depends(get_db),
590
- ):
591
- """Read the cached visual preview for a slide style. NEVER generates inline.
592
-
593
- Visibility mirrors ``GET /{style_id}`` (404 parity). When the cached preview
594
- is missing or stale relative to the current generation fingerprint, this
595
- enqueues a deduplicated background job and returns the current state (with a
596
- stale copy if one exists) so the UI stays fast and crawlers/prefetch/scroll
597
- never trigger LLM cost.
598
- """
599
- from src.api.services.slide_style_preview_queue import try_enqueue
600
-
601
- style = db.query(SlideStyleLibrary).filter(SlideStyleLibrary.id == style_id).first()
602
- if not style:
603
- raise HTTPException(
604
- status_code=status.HTTP_404_NOT_FOUND,
605
- detail=f"Slide style {style_id} not found",
606
- )
607
-
608
- current_fp = preview_fixture.compute_fingerprint(
609
- style.style_content,
610
- style.image_guidelines,
611
- preview_fixture.current_builder_definition(db),
612
- )
613
- status_val = style.preview_status or "missing"
614
-
615
- # Load any stored payload (ready OR last-known-good) once.
616
- payload = None
617
- if style.preview_payload_id:
618
- payload = preview_storage.load_payload(db, style.preview_payload_id)
619
-
620
- def _resp(status_str: str, *, include_payload: bool, stale: bool = False):
621
- has = include_payload and payload
622
- return SlideStylePreviewResponse(
623
- style_id=style_id,
624
- status=status_str,
625
- fingerprint=style.preview_fingerprint if include_payload else None,
626
- slides=(payload or {}).get("slides") if has else None,
627
- css=(payload or {}).get("css") if has else None,
628
- assets=(payload or {}).get("assets") if has else None,
629
- generated_at=style.preview_generated_at.isoformat()
630
- if (has and style.preview_generated_at)
631
- else None,
632
- error_code=style.preview_error_code,
633
- stale=stale,
634
- )
635
-
636
- # Ready and current (cache hit).
637
- if status_val == "ready" and style.preview_fingerprint == current_fp and payload:
638
- logger.info(
639
- "slide_style_preview.cache_hit",
640
- extra={"style_id": style_id, "status": "ready"},
641
- )
642
- return _resp("ready", include_payload=True)
643
-
644
- # Ready but stale (fingerprint moved). Serve the stale copy, kick a refresh.
645
- if status_val == "ready" and payload:
646
- age_s = None
647
- if style.preview_generated_at:
648
- from datetime import datetime as _dt
649
-
650
- age_s = (_dt.utcnow() - style.preview_generated_at).total_seconds()
651
- logger.info(
652
- "slide_style_preview.cache_stale",
653
- extra={"style_id": style_id, "stale_age_s": age_s},
654
- )
655
- try_enqueue(style_id)
656
- return _resp("stale", include_payload=True, stale=True)
657
-
658
- # In flight. Serve stale copy underneath if present. try_enqueue no-ops a
659
- # live job and re-queues one whose worker died, so a viewer recovers it.
660
- if status_val in ("queued", "generating"):
661
- try_enqueue(style_id)
662
- return _resp(status_val, include_payload=bool(payload), stale=bool(payload))
663
-
664
- # Failed. Return last-known-good if we have one; otherwise just the error.
665
- if status_val == "failed":
666
- return _resp("failed", include_payload=bool(payload), stale=bool(payload))
667
-
668
- # Missing (or unknown): enqueue and report queued.
669
- try_enqueue(style_id)
670
- # Re-read status: try_enqueue may have transitioned it to 'queued'.
671
- return SlideStylePreviewResponse(style_id=style_id, status="queued")
672
-
673
-
674
- # SDR-4437 HIGH-3: workspace-global library writes are admin-only.
675
- @router.post(
676
- "/{style_id}/preview/regenerate",
677
- response_model=SlideStylePreviewResponse,
678
- dependencies=[Depends(require_admin)],
679
- )
680
- def regenerate_slide_style_preview(
681
- style_id: int,
682
- db: Session = Depends(get_db),
683
- ):
684
- """Explicitly (re)generate a slide-style preview. Admin-only, deduplicated.
685
-
686
- Enqueues a background job against the current style snapshot. Idempotent: if
687
- a generation is already in flight this is a no-op that returns the in-flight
688
- status.
689
- """
690
- from datetime import datetime as _dt
691
-
692
- from src.api.services.slide_style_preview_queue import claimable_clause, try_enqueue
693
-
694
- style = db.query(SlideStyleLibrary).filter(SlideStyleLibrary.id == style_id).first()
695
- if not style:
696
- raise HTTPException(
697
- status_code=status.HTTP_404_NOT_FOUND,
698
- detail=f"Slide style {style_id} not found",
699
- )
700
-
701
- # Force a re-attempt even from a 'failed'/'ready' terminal state by clearing
702
- # to 'missing' first (in its own committed txn), then enqueue. A live job is
703
- # left alone (no duplicate generation); an abandoned one is claimable.
704
- db.query(SlideStyleLibrary).filter(
705
- SlideStyleLibrary.id == style_id, claimable_clause(_dt.utcnow())
706
- ).update({"preview_status": "missing"}, synchronize_session=False)
707
- db.commit()
708
-
709
- try_enqueue(style_id)
710
- db.refresh(style)
711
- return SlideStylePreviewResponse(
712
- style_id=style_id, status=style.preview_status or "queued"
713
- )
@@ -65,16 +65,15 @@ def _phase1_create_session(created_by: str) -> dict:
65
65
  fixture = _load_fixture()
66
66
  sm = get_session_manager()
67
67
 
68
- # Graph-capable (pinned): the fixture's chat_prompt carries no
69
- # USE LEGACY MODE opt-out, so since 2026-10-12 the tour deck resolves to
70
- # the graph like any other deck, and a graph turn on an unpinned session
71
- # raises ConversationPinMissingError. The fixture already ships a
72
- # deck_spec for exactly this (ws4d), so a user who keeps chatting after the
73
- # tour gets the default engine.
68
+ # Graph-capable (pinned) and locked to the agent engine from creation, so
69
+ # a user who keeps chatting after the tour stays on the graph. A graph
70
+ # turn on an unpinned session raises ConversationPinMissingError. The
71
+ # fixture already ships a deck_spec for exactly this (ws4d).
74
72
  session = sm.create_session(
75
73
  title=fixture["title"],
76
74
  created_by=created_by,
77
75
  graph_capable=True,
76
+ deck_mode="agent",
78
77
  )
79
78
  session_id = session["session_id"]
80
79