databricks-tellr-app 0.4.2.dev13__tar.gz → 0.4.2.dev14__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 (167) hide show
  1. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/PKG-INFO +1 -1
  2. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
  3. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/pyproject.toml +1 -1
  4. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/export.py +36 -1
  5. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/settings/design_systems.py +108 -14
  6. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/agent_factory.py +53 -6
  7. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/converter_jail/jail.py +14 -0
  8. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/converter_jail/pptx_runner.py +8 -0
  9. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/converter_jail/protocol.py +33 -0
  10. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/design_system_compiler.py +178 -17
  11. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/design_system_service.py +73 -0
  12. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/html_to_pptx.py +182 -2
  13. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/README.md +0 -0
  14. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/databricks_tellr_app/__init__.py +0 -0
  15. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/databricks_tellr_app/run.py +0 -0
  16. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/databricks_tellr_app.egg-info/SOURCES.txt +0 -0
  17. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
  18. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/databricks_tellr_app.egg-info/requires.txt +0 -0
  19. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/databricks_tellr_app.egg-info/top_level.txt +0 -0
  20. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/setup.cfg +0 -0
  21. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/setup.py +0 -0
  22. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/__init__.py +0 -0
  23. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/__init__.py +0 -0
  24. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/_otel_bootstrap.py +0 -0
  25. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/fixtures/tour_demo_deck.json +0 -0
  26. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/main.py +0 -0
  27. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/mcp_auth.py +0 -0
  28. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/mcp_server.py +0 -0
  29. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/middleware/__init__.py +0 -0
  30. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/middleware/csrf.py +0 -0
  31. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/middleware/request_logging.py +0 -0
  32. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/middleware/security_headers.py +0 -0
  33. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/__init__.py +0 -0
  34. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/_authz.py +0 -0
  35. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/admin.py +0 -0
  36. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/admin_usage.py +0 -0
  37. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/agent_config.py +0 -0
  38. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/chat.py +0 -0
  39. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/deck_contributors.py +0 -0
  40. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/feedback.py +0 -0
  41. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/google_slides.py +0 -0
  42. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/images.py +0 -0
  43. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/local_version.py +0 -0
  44. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/profiles.py +0 -0
  45. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/sessions.py +0 -0
  46. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/settings/__init__.py +0 -0
  47. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/settings/contributors.py +0 -0
  48. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/settings/deck_prompts.py +0 -0
  49. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/settings/identities.py +0 -0
  50. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/settings/slide_styles.py +0 -0
  51. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/setup.py +0 -0
  52. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/slides.py +0 -0
  53. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/tools.py +0 -0
  54. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/tour.py +0 -0
  55. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/verification.py +0 -0
  56. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/routes/version.py +0 -0
  57. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/__init__.py +0 -0
  58. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/agent_config.py +0 -0
  59. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/feedback.py +0 -0
  60. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/requests.py +0 -0
  61. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/responses.py +0 -0
  62. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/settings/__init__.py +0 -0
  63. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/settings/requests.py +0 -0
  64. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/settings/responses.py +0 -0
  65. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/schemas/streaming.py +0 -0
  66. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/__init__.py +0 -0
  67. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/chat_service.py +0 -0
  68. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/export_job_queue.py +0 -0
  69. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/feedback_service.py +0 -0
  70. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/job_queue.py +0 -0
  71. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/session_manager.py +0 -0
  72. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/session_naming.py +0 -0
  73. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/usage_events.py +0 -0
  74. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/services/usage_service.py +0 -0
  75. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/utils/__init__.py +0 -0
  76. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/api/utils/validation.py +0 -0
  77. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/__init__.py +0 -0
  78. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/config_loader.py +0 -0
  79. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/context_utils.py +0 -0
  80. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/database.py +0 -0
  81. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/databricks_client.py +0 -0
  82. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/defaults.py +0 -0
  83. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/encryption.py +0 -0
  84. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/init_default_profile.py +0 -0
  85. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/lakebase.py +0 -0
  86. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/migrate_profiles_to_agent_config.py +0 -0
  87. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/mlflow_agent_spans.py +0 -0
  88. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/mlflow_tracing.py +0 -0
  89. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/otel_logging.py +0 -0
  90. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/permission_context.py +0 -0
  91. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/prompt_modules.py +0 -0
  92. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/settings_db.py +0 -0
  93. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/core/user_context.py +0 -0
  94. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/__init__.py +0 -0
  95. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/__init__.py +0 -0
  96. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/deck_contributor.py +0 -0
  97. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/design_system.py +0 -0
  98. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/encryption_key.py +0 -0
  99. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/feedback.py +0 -0
  100. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/genie_space.py +0 -0
  101. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/google_global_credentials.py +0 -0
  102. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/google_oauth_token.py +0 -0
  103. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/identity.py +0 -0
  104. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/image.py +0 -0
  105. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/profile.py +0 -0
  106. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/profile_contributor.py +0 -0
  107. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/prompts.py +0 -0
  108. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/request_log.py +0 -0
  109. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/session.py +0 -0
  110. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/slide_deck_prompt.py +0 -0
  111. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/slide_style_library.py +0 -0
  112. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/usage_event.py +0 -0
  113. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/models/user_preference.py +0 -0
  114. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/database/types.py +0 -0
  115. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/domain/__init__.py +0 -0
  116. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/domain/slide.py +0 -0
  117. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/domain/slide_deck.py +0 -0
  118. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/__init__.py +0 -0
  119. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/agent.py +0 -0
  120. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/config_service.py +0 -0
  121. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/config_validator.py +0 -0
  122. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/converter_jail/__init__.py +0 -0
  123. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/converter_jail/ast_guard.py +0 -0
  124. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/converter_jail/codeprep.py +0 -0
  125. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/converter_jail/gslides_runner.py +0 -0
  126. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/design_system_templates.py +0 -0
  127. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/drive_uploader.py +0 -0
  128. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/evaluation/__init__.py +0 -0
  129. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/evaluation/llm_judge.py +0 -0
  130. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/genie_service.py +0 -0
  131. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/google_slides_auth.py +0 -0
  132. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/google_slides_prompts_defaults.py +0 -0
  133. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/html_to_google_slides.py +0 -0
  134. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/identity_provider.py +0 -0
  135. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/identity_providers/__init__.py +0 -0
  136. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/identity_providers/account_provider.py +0 -0
  137. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/identity_providers/local_provider.py +0 -0
  138. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/identity_providers/workspace_provider.py +0 -0
  139. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/image_service.py +0 -0
  140. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/image_tools.py +0 -0
  141. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/permission_service.py +0 -0
  142. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/pptx_from_html_huashu.py +0 -0
  143. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/pptx_from_records.py +0 -0
  144. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/pptx_prompts_defaults.py +0 -0
  145. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/profile_service.py +0 -0
  146. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/streaming_callback.py +0 -0
  147. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/tools/__init__.py +0 -0
  148. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/tools/agent_bricks_tool.py +0 -0
  149. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/tools/ds_asset_tool.py +0 -0
  150. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/tools/genie_tool.py +0 -0
  151. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/tools/mcp_tool.py +0 -0
  152. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/tools/model_endpoint_tool.py +0 -0
  153. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/tools/vector_tool.py +0 -0
  154. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/services/validator.py +0 -0
  155. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/__init__.py +0 -0
  156. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/css_utils.py +0 -0
  157. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/ds_asset_utils.py +0 -0
  158. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/error_handling.py +0 -0
  159. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/html_safety.py +0 -0
  160. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/html_utils.py +0 -0
  161. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/image_utils.py +0 -0
  162. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/js_validator.py +0 -0
  163. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/logging_config.py +0 -0
  164. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/pi_filter.py +0 -0
  165. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/slide_hash.py +0 -0
  166. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/src/utils/spotlight.py +0 -0
  167. {databricks_tellr_app-0.4.2.dev13 → databricks_tellr_app-0.4.2.dev14}/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.2.dev13
