From 117c06220e0678e5e9cb3ba56205159f63a91f34 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 3 Dec 2024 07:23:31 +1100 Subject: [PATCH] FEATURE: allow artifacts to be updated (#980) Add support for versioned artifacts with improved diff handling * Add versioned artifacts support allowing artifacts to be updated and tracked - New `ai_artifact_versions` table to store version history - Support for updating artifacts through a new `UpdateArtifact` tool - Add version-aware artifact rendering in posts - Include change descriptions for version tracking * Enhance artifact rendering and security - Add support for module-type scripts and external JS dependencies - Expand CSP to allow trusted CDN sources (unpkg, cdnjs, jsdelivr, googleapis) - Improve JavaScript handling in artifacts * Implement robust diff handling system (this is dormant but ready to use once LLMs catch up) - Add new DiffUtils module for applying changes to artifacts - Support for unified diff format with multiple hunks - Intelligent handling of whitespace and line endings - Comprehensive error handling for diff operations * Update routes and UI components - Add versioned artifact routes - Update markdown processing for versioned artifacts Also - Tweaks summary prompt - Improves upload support in custom tool to also provide urls --- .../ai_bot/artifacts_controller.rb | 25 +- app/models/ai_artifact.rb | 47 ++- app/models/ai_artifact_version.rb | 27 ++ app/models/shared_ai_conversation.rb | 4 +- .../discourse/components/ai-artifact.gjs | 7 +- .../javascripts/initializers/ai-artifacts.gjs | 9 +- .../lib/discourse-markdown/ai-tags.js | 6 +- config/locales/server.en.yml | 4 + config/routes.rb | 1 + .../20241130003808_add_artifact_versions.rb | 17 ++ lib/ai_bot/personas/persona.rb | 6 +- lib/ai_bot/personas/web_artifact_creator.rb | 4 +- lib/ai_bot/tool_runner.rb | 2 +- lib/ai_bot/tools/create_artifact.rb | 32 +- lib/ai_bot/tools/update_artifact.rb | 197 ++++++++++++ lib/summarization/strategies/topic_summary.rb | 18 +- lib/utils/diff_utils.rb | 184 ++++++++++++ lib/utils/dns_srv.rb | 2 +- .../ai_bot/tools/update_artifact_spec.rb | 148 +++++++++ spec/lib/utils/diff_utils_spec.rb | 284 ++++++++++++++++++ .../ai_bot/artifacts_controller_spec.rb | 15 +- 21 files changed, 1007 insertions(+), 32 deletions(-) create mode 100644 app/models/ai_artifact_version.rb create mode 100644 db/migrate/20241130003808_add_artifact_versions.rb create mode 100644 lib/ai_bot/tools/update_artifact.rb create mode 100644 lib/utils/diff_utils.rb create mode 100644 spec/lib/modules/ai_bot/tools/update_artifact_spec.rb create mode 100644 spec/lib/utils/diff_utils_spec.rb diff --git a/app/controllers/discourse_ai/ai_bot/artifacts_controller.rb b/app/controllers/discourse_ai/ai_bot/artifacts_controller.rb index 3ae65ef8..ff7f3260 100644 --- a/app/controllers/discourse_ai/ai_bot/artifacts_controller.rb +++ b/app/controllers/discourse_ai/ai_bot/artifacts_controller.rb @@ -19,22 +19,33 @@ module DiscourseAi raise Discourse::NotFound if !guardian.can_see?(post) end + name = artifact.name + + if params[:version].present? + artifact = artifact.versions.find_by(version_number: params[:version]) + raise Discourse::NotFound if !artifact + end + + js = artifact.js || "" + if !js.match?(%r{\A\s*}mi) + mod = "" + mod = " type=\"module\"" if js.match?(/\A\s*import.*/) + js = "\n#{js}\n" + end # Prepare the inner (untrusted) HTML document untrusted_html = <<~HTML - #{ERB::Util.html_escape(artifact.name)} + #{ERB::Util.html_escape(name)} #{artifact.html} - + #{js} HTML @@ -45,7 +56,7 @@ module DiscourseAi - #{ERB::Util.html_escape(artifact.name)} + #{ERB::Util.html_escape(name)}