databricks-tellr-app 0.4.3.dev3458__tar.gz → 0.4.3.dev3460__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/databricks_tellr_app.egg-info/SOURCES.txt +4 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/pyproject.toml +1 -1
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/slides.py +37 -14
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/chat_service.py +145 -119
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/session_manager.py +555 -86
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/slide_repository.py +240 -13
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/skills/architect.py +35 -4
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/usage_event.py +2 -1
- databricks_tellr_app-0.4.3.dev3460/src/domain/deck_spec_slides.py +347 -0
- databricks_tellr_app-0.4.3.dev3460/src/domain/slide_alignment.py +198 -0
- databricks_tellr_app-0.4.3.dev3460/src/services/agent_definition_manifest_v1.py +3 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph/nodes.py +524 -56
- databricks_tellr_app-0.4.3.dev3458/src/services/agent_definition_manifest_v1.py +0 -3
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/README.md +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/databricks_tellr_app/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/databricks_tellr_app/run.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/databricks_tellr_app.egg-info/requires.txt +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/databricks_tellr_app.egg-info/top_level.txt +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/setup.cfg +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/setup.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/_otel_bootstrap.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/fixtures/tour_demo_deck.json +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/main.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/mcp_auth.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/mcp_server.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/middleware/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/middleware/csrf.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/middleware/request_logging.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/middleware/security_headers.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/_authz.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/admin.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/admin_usage.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/agent_definitions.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/chat.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/deck_contributors.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/export.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/google_slides.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/images.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/local_version.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/profiles.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/sessions.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/settings/contributors.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/settings/deck_prompts.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/settings/design_systems.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/settings/identities.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/settings/slide_styles.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/setup.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/tools.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/tour.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/verification.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/version.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/agent_definitions.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/graph_release_history.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/graph_releases.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/requests.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/responses.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/settings/requests.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/settings/responses.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/schemas/streaming.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/deck_level_writer.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/export_job_queue.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/feedback_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/job_queue.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/session_naming.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/usage_events.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/services/usage_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/utils/validation.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/backfill_session_slides_startup.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/checkpointer.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/config_loader.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/context_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/database.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/databricks_client.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/encryption.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/init_default_profile.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/lakebase.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/migrate_profiles_to_agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/mlflow_agent_spans.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/mlflow_tracing.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/otel_logging.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/permission_context.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/prompt_modules.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/settings_db.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/skills/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/skills/build_reviewer.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/skills/builder.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/skills/data_analyst.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/skills/deck_reviewer.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/skills/fix_reviewer.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/skills/fixer.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/strip_retired_prompt_keys.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/core/user_context.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/data_migration.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/deck_contributor.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/deck_review.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/design_system.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/encryption_key.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/genie_space.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/google_global_credentials.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/google_oauth_token.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/graph_checkpoint.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/graph_configuration.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/identity.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/image.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/profile.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/profile_contributor.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/prompts.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/request_log.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/session.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/slide_deck_prompt.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/slide_style_library.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/models/user_preference.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/database/types.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/conversation_engine.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/conversation_turns.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/deck_spec.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/finding.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/finding_copy.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/skill_io.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/slide.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/slide_deck.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/domain/slide_numbering.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent_factory.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent_model_payload.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent_resolution.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent_runtime.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent_runtime_identity.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent_schema_registry.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent_schema_types.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/agent_test_workbench.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/collaboration_history.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/config_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/config_validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/conversation_pins.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/converter_jail/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/converter_jail/ast_guard.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/converter_jail/codeprep.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/converter_jail/gslides_runner.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/converter_jail/jail.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/converter_jail/pptx_runner.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/converter_jail/protocol.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/deck_css_aggregator.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/deck_review_store.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/design_system_compiler.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/design_system_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/design_system_templates.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/drive_uploader.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/evaluation/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/evaluation/llm_judge.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/foreman_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/gateway_openai.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/genie_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/google_slides_auth.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/google_slides_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph/builder.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph/event_emitter.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph/progress.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph/routers.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph/state.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph/user_notices.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_configuration.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_configuration_bootstrap.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_configuration_content.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_configuration_draft.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_configuration_publication.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_configuration_rollback.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_configuration_seed.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_configuration_workbench.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_definition_manifest.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_release_evidence.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/graph_release_history.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/html_to_google_slides.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/html_to_pptx.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/identity_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/identity_providers/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/identity_providers/account_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/identity_providers/local_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/identity_providers/scim_filter.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/identity_providers/workspace_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/image_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/image_tools.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/model_endpoint_catalog.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/model_endpoint_probe.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/permission_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/persisted_graph_release.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/pptx_from_html_huashu.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/pptx_from_records.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/pptx_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/profile_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/prompt_assembler.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/shared_deck_attribution.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/spec_sync.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/streaming_callback.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/svg_sanitizer.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/template_sections.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/tools/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/tools/agent_bricks_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/tools/ds_asset_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/tools/genie_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/tools/mcp_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/tools/model_endpoint_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/tools/vector_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/services/validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/css_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/ds_asset_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/error_handling.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/graph_safety.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/html_safety.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/html_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/image_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/js_validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/logging_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/pi_filter.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/slide_hash.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/spotlight.py +0 -0
- {databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/utils/text_caps.py +0 -0
|
@@ -123,10 +123,12 @@ setup.py
|
|
|
123
123
|
./src/domain/conversation_engine.py
|
|
124
124
|
./src/domain/conversation_turns.py
|
|
125
125
|
./src/domain/deck_spec.py
|
|
126
|
+
./src/domain/deck_spec_slides.py
|
|
126
127
|
./src/domain/finding.py
|
|
127
128
|
./src/domain/finding_copy.py
|
|
128
129
|
./src/domain/skill_io.py
|
|
129
130
|
./src/domain/slide.py
|
|
131
|
+
./src/domain/slide_alignment.py
|
|
130
132
|
./src/domain/slide_deck.py
|
|
131
133
|
./src/domain/slide_numbering.py
|
|
132
134
|
./src/services/__init__.py
|
|
@@ -356,10 +358,12 @@ src/domain/__init__.py
|
|
|
356
358
|
src/domain/conversation_engine.py
|
|
357
359
|
src/domain/conversation_turns.py
|
|
358
360
|
src/domain/deck_spec.py
|
|
361
|
+
src/domain/deck_spec_slides.py
|
|
359
362
|
src/domain/finding.py
|
|
360
363
|
src/domain/finding_copy.py
|
|
361
364
|
src/domain/skill_io.py
|
|
362
365
|
src/domain/slide.py
|
|
366
|
+
src/domain/slide_alignment.py
|
|
363
367
|
src/domain/slide_deck.py
|
|
364
368
|
src/domain/slide_numbering.py
|
|
365
369
|
src/services/__init__.py
|
{databricks_tellr_app-0.4.3.dev3458 → databricks_tellr_app-0.4.3.dev3460}/src/api/routes/slides.py
RENAMED
|
@@ -11,7 +11,10 @@ Slide access is controlled by session permissions:
|
|
|
11
11
|
The spec-dirty trigger lives in THIS module and nowhere else
|
|
12
12
|
------------------------------------------------------------
|
|
13
13
|
Five handlers below call ``spec_sync.mark_dirty`` after their mutation commits:
|
|
14
|
-
insert, reorder, update, duplicate and delete.
|
|
14
|
+
insert, reorder, update, duplicate and delete. Insert marks only when it carries
|
|
15
|
+
``html``: a blank insert (the viewer's "New slide") splices a spec entry that is
|
|
16
|
+
already the exact description of the blank, in the same transaction as the rows, so
|
|
17
|
+
there is nothing for the sweeper to describe. That is the whole of the trigger surface —
|
|
15
18
|
the LangGraph deck build calls the ``chat_service`` / ``slide_repository`` /
|
|
16
19
|
``deck_level_writer`` methods these handlers wrap, and never issues an HTTP
|
|
17
20
|
request, so "arrived via a route" *means* "a human did this" by construction. No
|
|
@@ -41,9 +44,12 @@ from src.api.routes._authz import (
|
|
|
41
44
|
_check_deck_permission_for_session,
|
|
42
45
|
_require_slide_permission,
|
|
43
46
|
)
|
|
44
|
-
from src.api.
|
|
47
|
+
from src.api.routes.sessions import CONVERSATION_BUSY_DETAIL
|
|
48
|
+
from src.api.services.chat_service import ArcReviewInFlightError, get_chat_service
|
|
45
49
|
from src.api.services.session_manager import (
|
|
50
|
+
DeckBusyError,
|
|
46
51
|
SessionNotFoundError,
|
|
52
|
+
SlideRowsChangedError,
|
|
47
53
|
VersionConflictError,
|
|
48
54
|
get_session_manager,
|
|
49
55
|
)
|
|
@@ -58,6 +64,12 @@ logger = logging.getLogger(__name__)
|
|
|
58
64
|
|
|
59
65
|
router = APIRouter(prefix="/api/slides", tags=["slides"])
|
|
60
66
|
|
|
67
|
+
# The insert's rows moved between the viewer's deck and the write (another editor, or
|
|
68
|
+
# a stale worker cache): nothing was written, and a refresh followed by a retry works.
|
|
69
|
+
DECK_CHANGED_DETAIL = (
|
|
70
|
+
"The deck changed while the slide was being added. Refresh and try again."
|
|
71
|
+
)
|
|
72
|
+
|
|
61
73
|
|
|
62
74
|
class ReorderRequest(BaseModel):
|
|
63
75
|
"""Request to reorder slides."""
|
|
@@ -93,8 +105,8 @@ class InsertSlideRequest(BaseModel):
|
|
|
93
105
|
as counting backwards from the end and land the slide somewhere the caller did
|
|
94
106
|
not ask for.
|
|
95
107
|
|
|
96
|
-
``html`` is optional: omitted,
|
|
97
|
-
architect to fill.
|
|
108
|
+
``html`` is optional: omitted, the deck's blank shell (its own slide frame with
|
|
109
|
+
nothing on it) is inserted for a human or the architect to fill.
|
|
98
110
|
"""
|
|
99
111
|
|
|
100
112
|
session_id: str
|
|
@@ -168,12 +180,15 @@ async def insert_slide(request: InsertSlideRequest, db: Session = Depends(get_db
|
|
|
168
180
|
request: InsertSlideRequest with session_id, position and optional html
|
|
169
181
|
|
|
170
182
|
Returns:
|
|
171
|
-
Updated slide deck
|
|
183
|
+
Updated slide deck, plus ``inserted_slide_id`` and ``inserted_position``
|
|
184
|
+
(the viewer selects the slide it just inserted from them)
|
|
172
185
|
|
|
173
186
|
Raises:
|
|
174
187
|
HTTPException: 403 if no permission, 400 for validation errors, 409 if
|
|
175
|
-
|
|
176
|
-
|
|
188
|
+
something is running on the deck (``CONVERSATION_BUSY_DETAIL``), the
|
|
189
|
+
deck's rows moved under the insert (``DECK_CHANGED_DETAIL``) or the
|
|
190
|
+
version is stale, 423 if another user holds the editing lock, 500 on
|
|
191
|
+
error
|
|
177
192
|
"""
|
|
178
193
|
_require_slide_permission(request.session_id, db, PermissionLevel.CAN_EDIT)
|
|
179
194
|
|
|
@@ -189,10 +204,8 @@ async def insert_slide(request: InsertSlideRequest, db: Session = Depends(get_db
|
|
|
189
204
|
request.session_id,
|
|
190
205
|
)
|
|
191
206
|
if not locked:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
detail="Session is currently processing another request. Please wait.",
|
|
195
|
-
)
|
|
207
|
+
# The lock belongs to whoever holds it: do not release it.
|
|
208
|
+
raise HTTPException(status_code=409, detail=CONVERSATION_BUSY_DETAIL)
|
|
196
209
|
|
|
197
210
|
try:
|
|
198
211
|
chat_service = get_chat_service()
|
|
@@ -202,6 +215,7 @@ async def insert_slide(request: InsertSlideRequest, db: Session = Depends(get_db
|
|
|
202
215
|
request.position,
|
|
203
216
|
html=request.html,
|
|
204
217
|
expected_version=request.expected_version,
|
|
218
|
+
inserted_by=get_current_user(),
|
|
205
219
|
)
|
|
206
220
|
|
|
207
221
|
logger.info(
|
|
@@ -209,11 +223,20 @@ async def insert_slide(request: InsertSlideRequest, db: Session = Depends(get_db
|
|
|
209
223
|
extra={"position": request.position, "session_id": request.session_id},
|
|
210
224
|
)
|
|
211
225
|
# A slide was added: the deck's slide list no longer matches the spec's.
|
|
212
|
-
#
|
|
213
|
-
#
|
|
214
|
-
|
|
226
|
+
# An insert that carries HTML has no description yet (the spliced spec entry
|
|
227
|
+
# is blank), so this is what schedules the arc review of it. A blank insert
|
|
228
|
+
# (no html) is already exactly described by that blank entry, so it
|
|
229
|
+
# schedules nothing.
|
|
230
|
+
if request.html is not None:
|
|
231
|
+
await asyncio.to_thread(mark_dirty, request.session_id, get_current_user())
|
|
215
232
|
return result
|
|
216
233
|
|
|
234
|
+
except (ArcReviewInFlightError, DeckBusyError):
|
|
235
|
+
# An arc review holds a claim on the deck, or a turn is running on another
|
|
236
|
+
# session of it; nothing was written and the insert can be retried.
|
|
237
|
+
raise HTTPException(status_code=409, detail=CONVERSATION_BUSY_DETAIL)
|
|
238
|
+
except SlideRowsChangedError:
|
|
239
|
+
raise HTTPException(status_code=409, detail=DECK_CHANGED_DETAIL)
|
|
217
240
|
except VersionConflictError as e:
|
|
218
241
|
raise HTTPException(status_code=409, detail=str(e))
|
|
219
242
|
except PermissionError as e:
|
|
@@ -8,6 +8,7 @@ its scripts are automatically replaced with it - no separate cleanup needed.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import contextvars
|
|
11
|
+
import copy
|
|
11
12
|
import logging
|
|
12
13
|
import queue
|
|
13
14
|
import re
|
|
@@ -40,6 +41,13 @@ from src.domain.conversation_engine import (
|
|
|
40
41
|
selects_graph_engine,
|
|
41
42
|
)
|
|
42
43
|
from src.domain.conversation_turns import turn_message_ids
|
|
44
|
+
# BLANK_SLIDE_HTML is re-exported: callers and tests import it from here.
|
|
45
|
+
from src.domain.deck_spec_slides import (
|
|
46
|
+
BLANK_DECK_SPEC_ENTRY,
|
|
47
|
+
BLANK_SLIDE_HTML as BLANK_SLIDE_HTML,
|
|
48
|
+
blank_slide_shell,
|
|
49
|
+
renumber_spec_slides,
|
|
50
|
+
)
|
|
43
51
|
from src.domain.slide import Slide, has_slide_wrapper
|
|
44
52
|
from src.domain.slide_deck import SlideDeck
|
|
45
53
|
from src.api.schemas.agent_config import resolve_agent_config
|
|
@@ -62,27 +70,17 @@ from src.utils.ds_asset_utils import (
|
|
|
62
70
|
substitute_ds_asset_placeholders,
|
|
63
71
|
)
|
|
64
72
|
from src.utils.image_utils import substitute_deck_dict_images, substitute_image_placeholders
|
|
73
|
+
from src.utils.slide_hash import compute_slide_hash
|
|
65
74
|
|
|
66
75
|
logger = logging.getLogger(__name__)
|
|
67
76
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
# The deck-spec entry a newly inserted slide gets: contiguous with its neighbours
|
|
76
|
-
# (`DeckSpec.slide_at` depends on that) and deliberately undescribed. The route
|
|
77
|
-
# that inserts fires the spec-dirty marker and the arc-review sweeper writes the
|
|
78
|
-
# prose; inventing a purpose here would put words in the architect's mouth.
|
|
79
|
-
_BLANK_DECK_SPEC_ENTRY: Dict[str, Any] = {
|
|
80
|
-
"purpose": "",
|
|
81
|
-
"content_brief": "",
|
|
82
|
-
"assumes": "",
|
|
83
|
-
"hands_off": "",
|
|
84
|
-
"data_references": [],
|
|
85
|
-
}
|
|
77
|
+
# The deck-spec entry a newly inserted slide gets (defined in
|
|
78
|
+
# src.domain.deck_spec_slides): contiguous with its neighbours (`DeckSpec.slide_at`
|
|
79
|
+
# depends on that) and deliberately undescribed. The spliced entry is the blank's
|
|
80
|
+
# description; inventing a purpose here would put words in the architect's mouth.
|
|
81
|
+
# SessionManager.insert_slide splices it, in the same transaction as the rows; this
|
|
82
|
+
# alias stays so there is one definition and callers that import it from here work.
|
|
83
|
+
_BLANK_DECK_SPEC_ENTRY = BLANK_DECK_SPEC_ENTRY
|
|
86
84
|
|
|
87
85
|
|
|
88
86
|
def _pinned_graph_failure_release_id(
|
|
@@ -3940,13 +3938,30 @@ class ChatService:
|
|
|
3940
3938
|
*,
|
|
3941
3939
|
html: Optional[str] = None,
|
|
3942
3940
|
expected_version: Optional[int] = None,
|
|
3941
|
+
inserted_by: Optional[str] = None,
|
|
3943
3942
|
) -> Dict[str, Any]:
|
|
3944
3943
|
"""Insert a new slide at *position*, shifting every higher slide up.
|
|
3945
3944
|
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3945
|
+
The write is ONE transaction in :meth:`SessionManager.insert_slide`: the
|
|
3946
|
+
rows (moved with the exact old-row map, so every existing slide keeps its
|
|
3947
|
+
identity, attribution, verdict and fragment), the deck spec's blank entry,
|
|
3948
|
+
the deck columns, one version bump and the evidence. This method plans
|
|
3949
|
+
the insert against a COPY of the cached deck and hands the writer the rows
|
|
3950
|
+
it planned against (``expected_rows``): a cache that has drifted from the
|
|
3951
|
+
database is a ``SlideRowsChangedError`` (a 409 at the route) and writes
|
|
3952
|
+
nothing, never a write-back of the stale deck.
|
|
3953
|
+
|
|
3954
|
+
WHAT THE NEW SLIDE IS
|
|
3955
|
+
---------------------
|
|
3956
|
+
With *html* it is stored verbatim. Without it, it is the deck's blank
|
|
3957
|
+
shell (:func:`blank_slide_shell` over this deck's slides at the landing
|
|
3958
|
+
position): the deck's own frame with nothing on it, so it looks like a
|
|
3959
|
+
blank slide of THIS deck. Its ``slide_id`` is minted here, and it is
|
|
3960
|
+
stamped with the current user and one explicit ``created_at`` /
|
|
3961
|
+
``modified_at``: the writer fabricates no timestamps, so a slide inserted
|
|
3962
|
+
while the username lookup fails still carries its creation time. The
|
|
3963
|
+
other slides' ids are left alone (no reindex): an id-less legacy row stays
|
|
3964
|
+
id-less, and the writer's map depends on it.
|
|
3950
3965
|
|
|
3951
3966
|
WHICH LAYER OWNS THE OUT-OF-RANGE CLAMP
|
|
3952
3967
|
---------------------------------------
|
|
@@ -3959,27 +3974,46 @@ class ChatService:
|
|
|
3959
3974
|
(``insert(-1, x)`` lands second-to-last, not last). A negative position is
|
|
3960
3975
|
therefore rejected rather than clamped: it almost certainly means the
|
|
3961
3976
|
caller computed it wrongly, and quietly inserting somewhere else is worse
|
|
3962
|
-
than a 400.
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3977
|
+
than a 400. The check comes BEFORE ``landed`` and the shell are computed:
|
|
3978
|
+
``min(-1, n)`` is -1, which would feed the shell a negative scan index.
|
|
3979
|
+
|
|
3980
|
+
``landed`` is computed BEFORE the insert precisely because of that clamp —
|
|
3981
|
+
after it, ``position`` may not be where the slide actually is, and the
|
|
3982
|
+
shell is derived for where the slide really goes.
|
|
3983
|
+
|
|
3984
|
+
THE CACHE
|
|
3985
|
+
---------
|
|
3986
|
+
The cached deck is never mutated before the write (the insert is built on a
|
|
3987
|
+
``copy.deepcopy``), and it is invalidated on EVERY exit, so a refused write
|
|
3988
|
+
leaves no ghost slide in this worker's cache and a stale-rows 409 heals on
|
|
3989
|
+
the next try. After a successful write the deck is reloaded from the
|
|
3990
|
+
database, and that reloaded deck is what the save point snapshots and the
|
|
3991
|
+
response carries.
|
|
3967
3992
|
|
|
3968
3993
|
Args:
|
|
3969
3994
|
session_id: Session ID. A contributor session resolves to its deck
|
|
3970
3995
|
owner in the layers below, exactly as every other mutation does.
|
|
3971
3996
|
position: 0-based position to insert at. Beyond the end appends.
|
|
3972
3997
|
html: HTML for the new slide. Must carry a ``<div class="slide">``
|
|
3973
|
-
wrapper. Omitted,
|
|
3974
|
-
architect to fill.
|
|
3998
|
+
wrapper. Omitted, the deck's blank shell is inserted for a human
|
|
3999
|
+
or the architect to fill.
|
|
3975
4000
|
expected_version: If provided, reject the write when the deck has moved on.
|
|
4001
|
+
inserted_by: The editor, for the ``slide_inserted`` usage event; None
|
|
4002
|
+
writes none.
|
|
3976
4003
|
|
|
3977
4004
|
Returns:
|
|
3978
|
-
|
|
4005
|
+
The reloaded slide deck dictionary plus ``inserted_slide_id`` and
|
|
4006
|
+
``inserted_position`` (where the slide landed), which the viewer uses
|
|
4007
|
+
to select the slide it just inserted.
|
|
3979
4008
|
|
|
3980
4009
|
Raises:
|
|
3981
4010
|
ValueError: If no slide deck exists, position is negative, or the
|
|
3982
4011
|
supplied HTML has no slide wrapper.
|
|
4012
|
+
VersionConflictError: *expected_version* is stale.
|
|
4013
|
+
SlideRowsChangedError: The committed rows are not the rows this insert
|
|
4014
|
+
planned against (the cache was stale).
|
|
4015
|
+
ArcReviewInFlightError: The deck's arc review holds a live claim.
|
|
4016
|
+
DeckBusyError: A turn holds another session of this deck.
|
|
3983
4017
|
"""
|
|
3984
4018
|
current_deck = self._get_or_load_deck(session_id)
|
|
3985
4019
|
if not current_deck:
|
|
@@ -3988,14 +4022,34 @@ class ChatService:
|
|
|
3988
4022
|
if position < 0:
|
|
3989
4023
|
raise ValueError(f"Invalid slide position: {position}")
|
|
3990
4024
|
|
|
3991
|
-
|
|
4025
|
+
# Where the slide will ACTUALLY be, given the domain's clamp.
|
|
4026
|
+
landed = min(position, len(current_deck.slides))
|
|
4027
|
+
|
|
4028
|
+
slide_html = (
|
|
4029
|
+
html
|
|
4030
|
+
if html is not None
|
|
4031
|
+
else blank_slide_shell([s.html for s in current_deck.slides], landed)
|
|
4032
|
+
)
|
|
3992
4033
|
if not has_slide_wrapper(slide_html):
|
|
3993
4034
|
raise ValueError("HTML must contain <div class='slide'> wrapper")
|
|
3994
4035
|
|
|
3995
|
-
#
|
|
3996
|
-
|
|
4036
|
+
# The rows this insert plans against, read off the cached deck BEFORE the
|
|
4037
|
+
# copy: the writer re-reads the committed rows and refuses (409) unless
|
|
4038
|
+
# they are exactly these. The cached html equals the row's html.
|
|
4039
|
+
expected_rows = [
|
|
4040
|
+
(s.slide_id, compute_slide_hash(s.html or "")) for s in current_deck.slides
|
|
4041
|
+
]
|
|
4042
|
+
|
|
4043
|
+
# Never mutate the cached deck before the write: build on a copy.
|
|
4044
|
+
working = copy.deepcopy(current_deck)
|
|
3997
4045
|
|
|
3998
|
-
|
|
4046
|
+
created = datetime.utcnow().isoformat() + "Z"
|
|
4047
|
+
new_slide = Slide(
|
|
4048
|
+
html=slide_html,
|
|
4049
|
+
slide_id=str(uuid.uuid4()),
|
|
4050
|
+
created_at=created,
|
|
4051
|
+
modified_at=created,
|
|
4052
|
+
)
|
|
3999
4053
|
try:
|
|
4000
4054
|
_user = get_current_username()
|
|
4001
4055
|
except Exception:
|
|
@@ -4003,36 +4057,42 @@ class ChatService:
|
|
|
4003
4057
|
if _user:
|
|
4004
4058
|
new_slide.stamp_created(_user)
|
|
4005
4059
|
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
self._reindex_slide_ids(current_deck)
|
|
4060
|
+
working.insert_slide(new_slide, position)
|
|
4009
4061
|
|
|
4010
|
-
|
|
4011
|
-
deck_dict = current_deck.to_dict()
|
|
4062
|
+
deck_dict = working.to_dict()
|
|
4012
4063
|
session_manager = get_session_manager()
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
title=current_deck.title,
|
|
4016
|
-
html_content=current_deck.knit(),
|
|
4017
|
-
scripts_content=current_deck.scripts,
|
|
4018
|
-
slide_count=len(current_deck.slides),
|
|
4019
|
-
deck_dict=deck_dict,
|
|
4020
|
-
expected_version=expected_version,
|
|
4021
|
-
mutation=session_manager.deck_mutation_context(
|
|
4064
|
+
try:
|
|
4065
|
+
write_result = session_manager.insert_slide(
|
|
4022
4066
|
session_id,
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4067
|
+
position,
|
|
4068
|
+
slide=deck_dict["slides"][landed],
|
|
4069
|
+
expected_rows=expected_rows,
|
|
4070
|
+
deck_dict=deck_dict,
|
|
4071
|
+
title=working.title,
|
|
4072
|
+
html_content=working.knit(),
|
|
4073
|
+
scripts_content=working.scripts,
|
|
4074
|
+
mutation=session_manager.deck_mutation_context(
|
|
4075
|
+
session_id,
|
|
4076
|
+
operation="insert_slide",
|
|
4077
|
+
object_type="deck",
|
|
4078
|
+
object_id=new_slide.slide_id,
|
|
4079
|
+
),
|
|
4080
|
+
expected_version=expected_version,
|
|
4081
|
+
inserted_by=inserted_by,
|
|
4082
|
+
)
|
|
4083
|
+
finally:
|
|
4084
|
+
# On every exit: a refused write leaves no ghost, and after a commit
|
|
4085
|
+
# the next load is the database's deck, not a plan.
|
|
4086
|
+
self._invalidate_deck_cache(session_id)
|
|
4029
4087
|
|
|
4030
|
-
#
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
self.
|
|
4088
|
+
# Prefer the writer's position: it is where the row actually landed.
|
|
4089
|
+
landed_at = write_result.get("position", landed)
|
|
4090
|
+
|
|
4091
|
+
reloaded: Optional[SlideDeck] = None
|
|
4092
|
+
try:
|
|
4093
|
+
reloaded = self._get_or_load_deck(session_id)
|
|
4094
|
+
except Exception as e:
|
|
4095
|
+
logger.warning(f"Failed to reload deck after insert_slide: {e}")
|
|
4036
4096
|
|
|
4037
4097
|
# ONE save point for the whole operation, after the work commits.
|
|
4038
4098
|
# VERSION_LIMIT evicts the OLDEST version, so a save point per shifted
|
|
@@ -4041,7 +4101,7 @@ class ChatService:
|
|
|
4041
4101
|
self.create_save_point(
|
|
4042
4102
|
session_id=session_id,
|
|
4043
4103
|
description=f"Inserted slide {landed_at + 1}",
|
|
4044
|
-
deck=
|
|
4104
|
+
deck=reloaded if reloaded is not None else working,
|
|
4045
4105
|
)
|
|
4046
4106
|
except Exception as e:
|
|
4047
4107
|
logger.warning(f"Failed to create save point (insert_slide): {e}")
|
|
@@ -4051,13 +4111,16 @@ class ChatService:
|
|
|
4051
4111
|
extra={
|
|
4052
4112
|
"requested_position": position,
|
|
4053
4113
|
"position": landed_at,
|
|
4054
|
-
"new_count": len(
|
|
4114
|
+
"new_count": write_result.get("slide_count", len(working.slides)),
|
|
4055
4115
|
"session_id": session_id,
|
|
4056
4116
|
},
|
|
4057
4117
|
)
|
|
4058
4118
|
|
|
4059
|
-
|
|
4060
|
-
|
|
4119
|
+
result = reloaded.to_dict() if reloaded is not None else deck_dict
|
|
4120
|
+
result, _ = self._substitute_images_for_response(result, session_id=session_id)
|
|
4121
|
+
result["inserted_slide_id"] = new_slide.slide_id
|
|
4122
|
+
result["inserted_position"] = landed_at
|
|
4123
|
+
return result
|
|
4061
4124
|
|
|
4062
4125
|
def _rewrite_deck_spec_slides(
|
|
4063
4126
|
self,
|
|
@@ -4086,9 +4149,13 @@ class ChatService:
|
|
|
4086
4149
|
--------------------------------------
|
|
4087
4150
|
Four hand-copied row-writers diverging is the defect class the previous
|
|
4088
4151
|
workstream's final review found, and C1 is itself an instance of it — insert
|
|
4089
|
-
renumbered, its three siblings did not. So the
|
|
4090
|
-
|
|
4091
|
-
|
|
4152
|
+
renumbered, its three siblings did not. So the three routes that still use
|
|
4153
|
+
this method (delete, duplicate, reorder) supply only *which entries end up in
|
|
4154
|
+
which order*; the position stamping, the raw-dict handling, the author stamp
|
|
4155
|
+
and the failure policy live here once. The fourth, insert, no longer writes
|
|
4156
|
+
the spec through this method at all: ``SessionManager.insert_slide`` splices
|
|
4157
|
+
its blank entry in the same transaction as the rows, through the same pure
|
|
4158
|
+
core (``renumber_spec_slides``), so the two cannot disagree on the renumber.
|
|
4092
4159
|
|
|
4093
4160
|
*reorder* receives the positioned entries **in position order** and returns
|
|
4094
4161
|
the new list in the new order — it does not touch ``position`` at all, which
|
|
@@ -4144,45 +4211,31 @@ class ChatService:
|
|
|
4144
4211
|
)
|
|
4145
4212
|
return None
|
|
4146
4213
|
|
|
4147
|
-
#
|
|
4148
|
-
#
|
|
4149
|
-
positioned: List[Dict[str, Any]] = []
|
|
4150
|
-
unpositioned: List[Any] = []
|
|
4151
|
-
for entry in slides:
|
|
4152
|
-
if isinstance(entry, dict) and isinstance(entry.get("position"), int):
|
|
4153
|
-
positioned.append(entry)
|
|
4154
|
-
else:
|
|
4155
|
-
unpositioned.append(entry)
|
|
4156
|
-
positioned.sort(key=lambda e: e["position"])
|
|
4157
|
-
|
|
4214
|
+
# The split, the reorder and the re-stamp are the pure core, shared with the
|
|
4215
|
+
# manual insert's transaction (src.domain.deck_spec_slides).
|
|
4158
4216
|
try:
|
|
4159
|
-
|
|
4217
|
+
spec = renumber_spec_slides(spec, reorder)
|
|
4160
4218
|
except IndexError:
|
|
4161
4219
|
# The route validated its index against the DECK, so an index the spec
|
|
4162
4220
|
# cannot answer means the two have already drifted. Leaving a drifted
|
|
4163
4221
|
# spec alone is recoverable; renumbering it against the wrong slides is
|
|
4164
|
-
# not.
|
|
4222
|
+
# not. The count is the entries renumber_spec_slides handed to reorder.
|
|
4223
|
+
positioned = sum(
|
|
4224
|
+
1
|
|
4225
|
+
for entry in slides
|
|
4226
|
+
if isinstance(entry, dict) and isinstance(entry.get("position"), int)
|
|
4227
|
+
)
|
|
4165
4228
|
logger.warning(
|
|
4166
4229
|
"deck spec has %s entries and cannot answer this mutation; "
|
|
4167
4230
|
"leaving it untouched",
|
|
4168
|
-
|
|
4231
|
+
positioned,
|
|
4169
4232
|
extra={"session_id": session_id, "route": label},
|
|
4170
4233
|
)
|
|
4171
4234
|
return None
|
|
4172
4235
|
|
|
4173
|
-
if
|
|
4236
|
+
if spec is None:
|
|
4174
4237
|
return None
|
|
4175
4238
|
|
|
4176
|
-
renumbered: List[Any] = []
|
|
4177
|
-
for index, entry in enumerate(rewritten):
|
|
4178
|
-
entry = dict(entry)
|
|
4179
|
-
entry["position"] = index
|
|
4180
|
-
renumbered.append(entry)
|
|
4181
|
-
renumbered.extend(unpositioned)
|
|
4182
|
-
|
|
4183
|
-
spec = dict(spec)
|
|
4184
|
-
spec["slides"] = renumbered
|
|
4185
|
-
|
|
4186
4239
|
try:
|
|
4187
4240
|
_user = get_current_username()
|
|
4188
4241
|
except Exception:
|
|
@@ -4198,33 +4251,6 @@ class ChatService:
|
|
|
4198
4251
|
logger.warning(f"Failed to write deck spec ({label}): {e}")
|
|
4199
4252
|
return None
|
|
4200
4253
|
|
|
4201
|
-
def _insert_deck_spec_slide(
|
|
4202
|
-
self,
|
|
4203
|
-
session_id: str,
|
|
4204
|
-
position: int,
|
|
4205
|
-
) -> Optional[Dict[str, Any]]:
|
|
4206
|
-
"""Give the deck spec a placeholder entry at *position*, shifting the rest up.
|
|
4207
|
-
|
|
4208
|
-
*position* is where the slide ACTUALLY landed, which the caller computes
|
|
4209
|
-
before the insert: ``SlideDeck.insert_slide`` delegates to ``list.insert``,
|
|
4210
|
-
which clamps a too-large position into an append, so the requested position
|
|
4211
|
-
and the real one diverge on an append. The clamp is re-applied here against
|
|
4212
|
-
the spec's own length rather than trusted, because a spec shorter than the
|
|
4213
|
-
deck would otherwise leave a hole.
|
|
4214
|
-
"""
|
|
4215
|
-
|
|
4216
|
-
def _splice(entries: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
4217
|
-
landed = min(position, len(entries))
|
|
4218
|
-
return (
|
|
4219
|
-
entries[:landed]
|
|
4220
|
-
+ [dict(_BLANK_DECK_SPEC_ENTRY)]
|
|
4221
|
-
+ entries[landed:]
|
|
4222
|
-
)
|
|
4223
|
-
|
|
4224
|
-
return self._rewrite_deck_spec_slides(
|
|
4225
|
-
session_id, _splice, label="insert_slide"
|
|
4226
|
-
)
|
|
4227
|
-
|
|
4228
4254
|
def _delete_deck_spec_slide(
|
|
4229
4255
|
self,
|
|
4230
4256
|
session_id: str,
|