3
+ Version: 0.4.2.dev14
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-tellr-app
3
- Version: 0.4.2.dev13
3
+ Version: 0.4.2.dev14
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "databricks-tellr-app"
7
- version = "0.4.2.dev13"
7
+ version = "0.4.2.dev14"
8
8
  description = "Tellr application package for Databricks Apps"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -102,8 +102,22 @@ def build_slide_html(slide: dict, slide_deck: dict) -> str:
102
102
  }
103
103
  )
104
104
 
105
+ # NO `crossorigin` — deliberately, and it must stay that way (WM-02).
106
+ #
107
+ # `crossorigin="anonymous"` turns these into CORS requests. cdn.tailwindcss.com
108
+ # answers with a 302 and no CORS headers, so the request failed with
109
+ # net::ERR_FAILED and Tailwind's Preflight never landed — measured consequence
110
+ # on a DS-OFF deck: h3 rendered 22px/600 in the exported file against
111
+ # 16px/400 on screen, up to 38.25 px of per-component drift and a heading
112
+ # losing a line to re-wrap. The frontend surfaces emit the same tag WITHOUT the
113
+ # attribute (see buildSlideDocument in frontend/src/services/slideDocument.ts)
114
+ # and it loads, so dropping it is parity with what the user actually saw.
115
+ #
116
+ # Safe to drop on its own because there is NO `integrity` attribute here: with
117
+ # SRI present, removing `crossorigin` would block the script outright and turn
118
+ # a 38 px drift into no styling at all.
105
119
  scripts_html = "\n".join([
106
- f' <script src="{src}" crossorigin="anonymous"></script>'
120
+ f' <script src="{src}"></script>'
107
121
  for src in external_scripts
108
122
  ])
