databricks-tellr-app 0.5.1.dev1__tar.gz → 0.5.1.dev2__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.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/PKG-INFO +1 -1
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/databricks_tellr_app.egg-info/SOURCES.txt +2 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/pyproject.toml +1 -1
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/session_manager.py +58 -6
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/slide_repository.py +149 -20
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/architect.py +85 -50
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/skill_io.py +23 -4
- databricks_tellr_app-0.5.1.dev2/src/domain/slide_operations.py +520 -0
- databricks_tellr_app-0.5.1.dev2/src/services/agent_definition_manifest_v1.py +3 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent_model_payload.py +4 -2
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent_schema_registry.py +4 -2
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph/nodes.py +1122 -231
- databricks_tellr_app-0.5.1.dev1/src/services/agent_definition_manifest_v1.py +0 -3
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/README.md +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/databricks_tellr_app/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/databricks_tellr_app/run.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/databricks_tellr_app.egg-info/requires.txt +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/databricks_tellr_app.egg-info/top_level.txt +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/setup.cfg +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/setup.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/_otel_bootstrap.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/fixtures/tour_demo_deck.json +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/main.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/mcp_auth.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/mcp_server.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/middleware/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/middleware/csrf.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/middleware/request_logging.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/middleware/security_headers.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/_authz.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/admin.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/admin_usage.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/agent_config.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/agent_definitions.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/chat.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/deck_contributors.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/export.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/feedback.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/google_slides.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/images.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/local_version.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/profiles.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/sessions.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/settings/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/settings/contributors.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/settings/deck_prompts.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/settings/design_systems.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/settings/identities.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/settings/slide_styles.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/setup.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/slides.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/tools.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/tour.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/verification.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/routes/version.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/agent_config.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/agent_definitions.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/feedback.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/graph_release_history.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/graph_releases.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/requests.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/responses.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/settings/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/settings/requests.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/settings/responses.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/schemas/streaming.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/chat_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/deck_level_writer.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/export_job_queue.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/feedback_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/job_queue.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/session_naming.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/slide_style_preview_queue.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/usage_events.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/services/usage_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/utils/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/api/utils/validation.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/backfill_session_slides_startup.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/checkpointer.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/config_loader.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/context_utils.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/database.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/databricks_client.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/defaults.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/encryption.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/init_default_profile.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/lakebase.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/migrate_profiles_to_agent_config.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/mlflow_agent_spans.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/mlflow_tracing.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/otel_logging.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/permission_context.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/prompt_modules.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/settings_db.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/build_reviewer.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/builder.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/data_analyst.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/deck_reviewer.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/fix_reviewer.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/fixer.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/strip_retired_prompt_keys.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/user_context.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/data_migration.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/deck_contributor.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/deck_review.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/design_system.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/encryption_key.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/feedback.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/genie_space.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/google_global_credentials.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/google_oauth_token.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/graph_checkpoint.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/graph_configuration.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/identity.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/image.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/profile.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/profile_contributor.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/prompts.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/request_log.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/session.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/slide_deck_prompt.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/slide_style_library.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/slide_style_preview.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/usage_event.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/models/user_preference.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/database/types.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/conversation_engine.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/conversation_turns.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/deck_spec.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/deck_spec_slides.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/finding.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/finding_copy.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/slide.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/slide_alignment.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/slide_deck.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/domain/slide_numbering.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent_factory.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent_resolution.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent_runtime.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent_runtime_identity.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent_schema_types.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/agent_test_workbench.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/collaboration_history.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/config_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/config_validator.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/conversation_pins.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/converter_jail/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/converter_jail/ast_guard.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/converter_jail/codeprep.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/converter_jail/gslides_runner.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/converter_jail/jail.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/converter_jail/pptx_runner.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/converter_jail/protocol.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/deck_css_aggregator.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/deck_review_store.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/design_system_compiler.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/design_system_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/design_system_templates.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/drive_uploader.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/evaluation/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/evaluation/llm_judge.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/foreman_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/gateway_openai.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/genie_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/google_slides_auth.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/google_slides_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph/builder.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph/event_emitter.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph/progress.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph/routers.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph/state.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph/user_notices.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_configuration.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_configuration_bootstrap.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_configuration_content.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_configuration_draft.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_configuration_publication.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_configuration_rollback.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_configuration_seed.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_configuration_workbench.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_definition_manifest.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_release_evidence.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/graph_release_history.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/html_to_google_slides.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/html_to_pptx.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/identity_provider.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/identity_providers/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/identity_providers/account_provider.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/identity_providers/local_provider.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/identity_providers/scim_filter.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/identity_providers/workspace_provider.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/image_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/image_tools.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/model_endpoint_catalog.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/model_endpoint_probe.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/permission_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/persisted_graph_release.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/pptx_from_html_huashu.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/pptx_from_records.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/pptx_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/profile_service.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/prompt_assembler.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/shared_deck_attribution.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/slide_style_preview_fixture.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/slide_style_preview_storage.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/spec_sync.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/streaming_callback.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/svg_sanitizer.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/template_sections.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/tools/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/tools/agent_bricks_tool.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/tools/ds_asset_tool.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/tools/genie_tool.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/tools/mcp_tool.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/tools/model_endpoint_tool.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/tools/vector_tool.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/services/validator.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/__init__.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/css_utils.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/ds_asset_utils.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/error_handling.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/graph_safety.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/html_safety.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/html_utils.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/image_utils.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/js_validator.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/logging_config.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/pi_filter.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/slide_hash.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/spotlight.py +0 -0
- {databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/utils/text_caps.py +0 -0
|
@@ -133,6 +133,7 @@ setup.py
|
|
|
133
133
|
./src/domain/slide_alignment.py
|
|
134
134
|
./src/domain/slide_deck.py
|
|
135
135
|
./src/domain/slide_numbering.py
|
|
136
|
+
./src/domain/slide_operations.py
|
|
136
137
|
./src/services/__init__.py
|
|
137
138
|
./src/services/agent.py
|
|
138
139
|
./src/services/agent_definition_manifest_v1.py
|
|
@@ -372,6 +373,7 @@ src/domain/slide.py
|
|
|
372
373
|
src/domain/slide_alignment.py
|
|
373
374
|
src/domain/slide_deck.py
|
|
374
375
|
src/domain/slide_numbering.py
|
|
376
|
+
src/domain/slide_operations.py
|
|
375
377
|
src/services/__init__.py
|
|
376
378
|
src/services/agent.py
|
|
377
379
|
src/services/agent_definition_manifest_v1.py
|
|
@@ -854,26 +854,78 @@ def _splice_slide_rows(
|
|
|
854
854
|
f"{new_count} positions"
|
|
855
855
|
)
|
|
856
856
|
|
|
857
|
+
layout = []
|
|
858
|
+
old_index = 0
|
|
859
|
+
for new_index in range(new_count):
|
|
860
|
+
if new_index in new_slides:
|
|
861
|
+
layout.append(None)
|
|
862
|
+
else:
|
|
863
|
+
layout.append(old_index)
|
|
864
|
+
old_index += 1
|
|
865
|
+
_lay_out_slide_rows(db, owner_id, old_rows, layout, new_slides)
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
def _lay_out_slide_rows(
|
|
869
|
+
db: Session,
|
|
870
|
+
owner_id: int,
|
|
871
|
+
old_rows: List[SessionSlide],
|
|
872
|
+
layout: Sequence[Optional[int]],
|
|
873
|
+
new_slides: Mapping[int, Tuple[Dict[str, Any], Dict[str, Any]]],
|
|
874
|
+
) -> None:
|
|
875
|
+
"""THE shift primitive: lay a deck's rows out in any order, with the EXACT map.
|
|
876
|
+
|
|
877
|
+
``layout[i]`` is the INDEX into ``old_rows`` (position order) whose row lands
|
|
878
|
+
at new index ``i``, or ``None`` for a new slide, whose
|
|
879
|
+
``(slide_dict, incoming_record)`` is ``new_slides[i]``. An old index may
|
|
880
|
+
appear at most once; one that is absent is deleted (pruned, with its record
|
|
881
|
+
and spec fragment). ``_splice_slide_rows`` is the in-order special case.
|
|
882
|
+
|
|
883
|
+
1. Every old row is snapshotted (:func:`_snapshot_row`) and attributed
|
|
884
|
+
(:func:`_attribution_from`) BEFORE any write: ``_upsert_slide_row``
|
|
885
|
+
rewrites those ORM rows in place.
|
|
886
|
+
2. Every position is rewritten through ``_rewrite_slide_rows`` with that exact
|
|
887
|
+
map, never the attribution heuristic, and with ``now_dt=None`` /
|
|
888
|
+
``author_fallback=None``, so a moved row with a NULL author or timestamp
|
|
889
|
+
stays NULL and no moved row gets a fresh ``modified_at``.
|
|
890
|
+
3. Rows beyond ``len(layout)`` are pruned (inside ``_rewrite_slide_rows``).
|
|
891
|
+
|
|
892
|
+
Raises:
|
|
893
|
+
ValueError: the layout is malformed (an old index repeated or outside
|
|
894
|
+
``range(len(old_rows))``, or ``new_slides`` keys that are not exactly
|
|
895
|
+
the ``None`` indices). Raised before anything is written.
|
|
896
|
+
"""
|
|
897
|
+
layout = list(layout)
|
|
898
|
+
old_count = len(old_rows)
|
|
899
|
+
kept = [index for index in layout if index is not None]
|
|
900
|
+
bad = sorted({index for index in kept if not 0 <= index < old_count})
|
|
901
|
+
if bad:
|
|
902
|
+
raise ValueError(f"layout names old rows {bad} outside range({old_count})")
|
|
903
|
+
if len(set(kept)) != len(kept):
|
|
904
|
+
raise ValueError(f"layout names an old row more than once: {layout}")
|
|
905
|
+
new_positions = {i for i, index in enumerate(layout) if index is None}
|
|
906
|
+
if set(new_slides) != new_positions:
|
|
907
|
+
raise ValueError(
|
|
908
|
+
f"new_slides keys {sorted(new_slides)} are not the layout's new "
|
|
909
|
+
f"positions {sorted(new_positions)}"
|
|
910
|
+
)
|
|
911
|
+
|
|
857
912
|
# 1. Snapshots and attributions from the ORM rows BEFORE any write.
|
|
858
913
|
snapshots = [_snapshot_row(row) for row in old_rows]
|
|
859
914
|
attributions = [_attribution_from(row) for row in old_rows]
|
|
860
915
|
|
|
861
|
-
# 2. The layout: each new slide at its index, the old rows in order around them.
|
|
862
916
|
slides: List[Dict[str, Any]] = []
|
|
863
917
|
attribution: Dict[int, SlideAttribution] = {}
|
|
864
918
|
incoming: Dict[int, Dict[str, Any]] = {}
|
|
865
|
-
old_index
|
|
866
|
-
|
|
867
|
-
if new_index in new_slides:
|
|
919
|
+
for new_index, old_index in enumerate(layout):
|
|
920
|
+
if old_index is None:
|
|
868
921
|
slide_dict, record = new_slides[new_index]
|
|
869
922
|
slides.append(slide_dict)
|
|
870
923
|
incoming[new_index] = record
|
|
871
924
|
else:
|
|
872
925
|
slides.append(snapshots[old_index])
|
|
873
926
|
attribution[new_index] = attributions[old_index]
|
|
874
|
-
old_index += 1
|
|
875
927
|
|
|
876
|
-
# 3. THE whole-deck rewrite, with the exact map.
|
|
928
|
+
# 2-3. THE whole-deck rewrite, with the exact map, then the prune.
|
|
877
929
|
_rewrite_slide_rows(
|
|
878
930
|
db,
|
|
879
931
|
owner_id,
|
|
@@ -25,8 +25,8 @@ from sqlalchemy import and_
|
|
|
25
25
|
from src.api.services.session_manager import (
|
|
26
26
|
SessionManager,
|
|
27
27
|
SlideRowsChangedError,
|
|
28
|
+
_lay_out_slide_rows,
|
|
28
29
|
_snapshot_row, # noqa: F401 — re-exported; it moved to session_manager
|
|
29
|
-
_splice_slide_rows,
|
|
30
30
|
get_session_manager,
|
|
31
31
|
)
|
|
32
32
|
from src.core.database import get_db_session
|
|
@@ -465,8 +465,9 @@ class SlideWriter:
|
|
|
465
465
|
EXACT old-row map, never the attribution heuristic, and with
|
|
466
466
|
``now_dt=None``/``author_fallback=None``, so a moved row with a NULL
|
|
467
467
|
author or timestamp stays NULL and no moved row gets a fresh
|
|
468
|
-
``modified_at``. Steps 2-4 are ``session_manager.
|
|
469
|
-
the one shift primitive, shared with
|
|
468
|
+
``modified_at``. Steps 2-4 are ``session_manager._lay_out_slide_rows``
|
|
469
|
+
(via :meth:`apply_slide_layout`), the one shift primitive, shared with
|
|
470
|
+
``SessionManager.insert_slide``.
|
|
470
471
|
5. ``deck_spec_json`` is set to *deck_spec*, ``version`` is bumped (which
|
|
471
472
|
invalidates every worker's deck cache) and ``last_activity`` touched.
|
|
472
473
|
``slide_count`` is NOT written: its single writer is the post-commit
|
|
@@ -516,8 +517,103 @@ class SlideWriter:
|
|
|
516
517
|
"insert_pending_slides records an insert_slide/deck mutation, not "
|
|
517
518
|
f"{mutation.operation}/{mutation.object_type}"
|
|
518
519
|
)
|
|
519
|
-
expected = [(slide_id, content_hash) for slide_id, content_hash in expected_rows]
|
|
520
520
|
spec_count = len(spec.slides)
|
|
521
|
+
if insert_at[-1] >= spec_count:
|
|
522
|
+
raise ValueError(
|
|
523
|
+
f"insert_at {insert_at} is beyond the spec's {spec_count} slides"
|
|
524
|
+
)
|
|
525
|
+
layout: List[Optional[int]]
|
|
526
|
+
if not expected_rows:
|
|
527
|
+
# Row-less (spec-only) deck: no rows to lay out, only None slots.
|
|
528
|
+
layout = [None] * len(insert_at)
|
|
529
|
+
else:
|
|
530
|
+
new_count = len(expected_rows) + len(insert_at)
|
|
531
|
+
if insert_at[-1] >= new_count:
|
|
532
|
+
raise ValueError(
|
|
533
|
+
f"insert_at {insert_at} is beyond the shifted deck's "
|
|
534
|
+
f"{new_count} slides"
|
|
535
|
+
)
|
|
536
|
+
# The in-order layout: the old rows in order around each inserted index.
|
|
537
|
+
layout = []
|
|
538
|
+
old_index = 0
|
|
539
|
+
for new_index in range(new_count):
|
|
540
|
+
if new_index in insert_at:
|
|
541
|
+
layout.append(None)
|
|
542
|
+
else:
|
|
543
|
+
layout.append(old_index)
|
|
544
|
+
old_index += 1
|
|
545
|
+
return self.apply_slide_layout(
|
|
546
|
+
session_id,
|
|
547
|
+
layout,
|
|
548
|
+
deck_spec=deck_spec,
|
|
549
|
+
expected_rows=expected_rows,
|
|
550
|
+
created_by=created_by,
|
|
551
|
+
mutation=mutation,
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
def apply_slide_layout(
|
|
555
|
+
self,
|
|
556
|
+
session_id: str,
|
|
557
|
+
layout: Sequence[Optional[int]],
|
|
558
|
+
*,
|
|
559
|
+
deck_spec: str,
|
|
560
|
+
expected_rows: Sequence[Tuple[Optional[str], str]],
|
|
561
|
+
created_by: Optional[str],
|
|
562
|
+
mutation: DeckMutationContext,
|
|
563
|
+
) -> List[str]:
|
|
564
|
+
"""Lay the deck's rows out as *layout*: move, delete and insert in one transaction.
|
|
565
|
+
|
|
566
|
+
The general form of :meth:`insert_pending_slides`. ``layout[i]`` is the
|
|
567
|
+
INDEX into the current rows (position order) that lands at new index
|
|
568
|
+
``i``, or ``None`` for a pending placeholder (``PENDING_SLIDE_TEXT``,
|
|
569
|
+
fresh ``slide_id``, authored by *created_by*). A current row whose index
|
|
570
|
+
is absent is deleted. Every kept row keeps its whole identity
|
|
571
|
+
(``slide_id``, authorship, timestamps, verification record, spec
|
|
572
|
+
fragment), through ``session_manager._lay_out_slide_rows``.
|
|
573
|
+
|
|
574
|
+
One ``get_db_session()`` transaction: the rows are re-read and
|
|
575
|
+
``[(slide_id, content_hash)]`` must equal *expected_rows*
|
|
576
|
+
(:class:`SlideRowsChangedError` otherwise, also for a session with no deck
|
|
577
|
+
row); the layout is validated against the committed rows; the rows are
|
|
578
|
+
laid out; ``deck_spec_json`` is set to *deck_spec*, ``version`` bumped,
|
|
579
|
+
``last_activity`` touched (``slide_count`` is NOT written); and ONE
|
|
580
|
+
mutation event is recorded. A row-less (spec-only) deck takes the last
|
|
581
|
+
two steps only, and its layout must be all ``None``.
|
|
582
|
+
|
|
583
|
+
Args:
|
|
584
|
+
session_id: the requesting session (a contributor writes the owner's deck).
|
|
585
|
+
layout: see above.
|
|
586
|
+
deck_spec: the canonical spec JSON of the deck after the edit; with
|
|
587
|
+
rows, its slide count must equal ``len(layout)``.
|
|
588
|
+
expected_rows: ``[(slide_id, content_hash)]`` the caller planned against.
|
|
589
|
+
created_by: the author of the turn that opens the pending rows.
|
|
590
|
+
mutation: provenance; its actor must be the requesting session, its
|
|
591
|
+
object type ``deck`` and its operation
|
|
592
|
+
``layout_mutation_operation(layout, len(rows))``.
|
|
593
|
+
|
|
594
|
+
Returns:
|
|
595
|
+
The new slides' ``slide_id`` values in ascending new-index order
|
|
596
|
+
(``[]`` for a row-less deck).
|
|
597
|
+
|
|
598
|
+
Raises:
|
|
599
|
+
ValueError: the layout is malformed or the identity; *deck_spec* is
|
|
600
|
+
not a valid DeckSpec or its count differs from the layout's;
|
|
601
|
+
*mutation* does not match the layout; or the evidence write
|
|
602
|
+
refuses the actor.
|
|
603
|
+
SlideRowsChangedError: the committed rows are not *expected_rows*, or
|
|
604
|
+
the session has no deck row.
|
|
605
|
+
SessionNotFoundError: *session_id* does not match any session.
|
|
606
|
+
|
|
607
|
+
Nothing is written on any raise.
|
|
608
|
+
"""
|
|
609
|
+
layout = list(layout)
|
|
610
|
+
kept = [index for index in layout if index is not None]
|
|
611
|
+
if any(index < 0 for index in kept) or len(set(kept)) != len(kept):
|
|
612
|
+
raise ValueError(f"malformed layout: {layout}")
|
|
613
|
+
spec = DeckSpec.from_json(deck_spec)
|
|
614
|
+
if spec is None:
|
|
615
|
+
raise ValueError("deck_spec is not a valid DeckSpec")
|
|
616
|
+
expected = [(slide_id, content_hash) for slide_id, content_hash in expected_rows]
|
|
521
617
|
|
|
522
618
|
with get_db_session() as db:
|
|
523
619
|
session = self.session_manager._get_session_or_raise(db, session_id)
|
|
@@ -527,7 +623,7 @@ class SlideWriter:
|
|
|
527
623
|
# The caller's prior spec came from this row; its absence means
|
|
528
624
|
# the deck changed under the planner.
|
|
529
625
|
raise SlideRowsChangedError(
|
|
530
|
-
f"session {session_id} has no deck row to
|
|
626
|
+
f"session {session_id} has no deck row to lay out"
|
|
531
627
|
)
|
|
532
628
|
|
|
533
629
|
# 1. The rows the caller planned against, or nothing is written.
|
|
@@ -546,29 +642,37 @@ class SlideWriter:
|
|
|
546
642
|
f"planned against ({len(committed)} committed, {len(expected)} "
|
|
547
643
|
"expected)"
|
|
548
644
|
)
|
|
549
|
-
|
|
645
|
+
|
|
646
|
+
# 2. The layout against the committed rows, before any write.
|
|
647
|
+
if any(index >= len(old_rows) for index in kept):
|
|
648
|
+
raise ValueError(
|
|
649
|
+
f"layout {layout} names a row beyond the deck's {len(old_rows)}"
|
|
650
|
+
)
|
|
651
|
+
operation = layout_mutation_operation(layout, len(old_rows))
|
|
652
|
+
if mutation.operation != operation or mutation.object_type != "deck":
|
|
550
653
|
raise ValueError(
|
|
551
|
-
f"
|
|
654
|
+
f"this layout records a {operation}/deck mutation, not "
|
|
655
|
+
f"{mutation.operation}/{mutation.object_type}"
|
|
552
656
|
)
|
|
553
|
-
|
|
554
|
-
if old_rows and spec_count != new_count:
|
|
657
|
+
if old_rows and len(spec.slides) != len(layout):
|
|
555
658
|
raise ValueError(
|
|
556
|
-
f"deck_spec has {
|
|
557
|
-
f"{len(
|
|
659
|
+
f"deck_spec has {len(spec.slides)} slides, but the layout "
|
|
660
|
+
f"makes {len(layout)}"
|
|
558
661
|
)
|
|
559
662
|
|
|
560
663
|
new_ids: List[str] = []
|
|
561
664
|
now = datetime.utcnow()
|
|
562
665
|
if old_rows:
|
|
563
|
-
#
|
|
564
|
-
#
|
|
565
|
-
#
|
|
566
|
-
# whole-deck rewrite with the exact old-row map.
|
|
666
|
+
# 3. A pending placeholder at each None, then THE shift
|
|
667
|
+
# (session_manager._lay_out_slide_rows): snapshots and
|
|
668
|
+
# attributions before any write, the exact-map rewrite, the prune.
|
|
567
669
|
pending_html, pending_record = placeholder_slide(
|
|
568
670
|
PENDING_SLIDE_MESSAGE, text=PENDING_SLIDE_TEXT
|
|
569
671
|
)
|
|
570
672
|
new_slides: Dict[int, Tuple[Dict[str, Any], Dict[str, Any]]] = {}
|
|
571
|
-
for new_index in
|
|
673
|
+
for new_index, old_index in enumerate(layout):
|
|
674
|
+
if old_index is not None:
|
|
675
|
+
continue
|
|
572
676
|
slide_id = str(uuid.uuid4())
|
|
573
677
|
new_ids.append(slide_id)
|
|
574
678
|
new_slides[new_index] = (
|
|
@@ -586,16 +690,16 @@ class SlideWriter:
|
|
|
586
690
|
for content_hash, verdict in pending_record.items()
|
|
587
691
|
},
|
|
588
692
|
)
|
|
589
|
-
|
|
693
|
+
_lay_out_slide_rows(db, deck_owner.id, old_rows, layout, new_slides)
|
|
590
694
|
|
|
591
|
-
#
|
|
695
|
+
# 4. Deck columns, in the same transaction as the rows.
|
|
592
696
|
deck.deck_spec_json = deck_spec
|
|
593
697
|
deck.version = (deck.version or 0) + 1
|
|
594
698
|
session.last_activity = now
|
|
595
699
|
if session.id != deck_owner.id:
|
|
596
700
|
deck_owner.last_activity = now
|
|
597
701
|
|
|
598
|
-
#
|
|
702
|
+
# 5. Evidence; a refusal here rolls the whole layout back.
|
|
599
703
|
db.flush()
|
|
600
704
|
record_shared_deck_mutation(
|
|
601
705
|
db,
|
|
@@ -603,13 +707,38 @@ class SlideWriter:
|
|
|
603
707
|
deck_owner=deck_owner,
|
|
604
708
|
deck=deck,
|
|
605
709
|
actor=mutation.actor,
|
|
606
|
-
operation=
|
|
710
|
+
operation=operation,
|
|
607
711
|
object_type="deck",
|
|
608
712
|
object_id=mutation.object_id,
|
|
609
713
|
)
|
|
610
714
|
return new_ids
|
|
611
715
|
|
|
612
716
|
|
|
717
|
+
def layout_mutation_operation(layout: Sequence[Optional[int]], old_count: int) -> str:
|
|
718
|
+
"""The ``MutationOperation`` that records *layout* over *old_count* current rows.
|
|
719
|
+
|
|
720
|
+
``insert_slide`` when every old index is present in order and at least one
|
|
721
|
+
slot is ``None``; ``delete_slide`` when there is no ``None``, the kept
|
|
722
|
+
indices ascend and some are missing; ``reorder_slides`` when there is no
|
|
723
|
+
``None``, every old index is present and they are out of order;
|
|
724
|
+
``save_deck_slides`` for anything else (a mix).
|
|
725
|
+
|
|
726
|
+
Raises:
|
|
727
|
+
ValueError: the identity layout, which has nothing to write.
|
|
728
|
+
"""
|
|
729
|
+
layout = list(layout)
|
|
730
|
+
kept = [index for index in layout if index is not None]
|
|
731
|
+
if len(kept) != len(layout):
|
|
732
|
+
return "insert_slide" if kept == list(range(old_count)) else "save_deck_slides"
|
|
733
|
+
if kept == list(range(old_count)):
|
|
734
|
+
raise ValueError("the identity layout changes nothing; there is nothing to write")
|
|
735
|
+
if all(a < b for a, b in zip(kept, kept[1:])):
|
|
736
|
+
return "delete_slide"
|
|
737
|
+
if len(kept) == old_count and set(kept) == set(range(old_count)):
|
|
738
|
+
return "reorder_slides"
|
|
739
|
+
return "save_deck_slides"
|
|
740
|
+
|
|
741
|
+
|
|
613
742
|
# ------------------------------------------------------------------
|
|
614
743
|
# Internal helpers
|
|
615
744
|
# ------------------------------------------------------------------
|
{databricks_tellr_app-0.5.1.dev1 → databricks_tellr_app-0.5.1.dev2}/src/core/skills/architect.py
RENAMED
|
@@ -25,8 +25,10 @@ INSTRUCTIONS: str = (
|
|
|
25
25
|
"PAYLOAD RULES:\n"
|
|
26
26
|
" build → deck_spec must be set\n"
|
|
27
27
|
" ask_data → data_request must be set\n"
|
|
28
|
-
" edit →
|
|
29
|
-
"
|
|
28
|
+
" edit → operations must be set for slide changes, and "
|
|
29
|
+
"deck_changes for a deck-level change the user asks for (one or both); "
|
|
30
|
+
"target_positions and deck_spec are not needed, except that re-describing the "
|
|
31
|
+
"deck as it stands returns the full deck_spec\n"
|
|
30
32
|
" confirm_design_contract → proposed_design_contract must be set; "
|
|
31
33
|
"never set deck_spec until the user confirms\n"
|
|
32
34
|
" discuss → message only; no payload required\n\n"
|
|
@@ -71,35 +73,69 @@ INSTRUCTIONS: str = (
|
|
|
71
73
|
"content-bearing section whose frame fits; the exhibit replaces that "
|
|
72
74
|
"section's body while its eyebrow, title and footer stay.\n\n"
|
|
73
75
|
"EDITING (edit intent):\n"
|
|
74
|
-
"On an edit,
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"slide
|
|
101
|
-
"
|
|
102
|
-
"
|
|
76
|
+
"On an edit, return `operations` instead of deck_spec: the ordered list of changes "
|
|
77
|
+
"to make to current_deck_spec. They are applied together as one change, and nothing "
|
|
78
|
+
"else in the deck changes. The operations are:\n"
|
|
79
|
+
" update — `position` and `slides` with exactly one entry: that slide gets this "
|
|
80
|
+
"content and is rebuilt in place\n"
|
|
81
|
+
" replace — `position` and `slides` with one or more entries: that slide becomes "
|
|
82
|
+
"these slides; the first takes its place and the rest follow it directly\n"
|
|
83
|
+
" insert — `after_position` and `slides` with one or more entries: new slides "
|
|
84
|
+
"directly after that slide, in list order; after_position -1 puts them at the start "
|
|
85
|
+
"of the deck\n"
|
|
86
|
+
" delete — `position`: that slide is removed, and nothing is rebuilt\n"
|
|
87
|
+
" move — `position` and `after_position`: that slide moves to directly after the "
|
|
88
|
+
"after_position slide (-1 = to the start); it is not rebuilt and its content does "
|
|
89
|
+
"not change\n"
|
|
90
|
+
"Each entry of `slides` is a SlideSpec without `position`, with slide_type and "
|
|
91
|
+
"template_section_index decided by the VISUAL / TEMPLATE BINDING rules. An update or "
|
|
92
|
+
"a replace describes the whole slide: start from the slide's entry in "
|
|
93
|
+
"current_deck_spec and revise only what the user asked for.\n"
|
|
94
|
+
"Every position and after_position is a position of current_deck_spec, the deck "
|
|
95
|
+
"before this edit, even for a slide that an earlier operation in the list shifts. "
|
|
96
|
+
"Give each slide the user asks about exactly one operation that does everything "
|
|
97
|
+
"asked of it: a slide can be the `position` of at most one operation. Slides placed "
|
|
98
|
+
"after the same slide go directly after it, in the order of their operations; "
|
|
99
|
+
"placed after a replaced slide, they follow all of its replacement slides; placed "
|
|
100
|
+
"after a moved slide, they follow it to its new place; placed after a deleted slide, "
|
|
101
|
+
"they fill its gap. Never move a slide after itself.\n"
|
|
102
|
+
"Changing what a slide says or shows is an update, even when the user says "
|
|
103
|
+
"\"replace\" about something on the slide. Expanding a slide into several slides, "
|
|
104
|
+
"splitting a slide, or replacing a slide with one or more new slides is a replace. "
|
|
105
|
+
"Rebuilding a slide without changing its content is an update with its current "
|
|
106
|
+
"content. Adding slides is an insert, removing a slide is a delete, and reordering "
|
|
107
|
+
"slides is a move.\n"
|
|
108
|
+
"Put each new slide where the user asks. When the user gives no place, put it where "
|
|
109
|
+
"it fits the argument: before the slides that close the deck (a closing or "
|
|
110
|
+
"call-to-action slide), unless the new slide is itself a closing slide. When the "
|
|
111
|
+
"user asks for the new slide to come last, put it after the last slide, even after "
|
|
112
|
+
"a closing slide.\n"
|
|
113
|
+
"Touch only the slides the user asks about: every other slide keeps its content "
|
|
114
|
+
"exactly, and only its number may change. Do not change any other slide to reflect "
|
|
115
|
+
"the edit, not a neighbour's assumes or hands_off and not a slide that lists or sums "
|
|
116
|
+
"up the deck, unless the user asks for that change.\n"
|
|
117
|
+
"Change deck-level fields only when the user asks, and then put only the changed "
|
|
118
|
+
"fields in `deck_changes` (title, audience, purpose, argument, call_to_action, "
|
|
119
|
+
"narrative_arc, design_contract, resolved_data); otherwise leave deck_changes unset. "
|
|
120
|
+
"Do not change narrative_arc to reflect an added, deleted or moved slide unless the "
|
|
121
|
+
"user asks for that change. Keep design_contract unchanged on an edit unless the "
|
|
122
|
+
"user has agreed to the contract you proposed with confirm_design_contract, and then "
|
|
123
|
+
"commit it in deck_changes.design_contract; otherwise a change of design system or "
|
|
124
|
+
"slide style still goes through confirm_design_contract. Keep resolved_data "
|
|
125
|
+
"unchanged unless new data has been fetched for this edit.\n"
|
|
126
|
+
"target_positions is not needed on an edit given as operations: the operations say "
|
|
127
|
+
"which slides are built.\n"
|
|
128
|
+
"Say in message what the edit will do: name each new or moved slide by its slide "
|
|
129
|
+
"number in the revised deck and each deleted slide by the number it had.\n"
|
|
130
|
+
"When the payload carries `rejected_edit`, your previous answer to this message "
|
|
131
|
+
"(`your_previous_answer`) was not applied and nothing in the deck changed; "
|
|
132
|
+
"`problems` lists every reason it was refused. Fix every listed problem and answer "
|
|
133
|
+
"again with the whole corrected answer. If a problem shows that the request cannot "
|
|
134
|
+
"be done as asked, use discuss and say why.\n"
|
|
135
|
+
"The one edit that returns deck_spec is a re-description: when the message asks you "
|
|
136
|
+
"to re-describe the deck as it now stands rather than change it, return the full "
|
|
137
|
+
"deck_spec describing every slide as it is, with target_positions listing its "
|
|
138
|
+
"positions and no operations.\n\n"
|
|
103
139
|
"SLIDESPEC FIELDS (one per slide):\n"
|
|
104
140
|
" position: 0-indexed integer, unique within the deck\n"
|
|
105
141
|
" purpose: what this slide contributes to the narrative arc\n"
|
|
@@ -141,25 +177,24 @@ INSTRUCTIONS: str = (
|
|
|
141
177
|
"and is never the number the user says. The payload's `slide_numbering` maps "
|
|
142
178
|
"each slide of the current deck from its `slide_number` to its `position`, "
|
|
143
179
|
"and `slide_references` lists the slides the user's latest message names by "
|
|
144
|
-
"number or ordinal, already resolved to `positions`. Take
|
|
145
|
-
"from `slide_references` when the user's phrase
|
|
146
|
-
"number or ordinal it does not resolve, look the
|
|
147
|
-
"`slide_numbering`. Never compute a position as the slide number
|
|
148
|
-
"A reference with numbers in `out_of_range` names a slide this deck
|
|
149
|
-
"have: do not edit; use discuss and say how many slides the deck has.
|
|
150
|
-
"the user names a slide by its content rather than its number, find it
|
|
151
|
-
"current_deck_spec. A reference says which slide the user means, not that "
|
|
180
|
+
"number or ordinal, already resolved to `positions`. Take each operation's "
|
|
181
|
+
"position and after_position from `slide_references` when the user's phrase "
|
|
182
|
+
"was resolved; for a slide number or ordinal it does not resolve, look the "
|
|
183
|
+
"slide up in `slide_numbering`. Never compute a position as the slide number "
|
|
184
|
+
"minus one. A reference with numbers in `out_of_range` names a slide this deck "
|
|
185
|
+
"does not have: do not edit; use discuss and say how many slides the deck has. "
|
|
186
|
+
"When the user names a slide by its content rather than its number, find it "
|
|
187
|
+
"in current_deck_spec. A reference says which slide the user means, not that "
|
|
152
188
|
"they want it changed: decide the intent from what the user asks for.\n"
|
|
153
|
-
"
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"slide
|
|
157
|
-
"slide
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"`position` and `target_positions` stay 0-indexed.\n\n"
|
|
189
|
+
"Read every slide number in an edit against `slide_numbering`, the deck before "
|
|
190
|
+
"the edit, even when the same message also adds, deletes or moves slides. A "
|
|
191
|
+
"slide the user names to say where a new or moved slide goes is its anchor, not "
|
|
192
|
+
"a slide to change. A slide placed after the named slide takes the named "
|
|
193
|
+
"slide's position as after_position. A slide placed before the named slide, or "
|
|
194
|
+
"given the named slide's number, takes as after_position the position of the "
|
|
195
|
+
"slide just before the named one in `slide_numbering`, or -1 when the named "
|
|
196
|
+
"slide is the first.\n"
|
|
197
|
+
"In `message` only, speak about slides 1-indexed, matching the UI. `position`, "
|
|
198
|
+
"`after_position` and `target_positions` stay 0-indexed.\n\n"
|
|
164
199
|
"Return an ArchitectOutput. Do not include prose outside the structured output."
|
|
165
200
|
)
|
|
@@ -26,6 +26,7 @@ from pydantic import BaseModel, field_validator, model_validator
|
|
|
26
26
|
|
|
27
27
|
from src.domain.deck_spec import DeckSpec, DesignContractRef
|
|
28
28
|
from src.domain.finding import DeckReviewOutput, SlideReviewOutput
|
|
29
|
+
from src.domain.slide_operations import DeckChanges, SlideOperation
|
|
29
30
|
|
|
30
31
|
# ---------------------------------------------------------------------------
|
|
31
32
|
# Primitive unions — CLOSED
|
|
@@ -70,13 +71,23 @@ class ArchitectOutput(BaseModel):
|
|
|
70
71
|
----------------------
|
|
71
72
|
- ``intent='build'`` → ``deck_spec`` must be present
|
|
72
73
|
- ``intent='ask_data'`` → ``data_request`` must be present
|
|
73
|
-
- ``intent='edit'`` → ``target_positions`` must be non-empty
|
|
74
|
+
- ``intent='edit'`` → ``target_positions`` must be non-empty,
|
|
75
|
+
or ``operations`` / ``deck_changes``
|
|
76
|
+
must be present
|
|
74
77
|
- ``intent='confirm_design_contract'`` → ``proposed_design_contract`` must be present
|
|
75
78
|
- ``intent='discuss'`` → no payload required
|
|
76
79
|
|
|
77
80
|
``confirm_design_contract`` holds its proposal in ``proposed_design_contract``
|
|
78
81
|
— never in ``deck_spec`` — so no downstream node restyles before the user
|
|
79
82
|
answers (§4.6/§M1).
|
|
83
|
+
|
|
84
|
+
``operations`` and ``deck_changes`` are the operations form of an edit: slide
|
|
85
|
+
operations against the persisted deck plus deck-level field changes, composed
|
|
86
|
+
into the next ``DeckSpec`` by the graph node. Both are optional and default to
|
|
87
|
+
``None`` so every output valid before they existed stays valid (the frozen
|
|
88
|
+
schema contract's historical digests rely on that). An explicit empty
|
|
89
|
+
``operations`` list is a valid edit here on purpose; the node reports it as a
|
|
90
|
+
retryable "nothing to do".
|
|
80
91
|
"""
|
|
81
92
|
|
|
82
93
|
intent: ArchitectIntent
|
|
@@ -85,6 +96,8 @@ class ArchitectOutput(BaseModel):
|
|
|
85
96
|
data_request: Optional[DataRequest] = None
|
|
86
97
|
target_positions: List[int] = []
|
|
87
98
|
proposed_design_contract: Optional[DesignContractRef] = None
|
|
99
|
+
operations: Optional[List[SlideOperation]] = None
|
|
100
|
+
deck_changes: Optional[DeckChanges] = None
|
|
88
101
|
|
|
89
102
|
@model_validator(mode="after")
|
|
90
103
|
def _intent_payload_consistency(self) -> "ArchitectOutput":
|
|
@@ -98,10 +111,16 @@ class ArchitectOutput(BaseModel):
|
|
|
98
111
|
"intent='ask_data' requires data_request; "
|
|
99
112
|
"the analyst node reads this to know what to fetch"
|
|
100
113
|
)
|
|
101
|
-
if
|
|
114
|
+
if (
|
|
115
|
+
self.intent == "edit"
|
|
116
|
+
and not self.target_positions
|
|
117
|
+
and self.operations is None
|
|
118
|
+
and self.deck_changes is None
|
|
119
|
+
):
|
|
102
120
|
raise ValueError(
|
|
103
|
-
"intent='edit' requires a non-empty target_positions list
|
|
104
|
-
"
|
|
121
|
+
"intent='edit' requires a non-empty target_positions list, "
|
|
122
|
+
"or operations, or deck_changes; "
|
|
123
|
+
"the router fans out one builder per changed position"
|
|
105
124
|
)
|
|
106
125
|
if (
|
|
107
126
|
self.intent == "confirm_design_contract"
|