109
123
 
@@ -148,6 +162,27 @@ def build_slide_html(slide: dict, slide_deck: dict) -> str:
148
162
  font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
149
163
  }}
150
164
  {deck_css}
165
+ /* After deck CSS: the fixed-frame document owns its OWN box (WM-01).
166
+ The html/body rule above is emitted BEFORE the deck, so a deck-authored
167
+ `body {{ padding: 48px 0; gap: 48px }}` — real generator output — used to win
168
+ on order and translate the WHOLE slide down: `.slide` measured at y=48, and
169
+ the .pptx carried that offset on every positioned component (dy 46-48 px)
170
+ including the background rectangle, whose bottom then sat at 768 inside a
171
+ 720 frame. So: a 48 px unpainted band at the top of every exported slide and
172
+ 48 px of content pushed past the clip.
173
+ Restated HERE, after the deck, exactly as the frontend preview surfaces
174
+ already do it (SLIDE_PREVIEW_RESET_STYLE is appended after the deck CSS in
175
+ buildSlideDocument), so the export agrees with what the user saw on screen.
176
+ Deliberately NOT added to the shared SLIDE_ROOT_RESET_STYLE: that constant is
177
+ also injected into the standalone MULTI-slide export, whose scrolling layout
178
+ depends on `body {{ padding: 40px 20px }}`.
179
+ No `!important`, matching the frontend rule: it wins by ORDER at equal
180
+ specificity, so both surfaces treat a deck's `!important` body padding the
181
+ same way and cannot drift apart. */
182
+ html, body {{
183
+ margin: 0;
184
+ padding: 0;
185
+ }}
151
186
  /* After deck CSS: flatten the slide root (outer margin / radius / shadow) —
152
187
  inside this fixed 1280x720 overflow:hidden document a root margin
153
188
  shifts content past the clip and truncates the export's bottom edge
@@ -25,6 +25,7 @@ import re
25
25
  import unicodedata
26
26
  from collections import OrderedDict
27
27
  from typing import Any, List, Optional, cast
28
+ from urllib.parse import unquote
28
29
 
29
30
  from fastapi import APIRouter, Depends, File, Form, HTTPException, Response, UploadFile, status
30
31
  from pydantic import BaseModel, Field
@@ -833,6 +834,60 @@ def set_default_design_system(ds_id: int, db: Session = Depends(get_db)):
833
834
  )
834
835
 
835
836
 
837
+ # SDR-4437 HIGH-3: workspace-global library writes are admin-only. REMOVING the
838
+ # org default is the same org-wide state change as setting it, so it carries the
839
+ # same gate — authorship must not buy it.
840
+ @router.post(
841
+ "/{ds_id}/clear-default", response_model=DesignSystemDetail,
842
+ dependencies=[Depends(require_admin)],
843
+ )
844
+ def clear_default_design_system(ds_id: int, db: Session = Depends(get_db)):
845
+ """Remove the org-wide default, returning the library to "no default".
846
+
847
+ The lifecycle used to be ASYMMETRIC: ``set-default`` could promote a system and
848
+ switch between systems, but nothing could withdraw the flag — so returning to
849
+ no-default meant DELETING the design system or promoting a different one, and
850
+ the legacy slide-style fallback was unreachable in practice. Generation then
851
+ resolves no design system (``get_default_design_system_id`` returns None) and
852
+ new sessions take the legacy path.
853
+
854
+ Idempotent: clearing a system that is not the default succeeds and changes
855
+ nothing, so a double-click cannot produce an error to interpret.
856
+
857
+ Deliberately asymmetric with ``set-default``, which refuses an INACTIVE row:
858
+ promoting a tombstone into org-wide state is wrong, but REMOVING org-wide state
859
+ is always the safe direction and must never be blocked — refusing it would
860
+ strand the flag with no way to withdraw it.
861
+
862
+ Clearing correctly UNFREEZES rename/delete for the row's author: the freeze in
863
+ :func:`_require_creator_or_admin` is a function of the LOADED row's
864
+ ``is_default``, so it lifts when the flag does. That grants a non-admin nothing
865
+ new, because this route is itself admin-only.
866
+ """
867
+ try:
868
+ ds = db.query(DesignSystem).filter(DesignSystem.id == ds_id).first()
869
+ if not ds:
870
+ raise HTTPException(
871
+ status_code=status.HTTP_404_NOT_FOUND,
872
+ detail=f"Design system {ds_id} not found",
873
+ )
874
+ if ds.is_default:
875
+ ds.is_default = False
876
+ db.commit()
877
+ db.refresh(ds)
878
+ logger.info(f"Cleared default design system: {ds.name} (id={ds.id})")
879
+ return _detail(ds)
880
+ except HTTPException:
881
+ raise
882
+ except Exception as e:
883
+ db.rollback()
884
+ logger.error(f"Error clearing default design system {ds_id}: {e}", exc_info=True)
885
+ raise HTTPException(
886
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
887
+ detail="Failed to clear default design system",
888
+ )
889
+
890
+
836
891
  def _template_thumbnail_url(ds_id: int, template_id: int) -> str:
837
892
  return f"/api/settings/design-systems/{ds_id}/templates/{template_id}/thumbnail"
838
893
 
@@ -1180,6 +1235,35 @@ _TEXT_SOURCE_MIMES = frozenset(
1180
1235
  # pass — only ever seen in double-encoding smuggling attempts, so reject outright.
1181
1236
  _ENCODED_TRAVERSAL_RE = re.compile(r"%(2e|2f|5c)", re.IGNORECASE)
1182
1237
 
1238
+ # How many decode passes a value may need before it stops changing. A value still
1239
+ # mutating after this many is pathological, never a real bundle path, and is
1240
+ # refused rather than normalized (see :func:`_validated_file_path`).
1241
+ _MAX_DECODE_PASSES = 4
1242
+
1243
+
1244
+ def _has_canonical_shape(value: str) -> bool:
1245
+ """True when ``value`` has the shape of a canonical bundle-relative path.
1246
+
1247
+ The SHAPE half of :func:`_validated_file_path`, factored out so the exact same
1248
+ rules can be re-applied to each decoded form of a request path — one source of
1249
+ truth, rather than a second, weaker copy of the checks.
1250
+ """
1251
+ if not value or "\\" in value:
1252
+ return False
1253
+ # NUL / C0 control characters never appear in a legitimate stored path, and
1254
+ # NUL in particular must be rejected BEFORE the DB lookup: psycopg2 refuses
1255
+ # NUL in a bound parameter (ValueError), which would surface as a 500
1256
+ # instead of the uniform opaque 404 (SQLite masks this as a no-match 404).
1257
+ if any(ord(ch) < 0x20 for ch in value):
1258
+ return False
1259
+ if _ENCODED_TRAVERSAL_RE.search(value):
1260
+ return False
1261
+ if value.startswith("/") or re.match(r"^[A-Za-z]:", value):
1262
+ return False
1263
+ if any(segment in ("", ".", "..") for segment in value.split("/")):
1264
+ return False
1265
+ return True
1266
+
1183
1267
 
1184
1268
  def _validated_file_path(raw: str) -> Optional[str]:
1185
1269
  """Return ``raw`` when it is a canonical bundle-relative path, else ``None``.
@@ -1190,22 +1274,32 @@ def _validated_file_path(raw: str) -> Optional[str]:
1190
1274
  backslashes, absolute/drive paths, empty/``.``/``..`` segments, and lingering
1191
1275
  percent-encoded traversal bytes all fail. Lookups are DB-exact within one
1192
1276
  design system (no filesystem involved), so this is defence-in-depth.
1277
+
1278
+ MULTIPLY-ENCODED forms are refused too. ``_ENCODED_TRAVERSAL_RE`` matches a
1279
+ lingering ``%2e``/``%2f``/``%5c``, but in ``%252e`` the traversal is hidden
1280
+ behind its own encoded ``%``, so ONE pass of that check cannot see it. The
1281
+ value is therefore decoded repeatedly and every intermediate form must satisfy
1282
+ the same shape rules; a value that keeps decoding into a traversal is refused
1283
+ at any depth.
1284
+
1285
+ The refusal keys on TRAVERSAL, never on the ``%`` character: a literal ``%``
1286
+ is legitimate in a brand's own filename, and an escape that decodes to
1287
+ something harmless (``%41`` -> ``A``) stays accepted. Rejecting ``%`` outright
1288
+ would turn a brand's real file into a 404 — the same class of brand-hostile
1289
+ limit the uncapped-text columns exist to avoid.
1193
1290
  """
1194
- if not raw or "\\" in raw:
1195
- return None
1196
- # NUL / C0 control characters never appear in a legitimate stored path, and
1197
- # NUL in particular must be rejected BEFORE the DB lookup: psycopg2 refuses
1198
- # NUL in a bound parameter (ValueError), which would surface as a 500
1199
- # instead of the uniform opaque 404 (SQLite masks this as a no-match 404).
1200
- if any(ord(ch) < 0x20 for ch in raw):
1201
- return None
1202
- if _ENCODED_TRAVERSAL_RE.search(raw):
1203
- return None
1204
- if raw.startswith("/") or re.match(r"^[A-Za-z]:", raw):
1205
- return None
1206
- if any(segment in ("", ".", "..") for segment in raw.split("/")):
1291
+ if not _has_canonical_shape(raw):
1207
1292
  return None
1208
- return raw
1293
+ candidate = raw
1294
+ for _ in range(_MAX_DECODE_PASSES):
1295
+ decoded = unquote(candidate)
1296
+ if decoded == candidate:
1297
+ return raw
1298
+ if not _has_canonical_shape(decoded):
1299
+ return None
1300
+ candidate = decoded
1301
+ # Still changing after _MAX_DECODE_PASSES: refuse rather than keep unwrapping.
1302
+ return None
1209
1303
 
1210
1304
 
1211
1305
  def _is_text_source(path: str, mime: str) -> bool:
@@ -312,6 +312,44 @@ def _get_prompt_content(
312
312
  }
313
313
 
314
314
 
315
+ def _design_system_is_active(design_system_id: int) -> bool:
316
+ """True when that design system exists and is ACTIVE.
317
+
318
+ The tool gate below needs the same verdict the prompt branch reaches at
319
+ :func:`_get_prompt_content` (``.filter_by(id=…, is_active=True)``, else
320
+ *"Design system not found, using default"*), so both halves of a generation
321
+ request agree about whether a design system is in play.
322
+
323
+ NOT the same question as ``chat_service.resolve_active_design_system_id``,
324
+ despite the name: that resolves the ``{{ds-asset:ID}}`` scope for a deck
325
+ RESPONSE and deliberately still resolves a soft-deleted system's bytes, so
326
+ already-generated decks keep their fonts and images (the D7 retention
327
+ contract). This is the AUTHORING question — may new content be made against
328
+ this brand — and a tombstone answers no.
329
+
330
+ Fails CLOSED. A lookup error degrades exactly the way the prompt branch does
331
+ (no brand material) rather than advertising a tool whose own lookup would fail
332
+ in the same breath.
333
+ """
334
+ try:
335
+ from src.core.database import get_db_session
336
+ from src.database.models import DesignSystem
337
+
338
+ with get_db_session() as db:
339
+ return (
340
+ db.query(DesignSystem.id)
341
+ .filter_by(id=design_system_id, is_active=True)
342
+ .first()
343
+ is not None
344
+ )
345
+ except Exception as e:
346
+ logger.error(
347
+ f"Failed to resolve design_system_id for tool registration: {e}",
348
+ extra={"design_system_id": design_system_id},
349
+ )
350
+ return False
351
+
352
+
315
353
  def _build_tools(
316
354
  config: AgentConfig,
317
355
  session_data: dict[str, Any],
@@ -351,12 +389,21 @@ def _build_tools(
351
389
  )
352
390
  tools.append(image_search_tool)
353
391
 
354
- # Brand-asset search tool — ONLY when a design system is selected (state
355
- # guard). Bound to the design_system_id via closure so it surfaces only that
356
- # system's assets; the compiled style's ASSET CONTRACT tells the model to call
357
- # it. Gated on design_system_id alone — a pinned template_id (Phase 4) shapes
358
- # prompt assembly only and never changes tool registration.
359
- if config.design_system_id is not None:
392
+ # Brand-asset search tool — ONLY when a selected design system is ACTIVE.
393
+ # Bound to the design_system_id via closure so it surfaces only that system's
394
+ # assets; the compiled style's ASSET CONTRACT tells the model to call it. A
395
+ # pinned template_id (Phase 4) shapes prompt assembly only and never changes
396
+ # tool registration.
397
+ #
398
+ # The is_active half matters because a session keeps its pin after the design
399
+ # system is soft-deleted: on the id alone, generation got a fully working brand
400
+ # tool for a TOMBSTONE (measured: "Found 2 brand asset(s)" with embeddable
401
+ # handles) while the prompt branch, which does filter is_active, supplied no
402
+ # brand at all — so new content was authored against a deleted brand with none
403
+ # of its instructions. Both halves now answer the same question.
404
+ if config.design_system_id is not None and _design_system_is_active(
405
+ config.design_system_id
406
+ ):
360
407
  tools.append(build_ds_asset_tool(config.design_system_id))
361
408
 
362
409
  genie_index = 0
@@ -43,6 +43,13 @@ class JailResult:
43
43
  returncode: int
44
44
  timed_out: bool
45
45
  stderr_tail: str = ""
46
+ #: Per-slide outcomes reported by the trusted runner, in the order received:
47
+ #: True when the slide's generated code produced its slide, False when the
48
+ #: deterministic placeholder fallback was used. EMPTY when the runner reported
49
+ #: nothing (a runner with no result channel, or one that died before emitting) —
50
+ #: callers must treat empty as "unknown", never as "all failed", so an absent
51
+ #: channel cannot manufacture a failure.
52
+ slide_results: tuple = ()
46
53
 
47
54
 
48
55
  @dataclass
@@ -177,8 +184,14 @@ def _spawn(
177
184
 
178
185
  assert proc.stdout is not None
179
186
 
187
+ slide_results: List[bool] = []
188
+
180
189
  def _drain_stdout():
181
190
  for line in proc.stdout:
191
+ result = protocol.decode_slide_result(line)
192
+ if result is not None:
193
+ slide_results.append(result[1])
194
+ continue
182
195
  decoded = protocol.decode_progress(line)
183
196
  if decoded and progress_cb:
184
197
  try:
@@ -207,6 +220,7 @@ def _spawn(
207
220
  returncode=proc.returncode if proc.returncode is not None else -1,
208
221
  timed_out=timed_out,
209
222
  stderr_tail="".join(stderr_lines[-40:]),
223
+ slide_results=tuple(slide_results),
210
224
  )
211
225
  finally:
212
226
  shutil.rmtree(env["HOME"], ignore_errors=True)
@@ -106,14 +106,22 @@ def run(job_dir: str, output_path: str, emit: Optional[Callable[[str], None]] =
106
106
  sdir = Path(job_dir) / entry["dir"]
107
107
  assets_dir = str(sdir / protocol.ASSETS_DIR)
108
108
 
109
+ # Report whether this slide got REAL content or the deterministic
110
+ # placeholder. Both fallback branches below are invisible in the saved
111
+ # file — it is a valid .pptx either way — so the host cannot otherwise
112
+ # tell an all-placeholder deck from a good one.
113
+ rendered = True
109
114
  if not entry.get("has_code"):
110
115
  _add_fallback(prs, i, f"Slide {i}")
116
+ rendered = False
111
117
  else:
112
118
  html_str = (sdir / protocol.HTML_NAME).read_text(encoding="utf-8")
113
119
  code = (sdir / protocol.CODE_NAME).read_text(encoding="utf-8")
114
120
  if not _exec_snippet(code, prs, html_str, assets_dir):
115
121
  _add_fallback(prs, i, "Slide Content")
122
+ rendered = False
116
123
 
124
+ emit(protocol.encode_slide_result(entry["index"], rendered))
117
125
  emit(protocol.encode_progress(i, total, f"Building slide {i}/{total}…"))
118
126
 
119
127
  prs.save(output_path)
@@ -23,6 +23,39 @@ HTML_NAME = "html.txt"
23
23
  ASSETS_DIR = "assets"
24
24
 
25
25
 
26
+ # Sentinel prefix for the trusted per-slide RESULT channel. Same trust property as
27
+ # PROGRESS_PREFIX and for the same reason: only the trusted runner emits it, and
28
+ # generated code's stdout is redirected to stderr before any snippet executes, so a
29
+ # snippet cannot forge a result for itself. The host needs this because whether a
30
+ # slide produced REAL content is only known after validation and execution — a
31
+ # non-empty snippet can still be rejected by the import allowlist or raise when it
32
+ # runs, and both outcomes fall back to a placeholder slide. Without a report, an
33
+ # all-placeholder deck is indistinguishable from a good one.
34
+ RESULT_PREFIX = "@@TELLR_JAIL_SLIDE_RESULT@@ "
35
+
36
+
37
+ def encode_slide_result(index: int, rendered: bool) -> str:
38
+ """Encode one per-slide outcome as a single stdout line (with newline).
39
+
40
+ ``rendered`` is True only when the slide's own generated code ran and produced
41
+ its slide; False whenever the deterministic placeholder fallback was used.
42
+ """
43
+ payload = json.dumps({"index": index, "rendered": bool(rendered)})
44
+ return f"{RESULT_PREFIX}{payload}\n"
45
+
46
+
47
+ def decode_slide_result(line: str):
48
+ """Decode a stdout line into ``(index, rendered)``, or None when the line is
49
+ not a slide-result line / is malformed."""
50
+ if not line.startswith(RESULT_PREFIX):
51
+ return None
52
+ try:
53
+ data = json.loads(line[len(RESULT_PREFIX):].strip())
54
+ return int(data["index"]), bool(data["rendered"])
55
+ except (ValueError, KeyError, TypeError):
56
+ return None
57
+
58
+
26
59
  def encode_progress(current: int, total: int, message: str) -> str:
27
60
  """Encode one progress event as a single stdout line (with newline)."""
28
61
  payload = json.dumps({"current": current, "total": total, "message": message})