From b051679b9e8900722727bf8e2846d391431084a4 Mon Sep 17 00:00:00 2001 From: Sarbada Date: Sun, 16 Nov 2025 05:43:25 +0545 Subject: [PATCH 1/5] feat(active_prompt): add and finalize mountable Rails engine (#243) - Add ActivePrompt engine (engine.rb, version.rb, module) - Isolate namespace via \`isolate_namespace\` - Wire asset pipeline (JS/CSS + manifest) and precompile hooks - Add engine routes with GET /health (no optional format) - Add minimal controller/helper stubs - Mount engine in dummy app and load engine before routes - Define \`ActiveAgent::TestCase\` to satisfy Zeitwerk - Add Minitest coverage: engine load/isolation, routes, assets - Stabilize route tests (assert named route and exact path) - Test hygiene: clean tmp/generators and remove lingering constants to avoid generator collisions --- app/assets/config/active_prompt_manifest.js | 2 ++ .../javascripts/active_prompt/application.js | 8 +++++ .../stylesheets/active_prompt/application.css | 6 ++++ .../active_prompt/application_controller.rb | 7 ++++ .../active_prompt/application_helper.rb | 6 ++++ config/routes.rb | 5 +++ .../json-and-auto-parses-JSON.md | 21 +++++++++++ .../plain-content-type.md | 21 +++++++++++ lib/active_agent/test_case.rb | 12 +++++++ lib/active_prompt.rb | 7 ++++ lib/active_prompt/engine.rb | 36 +++++++++++++++++++ lib/active_prompt/version.rb | 5 +++ test/active_prompt/asset_pipeline_test.rb | 22 ++++++++++++ test/active_prompt/engine_test.rb | 17 +++++++++ test/active_prompt/load_test.rb | 10 ++++++ test/active_prompt/routes_test.rb | 19 ++++++++++ test/dummy/config/application.rb | 4 +++ test/dummy/config/routes.rb | 1 + test/test_helper.rb | 35 ++++++++++++++++++ 19 files changed, 244 insertions(+) create mode 100644 app/assets/config/active_prompt_manifest.js create mode 100644 app/assets/javascripts/active_prompt/application.js create mode 100644 app/assets/stylesheets/active_prompt/application.css create mode 100644 app/controllers/active_prompt/application_controller.rb create mode 100644 app/helpers/active_prompt/application_helper.rb create mode 100644 config/routes.rb create mode 100644 docs/parts/examples/structured-output-json-parsing-test.rb-test-structured-output-sets-content-type-to-application/json-and-auto-parses-JSON.md create mode 100644 docs/parts/examples/structured-output-json-parsing-test.rb-test-without-structured-output-uses-text/plain-content-type.md create mode 100644 lib/active_agent/test_case.rb create mode 100644 lib/active_prompt.rb create mode 100644 lib/active_prompt/engine.rb create mode 100644 lib/active_prompt/version.rb create mode 100644 test/active_prompt/asset_pipeline_test.rb create mode 100644 test/active_prompt/engine_test.rb create mode 100644 test/active_prompt/load_test.rb create mode 100644 test/active_prompt/routes_test.rb diff --git a/app/assets/config/active_prompt_manifest.js b/app/assets/config/active_prompt_manifest.js new file mode 100644 index 00000000..25434838 --- /dev/null +++ b/app/assets/config/active_prompt_manifest.js @@ -0,0 +1,2 @@ +//= link_directory ../javascripts/active_prompt .js +//= link_directory ../stylesheets/active_prompt .css diff --git a/app/assets/javascripts/active_prompt/application.js b/app/assets/javascripts/active_prompt/application.js new file mode 100644 index 00000000..eaa45c39 --- /dev/null +++ b/app/assets/javascripts/active_prompt/application.js @@ -0,0 +1,8 @@ +// This file is compiled into the host app's asset pipeline as active_prompt/application.js +// Add engine-specific JS here. +//= require_self + +(function () { + // Namespace guard + window.ActivePrompt = window.ActivePrompt || {}; +})(); diff --git a/app/assets/stylesheets/active_prompt/application.css b/app/assets/stylesheets/active_prompt/application.css new file mode 100644 index 00000000..8f41e56f --- /dev/null +++ b/app/assets/stylesheets/active_prompt/application.css @@ -0,0 +1,6 @@ +/* + *= require_self + */ + +/* Add engine-specific styles here */ +.active-prompt--hidden { display: none; } diff --git a/app/controllers/active_prompt/application_controller.rb b/app/controllers/active_prompt/application_controller.rb new file mode 100644 index 00000000..ab1aeff6 --- /dev/null +++ b/app/controllers/active_prompt/application_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module ActivePrompt + class ApplicationController < ActionController::Base + protect_from_forgery with: :exception + end +end diff --git a/app/helpers/active_prompt/application_helper.rb b/app/helpers/active_prompt/application_helper.rb new file mode 100644 index 00000000..8ea40ac1 --- /dev/null +++ b/app/helpers/active_prompt/application_helper.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module ActivePrompt + module ApplicationHelper + end +end diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 00000000..27ab3143 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +ActivePrompt::Engine.routes.draw do + get "health", to: proc { [200, { "Content-Type" => "text/plain" }, ["ok"]] }, as: :health +end diff --git a/docs/parts/examples/structured-output-json-parsing-test.rb-test-structured-output-sets-content-type-to-application/json-and-auto-parses-JSON.md b/docs/parts/examples/structured-output-json-parsing-test.rb-test-structured-output-sets-content-type-to-application/json-and-auto-parses-JSON.md new file mode 100644 index 00000000..fc01d544 --- /dev/null +++ b/docs/parts/examples/structured-output-json-parsing-test.rb-test-structured-output-sets-content-type-to-application/json-and-auto-parses-JSON.md @@ -0,0 +1,21 @@ + +[activeagent/test/integration/structured_output_json_parsing_test.rb:69](vscode://file//Users/sarbadajaiswal/development/Justin/activeagents/activeagent/test/integration/structured_output_json_parsing_test.rb:69) + + +```ruby +# Response object +# "John Doe", "age" => 30, "email" => "john@example.com"}, + @role=:assistant> + @prompt=# + @content_type="application/json" + @raw_response={...}> + +# Message content +response.message.content # => {"name" => "John Doe", "age" => 30, "email" => "john@example.com"} +``` \ No newline at end of file diff --git a/docs/parts/examples/structured-output-json-parsing-test.rb-test-without-structured-output-uses-text/plain-content-type.md b/docs/parts/examples/structured-output-json-parsing-test.rb-test-without-structured-output-uses-text/plain-content-type.md new file mode 100644 index 00000000..b57c5c3b --- /dev/null +++ b/docs/parts/examples/structured-output-json-parsing-test.rb-test-without-structured-output-uses-text/plain-content-type.md @@ -0,0 +1,21 @@ + +[activeagent/test/integration/structured_output_json_parsing_test.rb:151](vscode://file//Users/sarbadajaiswal/development/Justin/activeagents/activeagent/test/integration/structured_output_json_parsing_test.rb:151) + + +```ruby +# Response object +# + @prompt=# + @content_type="text/plain" + @raw_response={...}> + +# Message content +response.message.content # => "The capital of France is Paris." +``` \ No newline at end of file diff --git a/lib/active_agent/test_case.rb b/lib/active_agent/test_case.rb new file mode 100644 index 00000000..18868b5b --- /dev/null +++ b/lib/active_agent/test_case.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require "active_support/test_case" + +module ActiveAgent + class TestCase < ActiveSupport::TestCase + # minimal base to satisfy Zeitwerk + end +end + +# Back-compat for any existing tests +ActiveAgentTestCase = ActiveAgent::TestCase unless defined?(ActiveAgentTestCase) diff --git a/lib/active_prompt.rb b/lib/active_prompt.rb new file mode 100644 index 00000000..77166e20 --- /dev/null +++ b/lib/active_prompt.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "active_prompt/version" +require "active_prompt/engine" if defined?(Rails) + +module ActivePrompt +end diff --git a/lib/active_prompt/engine.rb b/lib/active_prompt/engine.rb new file mode 100644 index 00000000..51369f14 --- /dev/null +++ b/lib/active_prompt/engine.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require "rails/engine" + +module ActivePrompt + class Engine < ::Rails::Engine + isolate_namespace ActivePrompt + + # Ensures the engine's app/ is eager loaded in production and autoloaded in dev/test + config.autoload_paths << root.join("lib").to_s + + # Keep generated files tidy (no assets/helpers/tests by default from generators) + config.generators do |g| + g.assets false + g.helper false + g.test_framework :rspec, fixture: false if defined?(RSpec) + end + + # Sprockets / asset pipeline configuration + initializer "active_prompt.assets.precompile" do |app| + # When the engine is used within a host Rails app, ensure our assets are precompiled + if app.config.respond_to?(:assets) + app.config.assets.paths << root.join("app", "assets") + app.config.assets.precompile += %w[ + active_prompt/application.js + active_prompt/application.css + ] + end + end + + # Make sure the engine’s translations are available + initializer "active_prompt.i18n" do + config.i18n.load_path += Dir[root.join("config", "locales", "**", "*.yml")] + end + end +end diff --git a/lib/active_prompt/version.rb b/lib/active_prompt/version.rb new file mode 100644 index 00000000..2594fc06 --- /dev/null +++ b/lib/active_prompt/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module ActivePrompt + VERSION = "0.1.0" +end diff --git a/test/active_prompt/asset_pipeline_test.rb b/test/active_prompt/asset_pipeline_test.rb new file mode 100644 index 00000000..646fde0a --- /dev/null +++ b/test/active_prompt/asset_pipeline_test.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +require "test_helper" + +class ActivePromptAssetPipelineTest < ActiveSupport::TestCase + def assets_enabled? + Rails.application.config.respond_to?(:assets) && Rails.application.config.assets + end + + test "adds engine assets path to host app (if assets enabled)" do + skip "Assets not enabled in host app" unless assets_enabled? + paths = Rails.application.config.assets.paths.map(&:to_s) + expected = ActivePrompt::Engine.root.join("app", "assets").to_s + assert_includes paths, expected + end + + test "adds engine assets to precompile list (if assets enabled)" do + skip "Assets not enabled in host app" unless assets_enabled? + precompile = Array(Rails.application.config.assets.precompile).map(&:to_s) + assert_includes precompile, "active_prompt/application.js" + assert_includes precompile, "active_prompt/application.css" + end +end diff --git a/test/active_prompt/engine_test.rb b/test/active_prompt/engine_test.rb new file mode 100644 index 00000000..bfcbc0fa --- /dev/null +++ b/test/active_prompt/engine_test.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +require "test_helper" + +class ActivePromptEngineTest < ActiveSupport::TestCase + test "engine constant is defined" do + assert defined?(ActivePrompt::Engine), "ActivePrompt::Engine should be defined" + end + + test "engine isolates namespace" do + assert ActivePrompt::Engine.isolated?, "Engine should isolate the ActivePrompt namespace" + end + + test "version is present and semantic" do + assert defined?(ActivePrompt::VERSION), "ActivePrompt::VERSION should be defined" + assert_match(/\A\d+\.\d+\.\d+\z/, ActivePrompt::VERSION) + end +end diff --git a/test/active_prompt/load_test.rb b/test/active_prompt/load_test.rb new file mode 100644 index 00000000..0f7a1f17 --- /dev/null +++ b/test/active_prompt/load_test.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +require "test_helper" + +class ActivePromptLoadTest < ActiveSupport::TestCase + test "requiring top-level file doesn't error" do + assert_nothing_raised do + require "active_prompt" + end + end +end diff --git a/test/active_prompt/routes_test.rb b/test/active_prompt/routes_test.rb new file mode 100644 index 00000000..8365693c --- /dev/null +++ b/test/active_prompt/routes_test.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +require "test_helper" + +class ActivePromptRoutesTest < ActionDispatch::IntegrationTest + test "engine mounted health endpoint responds ok" do + get "/active_prompt/health" + assert_response :success + assert_equal "ok", @response.body + end + + test "engine defines a named :health route with path /health" do + named = ActivePrompt::Engine.routes.named_routes + assert named.key?(:health), "Expected engine to define a :health named route" + + route = named[:health] + actual = route.path.spec.to_s.sub(/\(\.:format\)\z/, "") # <-- strip optional format + assert_equal "/health", actual + end +end diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index b1fafbad..0b853544 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -3,6 +3,8 @@ require "rails" # Pick the frameworks you want: require "active_model/railtie" +$LOAD_PATH.unshift File.expand_path("../../../lib", __dir__) +require "active_prompt" require "active_job/railtie" require "active_record/railtie" require "active_storage/engine" @@ -34,5 +36,7 @@ class Application < Rails::Application # # config.time_zone = "Central Time (US & Canada)" # config.eager_load_paths << Rails.root.join("extras") + config.eager_load = false + config.secret_key_base = "test-secret-key-base-activeprompt" end end diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index 2cba1443..e3485836 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -11,4 +11,5 @@ # Defines the root path route ("/") # root "posts#index" + mount ActivePrompt::Engine => "/active_prompt", as: :active_prompt end diff --git a/test/test_helper.rb b/test/test_helper.rb index 55047d33..5f35293e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -17,6 +17,41 @@ require "webmock/minitest" require "minitest/mock" +# ------------------------------------------------------------------- +# 🔧 Test environment hygiene (prevents generator test collisions) +# - Clean any leftover generated files under tmp/generators so they +# don't get picked up by test discovery in subsequent runs. +# - Remove lingering constants that would cause class-collision checks +# to abort generator runs (e.g., UserAgentTest). +# ------------------------------------------------------------------- +begin + generated_dir = Rails.root.join("tmp", "generators") + FileUtils.rm_rf(generated_dir) +rescue => e + warn "Warning: failed to clean #{generated_dir}: #{e.message}" +end + + +# Helper to remove a constant by fully qualified name (supports namespaces) +def remove_constant(name) + names = name.to_s.split("::") + parent = Object + names[0..-2].each do |n| + return unless parent.const_defined?(n, false) + parent = parent.const_get(n) + end + last = names.last + parent.send(:remove_const, last) if parent.const_defined?(last, false) +end + +# Remove any lingering constants that the generator collision check might trip over +%w[ + UserAgentTest + Admin::UserAgentTest +].each { |const| remove_constant(const) } + +# ------------------------------------------------------------------- + # Extract full path and relative path from caller_info def extract_path_info(caller_info) if caller_info =~ /(.+):(\d+):in/ From f682c7c51d2d3ebb58c88567b09144a615c308f7 Mon Sep 17 00:00:00 2001 From: Sarbada Date: Thu, 27 Nov 2025 21:51:23 +0545 Subject: [PATCH 2/5] =?UTF-8?q?feat(active=5Fprompt):=20add=20Solid=20Agen?= =?UTF-8?q?t=E2=80=93style=20persistence=20+=20install=20generator;=20make?= =?UTF-8?q?=20tests=20auto-migrate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ActiveRecord models: - app/models/active_prompt/prompt.rb - app/models/active_prompt/message.rb - app/models/active_prompt/action.rb - app/models/active_prompt/context.rb - Add agent DSL: - lib/active_agent/has_context.rb - enables: `has_context prompts: :prompts, messages: :messages, tools: :actions` - instance helpers: `add_prompt`, `remove_prompt` - Add engine migration (SQLite-friendly: uses `t.json`): - db/migrate/20251123000000_create_active_prompt_core.rb - Add install generator for host apps: - lib/generators/active_prompt/install/install_generator.rb - (optional) lib/active_prompt/railtie.rb + `require "active_prompt/railtie"` - Wire dummy app for verification: - test/dummy/app/models/application_agent.rb - test/dummy/db/migrate/20251123001000_create_application_agents.rb (uses `t.json`) - Tests: - test/active_prompt/models_test.rb (persistence + DSL smoke tests) - test/active_prompt/* (engine load, routes, assets) kept - test(active_prompt): add validations + message ordering coverage - Test boot: proactively migrate both dummy and engine paths: - test/test_helper.rb: construct MigrationContext with paths (no `connection.migration_context`) - still calls `ActiveRecord::Migration.maintain_test_schema!` Notes: - Accepts `rails g active_prompt:install` in host apps (or `railties:install:migrations FROM=active_prompt`). --- app/models/active_prompt/action.rb | 10 ++++ app/models/active_prompt/context.rb | 13 +++++ app/models/active_prompt/message.rb | 11 +++++ app/models/active_prompt/prompt.rb | 25 ++++++++++ ...0251127000000_create_active_prompt_core.rb | 44 +++++++++++++++++ .../json-and-auto-parses-JSON.md | 6 +-- .../plain-content-type.md | 6 +-- lib/active_agent/has_context.rb | 34 ++++++++++++++ .../install/install_generator.rb | 19 ++++++++ test/active_prompt/models_test.rb | 27 +++++++++++ test/active_prompt/ordering_test.rb | 12 +++++ test/active_prompt/validations_test.rb | 17 +++++++ test/dummy/app/models/application_agent.rb | 7 +++ ...0251127001000_create_application_agents.rb | 10 ++++ test/dummy/db/schema.rb | 39 ++++++++------- test/test_helper.rb | 47 ++++++++++++++++++- 16 files changed, 304 insertions(+), 23 deletions(-) create mode 100644 app/models/active_prompt/action.rb create mode 100644 app/models/active_prompt/context.rb create mode 100644 app/models/active_prompt/message.rb create mode 100644 app/models/active_prompt/prompt.rb create mode 100644 db/migrate/20251127000000_create_active_prompt_core.rb create mode 100644 lib/active_agent/has_context.rb create mode 100644 lib/generators/active_prompt/install/install_generator.rb create mode 100644 test/active_prompt/models_test.rb create mode 100644 test/active_prompt/ordering_test.rb create mode 100644 test/active_prompt/validations_test.rb create mode 100644 test/dummy/app/models/application_agent.rb create mode 100644 test/dummy/db/migrate/20251127001000_create_application_agents.rb diff --git a/app/models/active_prompt/action.rb b/app/models/active_prompt/action.rb new file mode 100644 index 00000000..c53c5b88 --- /dev/null +++ b/app/models/active_prompt/action.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module ActivePrompt + class Action < ApplicationRecord + self.table_name = "active_prompt_actions" + + belongs_to :prompt, class_name: "ActivePrompt::Prompt", inverse_of: :actions + + validates :name, presence: true + end +end diff --git a/app/models/active_prompt/context.rb b/app/models/active_prompt/context.rb new file mode 100644 index 00000000..1584766f --- /dev/null +++ b/app/models/active_prompt/context.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module ActivePrompt + # Polymorphic join: attach prompts to any agent record + class Context < ApplicationRecord + self.table_name = "active_prompt_contexts" + + belongs_to :agent, polymorphic: true, inverse_of: :prompt_contexts + belongs_to :prompt, class_name: "ActivePrompt::Prompt", inverse_of: :contexts + + validates :agent, :prompt, presence: true + validates :label, length: { maximum: 255 }, allow_nil: true + end +end diff --git a/app/models/active_prompt/message.rb b/app/models/active_prompt/message.rb new file mode 100644 index 00000000..e253ef80 --- /dev/null +++ b/app/models/active_prompt/message.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true +module ActivePrompt + class Message < ApplicationRecord + self.table_name = "active_prompt_messages" + + belongs_to :prompt, class_name: "ActivePrompt::Prompt", inverse_of: :messages + + enum :role, { system: "system", user: "user", assistant: "assistant", tool: "tool" }, prefix: true + validates :role, :content, presence: true + end +end diff --git a/app/models/active_prompt/prompt.rb b/app/models/active_prompt/prompt.rb new file mode 100644 index 00000000..592f0da1 --- /dev/null +++ b/app/models/active_prompt/prompt.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +module ActivePrompt + class Prompt < ApplicationRecord + self.table_name = "active_prompt_prompts" + + has_many :messages, class_name: "ActivePrompt::Message", dependent: :destroy, inverse_of: :prompt + has_many :actions, class_name: "ActivePrompt::Action", dependent: :destroy, inverse_of: :prompt + + has_many :contexts, class_name: "ActivePrompt::Context", dependent: :destroy, inverse_of: :prompt + has_many :agents, through: :contexts, source: :agent + + validates :name, presence: true + + def to_runtime + { + name: name, + description: description, + template: template, + messages: messages.order(:position).map(&:attributes), + actions: actions.map(&:attributes), + metadata: metadata || {} + } + end + end +end diff --git a/db/migrate/20251127000000_create_active_prompt_core.rb b/db/migrate/20251127000000_create_active_prompt_core.rb new file mode 100644 index 00000000..6ced3a6e --- /dev/null +++ b/db/migrate/20251127000000_create_active_prompt_core.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +class CreateActivePromptCore < ActiveRecord::Migration[7.0] + def change + create_table :active_prompt_prompts do |t| + t.string :name, null: false + t.text :description + t.json :metadata, null: false, default: {} + t.text :template + t.timestamps + end + add_index :active_prompt_prompts, :name + + create_table :active_prompt_messages do |t| + t.references :prompt, null: false, foreign_key: { to_table: :active_prompt_prompts } + t.string :role, null: false + t.text :content, null: false + t.integer :position + t.json :metadata, null: false, default: {} + t.timestamps + end + add_index :active_prompt_messages, [:prompt_id, :position] + + create_table :active_prompt_actions do |t| + t.references :prompt, null: false, foreign_key: { to_table: :active_prompt_prompts } + t.string :name, null: false + t.string :tool_name + t.json :parameters, null: false, default: {} + t.json :result, null: false, default: {} + t.string :status + t.timestamps + end + add_index :active_prompt_actions, [:prompt_id, :name] + + create_table :active_prompt_contexts do |t| + t.string :agent_type, null: false + t.bigint :agent_id, null: false + t.references :prompt, null: false, foreign_key: { to_table: :active_prompt_prompts } + t.string :label + t.json :metadata, null: false, default: {} + t.timestamps + end + add_index :active_prompt_contexts, [:agent_type, :agent_id, :prompt_id], unique: true, name: "idx_ap_contexts_agent_prompt" + end +end diff --git a/docs/parts/examples/structured-output-json-parsing-test.rb-test-structured-output-sets-content-type-to-application/json-and-auto-parses-JSON.md b/docs/parts/examples/structured-output-json-parsing-test.rb-test-structured-output-sets-content-type-to-application/json-and-auto-parses-JSON.md index fc01d544..40cd46e8 100644 --- a/docs/parts/examples/structured-output-json-parsing-test.rb-test-structured-output-sets-content-type-to-application/json-and-auto-parses-JSON.md +++ b/docs/parts/examples/structured-output-json-parsing-test.rb-test-structured-output-sets-content-type-to-application/json-and-auto-parses-JSON.md @@ -4,15 +4,15 @@ ```ruby # Response object -# "John Doe", "age" => 30, "email" => "john@example.com"}, @role=:assistant> - @prompt=# + @prompt=# @content_type="application/json" @raw_response={...}> diff --git a/docs/parts/examples/structured-output-json-parsing-test.rb-test-without-structured-output-uses-text/plain-content-type.md b/docs/parts/examples/structured-output-json-parsing-test.rb-test-without-structured-output-uses-text/plain-content-type.md index b57c5c3b..71797adc 100644 --- a/docs/parts/examples/structured-output-json-parsing-test.rb-test-without-structured-output-uses-text/plain-content-type.md +++ b/docs/parts/examples/structured-output-json-parsing-test.rb-test-without-structured-output-uses-text/plain-content-type.md @@ -4,15 +4,15 @@ ```ruby # Response object -# - @prompt=# + @prompt=# @content_type="text/plain" @raw_response={...}> diff --git a/lib/active_agent/has_context.rb b/lib/active_agent/has_context.rb new file mode 100644 index 00000000..3bbc04f0 --- /dev/null +++ b/lib/active_agent/has_context.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true +module ActiveAgent + module HasContext + extend ActiveSupport::Concern + + class_methods do + # Example: + # has_context prompts: :prompts, messages: :messages, tools: :actions + # + # Associations added: + # has_many :prompt_contexts (ActivePrompt::Context, as: :agent) + # has_many :prompts, :messages, :actions (through prompt_contexts/prompts) + def has_context(prompts: :prompts, messages: :messages, tools: :actions) + has_many :prompt_contexts, + class_name: "ActivePrompt::Context", + as: :agent, + dependent: :destroy, + inverse_of: :agent + + has_many prompts, through: :prompt_contexts, source: :prompt + has_many messages, through: prompts, source: :messages + has_many tools, through: prompts, source: :actions + + define_method :add_prompt do |prompt, label: nil, metadata: {}| + ActivePrompt::Context.create!(agent: self, prompt:, label:, metadata:) + end + + define_method :remove_prompt do |prompt| + prompt_contexts.where(prompt:).destroy_all + end + end + end + end +end diff --git a/lib/generators/active_prompt/install/install_generator.rb b/lib/generators/active_prompt/install/install_generator.rb new file mode 100644 index 00000000..dc6e7d79 --- /dev/null +++ b/lib/generators/active_prompt/install/install_generator.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +require "rails/generators" +module ActivePrompt + module Generators + class InstallGenerator < Rails::Generators::Base + source_root File.expand_path("../../../../..", __dir__) # engine root + + desc "Copy ActivePrompt migrations into the host app" + + def copy_migrations + rake("railties:install:migrations FROM=active_prompt") + end + + def show_readme + say_status :info, "Run `bin/rails db:migrate` to apply ActivePrompt tables.", :blue + end + end + end +end diff --git a/test/active_prompt/models_test.rb b/test/active_prompt/models_test.rb new file mode 100644 index 00000000..510c285f --- /dev/null +++ b/test/active_prompt/models_test.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +require "test_helper" + +class ActivePromptModelsTest < ActiveSupport::TestCase + test "prompt with messages and actions persists" do + p = ActivePrompt::Prompt.create!(name: "translate", description: "Translate text") + p.messages.create!(role: :system, content: "You translate.", position: 0) + p.messages.create!(role: :user, content: "Hello", position: 1) + p.actions.create!(name: "glossary_lookup", tool_name: "glossary", parameters: { term: "Hello" }) + + assert_equal 2, p.messages.count + assert_equal 1, p.actions.count + end + + test "context attaches prompts to an agent" do + # Use test-only AR model to avoid name collision with non-AR ApplicationAgent + agent_class = ::PromptTestAgent + + agent = agent_class.create!(name: "Translator", config: {}) + prompt = ActivePrompt::Prompt.create!(name: "translate") + + agent.add_prompt(prompt, label: "default") + + assert_equal [prompt.id], agent.prompts.pluck(:id) + assert_equal 1, agent.prompt_contexts.count + end +end diff --git a/test/active_prompt/ordering_test.rb b/test/active_prompt/ordering_test.rb new file mode 100644 index 00000000..7b07c5d8 --- /dev/null +++ b/test/active_prompt/ordering_test.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +require "test_helper" + +class ActivePromptOrderingTest < ActiveSupport::TestCase + test "messages return in position order via to_runtime" do + p = ActivePrompt::Prompt.create!(name: "ordered") + p.messages.create!(role: :user, content: "B", position: 2) + p.messages.create!(role: :system, content: "A", position: 1) + order = p.to_runtime[:messages].map { |m| m["content"] } + assert_equal %w[A B], order + end +end diff --git a/test/active_prompt/validations_test.rb b/test/active_prompt/validations_test.rb new file mode 100644 index 00000000..8220b1b8 --- /dev/null +++ b/test/active_prompt/validations_test.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +require "test_helper" + +class ActivePromptValidationsTest < ActiveSupport::TestCase + test "prompt requires name" do + prompt = ActivePrompt::Prompt.new + refute prompt.valid? + assert_includes prompt.errors[:name], "can't be blank" + end + + test "message requires role and content" do + msg = ActivePrompt::Message.new + refute msg.valid? + assert_includes msg.errors[:role], "can't be blank" + assert_includes msg.errors[:content], "can't be blank" + end +end diff --git a/test/dummy/app/models/application_agent.rb b/test/dummy/app/models/application_agent.rb new file mode 100644 index 00000000..099b54cf --- /dev/null +++ b/test/dummy/app/models/application_agent.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +class ApplicationAgent < ApplicationRecord + include ActiveAgent::HasContext + has_context prompts: :prompts, messages: :messages, tools: :actions + + validates :name, presence: true +end diff --git a/test/dummy/db/migrate/20251127001000_create_application_agents.rb b/test/dummy/db/migrate/20251127001000_create_application_agents.rb new file mode 100644 index 00000000..0be46c83 --- /dev/null +++ b/test/dummy/db/migrate/20251127001000_create_application_agents.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +class CreateApplicationAgents < ActiveRecord::Migration[7.0] + def change + create_table :application_agents do |t| + t.string :name, null: false + t.json :config, null: false, default: {} + t.timestamps + end + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index d7cab59b..c60310c3 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -10,39 +10,46 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 3) do +ActiveRecord::Schema[8.0].define(version: 2025_11_27_001000) do + create_table "application_agents", force: :cascade do |t| + t.string "name", null: false + t.json "config", default: {}, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "posts", force: :cascade do |t| - t.string "title", null: false t.text "content" - t.integer "user_id" - t.boolean "published", default: false - t.datetime "published_at" t.datetime "created_at", null: false + t.boolean "published" + t.datetime "published_at" + t.string "title", null: false t.datetime "updated_at", null: false - t.index [ "published" ], name: "index_posts_on_published" - t.index [ "user_id" ], name: "index_posts_on_user_id" + t.integer "user_id" + t.index ["published"], name: "index_posts_on_published" + t.index ["user_id"], name: "index_posts_on_user_id" end create_table "profiles", force: :cascade do |t| - t.integer "user_id" t.text "bio" + t.datetime "created_at", null: false t.string "location" - t.string "website" t.json "social_links" - t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index [ "user_id" ], name: "index_profiles_on_user_id", unique: true + t.integer "user_id" + t.string "website" + t.index ["user_id"], name: "index_profiles_on_user_id", unique: true end create_table "users", force: :cascade do |t| - t.string "name", null: false - t.string "email", null: false + t.boolean "active" t.integer "age" - t.string "role", default: "user" - t.boolean "active", default: true t.datetime "created_at", null: false + t.string "email", null: false + t.string "name", null: false + t.string "role", default: "user" t.datetime "updated_at", null: false - t.index [ "email" ], name: "index_users_on_email", unique: true + t.index ["email"], name: "index_users_on_email", unique: true end add_foreign_key "posts", "users" diff --git a/test/test_helper.rb b/test/test_helper.rb index 5f35293e..4e1cbc83 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -11,7 +11,38 @@ require "jbuilder" require_relative "../test/dummy/config/environment" -ActiveRecord::Migrator.migrations_paths = [ File.expand_path("../test/dummy/db/migrate", __dir__) ] + +# Make sure BOTH dummy and engine migrations are available to the test DB +ActiveRecord::Migrator.migrations_paths = [ + File.expand_path("../test/dummy/db/migrate", __dir__), + File.expand_path("../db/migrate", __dir__) +] + +# Proactively migrate both dummy and engine paths (works across AR versions) +begin + require "active_record" + ActiveRecord::Schema.verbose = false + ActiveRecord::Base.establish_connection unless ActiveRecord::Base.connected? + + paths = ActiveRecord::Migrator.migrations_paths + + migration_context = + begin + # AR >= ~6 supports single-arg constructor + ActiveRecord::MigrationContext.new(paths) + rescue ArgumentError + # Older AR expects (paths, schema_migration) + ActiveRecord::MigrationContext.new(paths, ActiveRecord::SchemaMigration) + end + + migration_context.migrate +rescue ActiveRecord::NoDatabaseError + # If DB isn't created yet, ignore; the dummy app tasks will handle creation. +end + +# Rails still checks consistency after we migrate +ActiveRecord::Migration.maintain_test_schema! + require "rails/test_help" require "vcr" require "webmock/minitest" @@ -50,6 +81,20 @@ def remove_constant(name) Admin::UserAgentTest ].each { |const| remove_constant(const) } +# ------------------------------------------------------------------- +# A tiny AR model just for tests, to avoid clashing with any non-AR ApplicationAgent +# Uses the dummy's application_agents table. +class PromptTestAgent < ActiveRecord::Base + self.table_name = "application_agents" + + begin + require "active_agent/has_context" + include ActiveAgent::HasContext + has_context prompts: :prompts, messages: :messages, tools: :actions + rescue LoadError, NameError + # If HasContext isn't present in this branch, tests that rely on it should be skipped or guarded. + end +end # ------------------------------------------------------------------- # Extract full path and relative path from caller_info From 7c0a466499e2bc6281f89e4966f48f00877816ea Mon Sep 17 00:00:00 2001 From: Sarbada Date: Thu, 22 Jan 2026 12:23:59 +0545 Subject: [PATCH 3/5] Fix provider autoload aliases and test credentials --- .gitignore | 1 + lib/active_agent/providers/common/model.rb | 11 ++++++++--- lib/active_agent/providers/openrouter_provider.rb | 7 +++++++ test/test_helper.rb | 9 +++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 0b289be6..2b4724e7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ docs/parts/examples/*.md Gemfile.lock gemfiles/*.lock test/dummy/config/master.key +endor/bundle \ No newline at end of file diff --git a/lib/active_agent/providers/common/model.rb b/lib/active_agent/providers/common/model.rb index 0737d881..d9e96f70 100644 --- a/lib/active_agent/providers/common/model.rb +++ b/lib/active_agent/providers/common/model.rb @@ -352,10 +352,15 @@ def <=>(other) # model1 = Message.new(content: "Hello") # model2 = Message.new(content: "Hello") # model1 == model2 #=> true - def ==(other) - serialize == other&.serialize - end + def ==(other) + serialize == other&.serialize end end + + # Zeitwerk expects this file to define ActiveAgent::Providers::Common::Model + # based on its path. Provide an alias so autoloading succeeds while keeping + # the BaseModel name used throughout the codebase. + Model = BaseModel end end +end diff --git a/lib/active_agent/providers/openrouter_provider.rb b/lib/active_agent/providers/openrouter_provider.rb index 8662d753..74e91114 100644 --- a/lib/active_agent/providers/openrouter_provider.rb +++ b/lib/active_agent/providers/openrouter_provider.rb @@ -1,2 +1,9 @@ # OpenRouter, just copying OpenAI require_relative "open_router_provider" + +# Zeitwerk expects OpenrouterProvider from this file name. +module ActiveAgent + module Providers + OpenrouterProvider = OpenRouterProvider + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 4e1cbc83..5e546caf 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,6 +1,15 @@ # Configure Rails Environment ENV["RAILS_ENV"] = "test" +# Provide placeholder API keys so provider clients initialize without +# real credentials during cassette-driven tests. +ENV["OPENAI_API_KEY"] ||= "test-openai-key" +ENV["OPENAI_ACCESS_TOKEN"] ||= ENV["OPENAI_API_KEY"] +ENV["OPEN_AI_ACCESS_TOKEN"] ||= ENV["OPENAI_API_KEY"] +ENV["OPEN_ROUTER_ACCESS_TOKEN"] ||= "test-openrouter-key" +ENV["ANTHROPIC_API_KEY"] ||= "test-anthropic-key" +ENV["ANTHROPIC_ACCESS_TOKEN"] ||= ENV["ANTHROPIC_API_KEY"] + begin require "debug" require "pry" From e7260b5153b43f62f1e5fb8c07acaa21af6fa941 Mon Sep 17 00:00:00 2001 From: Sarbada Date: Thu, 22 Jan 2026 12:43:14 +0545 Subject: [PATCH 4/5] Add engine ApplicationRecord, health controller, runtime preload scope, and tests --- .../active_prompt/health_controller.rb | 9 ++++++++ .../active_prompt/application_record.rb | 7 ++++++ app/models/active_prompt/prompt.rb | 6 +++-- config/routes.rb | 2 +- .../install/install_generator.rb | 2 +- test/active_prompt/models_test.rb | 23 +++++++++++++++++++ .../active_prompt/install_generator_test.rb | 14 +++++++++++ test/test_helper.rb | 2 +- 8 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 app/controllers/active_prompt/health_controller.rb create mode 100644 app/models/active_prompt/application_record.rb create mode 100644 test/generators/active_prompt/install_generator_test.rb diff --git a/app/controllers/active_prompt/health_controller.rb b/app/controllers/active_prompt/health_controller.rb new file mode 100644 index 00000000..a9ba9545 --- /dev/null +++ b/app/controllers/active_prompt/health_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module ActivePrompt + class HealthController < ApplicationController + def show + render plain: "ok" + end + end +end diff --git a/app/models/active_prompt/application_record.rb b/app/models/active_prompt/application_record.rb new file mode 100644 index 00000000..926afac3 --- /dev/null +++ b/app/models/active_prompt/application_record.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module ActivePrompt + class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true + end +end diff --git a/app/models/active_prompt/prompt.rb b/app/models/active_prompt/prompt.rb index 592f0da1..515c6a40 100644 --- a/app/models/active_prompt/prompt.rb +++ b/app/models/active_prompt/prompt.rb @@ -11,13 +11,15 @@ class Prompt < ApplicationRecord validates :name, presence: true + scope :with_runtime_associations, -> { includes(:messages, :actions) } + def to_runtime { name: name, description: description, template: template, - messages: messages.order(:position).map(&:attributes), - actions: actions.map(&:attributes), + messages: messages.order(:position).as_json, + actions: actions.as_json, metadata: metadata || {} } end diff --git a/config/routes.rb b/config/routes.rb index 27ab3143..4022fe01 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true ActivePrompt::Engine.routes.draw do - get "health", to: proc { [200, { "Content-Type" => "text/plain" }, ["ok"]] }, as: :health + get "health", to: "health#show", as: :health end diff --git a/lib/generators/active_prompt/install/install_generator.rb b/lib/generators/active_prompt/install/install_generator.rb index dc6e7d79..1159d8e6 100644 --- a/lib/generators/active_prompt/install/install_generator.rb +++ b/lib/generators/active_prompt/install/install_generator.rb @@ -3,7 +3,7 @@ module ActivePrompt module Generators class InstallGenerator < Rails::Generators::Base - source_root File.expand_path("../../../../..", __dir__) # engine root + source_root File.expand_path("../../../..", __dir__) # engine root desc "Copy ActivePrompt migrations into the host app" diff --git a/test/active_prompt/models_test.rb b/test/active_prompt/models_test.rb index 510c285f..d2c13d8e 100644 --- a/test/active_prompt/models_test.rb +++ b/test/active_prompt/models_test.rb @@ -24,4 +24,27 @@ class ActivePromptModelsTest < ActiveSupport::TestCase assert_equal [prompt.id], agent.prompts.pluck(:id) assert_equal 1, agent.prompt_contexts.count end + + test "engine models inherit from ActivePrompt::ApplicationRecord" do + assert ActivePrompt::ApplicationRecord.abstract_class?, "ApplicationRecord should be abstract" + assert_equal ActivePrompt::ApplicationRecord, ActivePrompt::Prompt.superclass + assert_equal ActivePrompt::ApplicationRecord, ActivePrompt::Message.superclass + assert_equal ActivePrompt::ApplicationRecord, ActivePrompt::Action.superclass + assert_equal ActivePrompt::ApplicationRecord, ActivePrompt::Context.superclass + end + + test "prompt to_runtime returns eager-loadable hashes" do + prompt = ActivePrompt::Prompt.create!(name: "runtime") + prompt.messages.create!(role: :system, content: "You are helpful", position: 0) + prompt.actions.create!(name: "search", tool_name: "search", parameters: { q: "hello" }) + + runtime = ActivePrompt::Prompt.with_runtime_associations.find(prompt.id).to_runtime + + assert_equal "runtime", runtime[:name] + assert_equal 1, runtime[:messages].size + assert_equal "You are helpful", runtime[:messages].first["content"] + assert_equal 1, runtime[:actions].size + assert_equal "search", runtime[:actions].first["name"] + assert_equal({}, runtime[:metadata]) + end end diff --git a/test/generators/active_prompt/install_generator_test.rb b/test/generators/active_prompt/install_generator_test.rb new file mode 100644 index 00000000..2d67a775 --- /dev/null +++ b/test/generators/active_prompt/install_generator_test.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require "test_helper" +require "generators/active_prompt/install/install_generator" + +class ActivePrompt::Generators::InstallGeneratorTest < Rails::Generators::TestCase + tests ActivePrompt::Generators::InstallGenerator + destination Rails.root.join("tmp/generators") + setup :prepare_destination + + test "source_root points to engine root" do + assert_equal ActivePrompt::Engine.root.to_s, ActivePrompt::Generators::InstallGenerator.source_root + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 5e546caf..27250111 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -67,7 +67,7 @@ begin generated_dir = Rails.root.join("tmp", "generators") FileUtils.rm_rf(generated_dir) -rescue => e +rescue StandardError => e warn "Warning: failed to clean #{generated_dir}: #{e.message}" end From d75f021d8c63297dcf7e648ed667dcd1fb2789bc Mon Sep 17 00:00:00 2001 From: Sarbada Date: Thu, 22 Jan 2026 22:21:27 +0545 Subject: [PATCH 5/5] Name composite indexes and add coverage for engine base/generator/indexes Tidy engine setup: enum shorthand, explicit asset manifest, dummy require_relative Add tests for ApplicationRecord inheritance, runtime scope, install generator, and index names --- app/assets/config/active_prompt_manifest.js | 4 +-- app/models/active_prompt/message.rb | 2 +- ...0251127000000_create_active_prompt_core.rb | 4 +-- test/active_prompt/indexes_test.rb | 14 ++++++++++ test/dummy/Gemfile.lock | 27 ++++++------------- test/dummy/config/application.rb | 3 +-- test/dummy/db/schema.rb | 22 +++++++-------- 7 files changed, 39 insertions(+), 37 deletions(-) create mode 100644 test/active_prompt/indexes_test.rb diff --git a/app/assets/config/active_prompt_manifest.js b/app/assets/config/active_prompt_manifest.js index 25434838..b58d2651 100644 --- a/app/assets/config/active_prompt_manifest.js +++ b/app/assets/config/active_prompt_manifest.js @@ -1,2 +1,2 @@ -//= link_directory ../javascripts/active_prompt .js -//= link_directory ../stylesheets/active_prompt .css +//= link active_prompt/application.js +//= link active_prompt/application.css diff --git a/app/models/active_prompt/message.rb b/app/models/active_prompt/message.rb index e253ef80..98230e7d 100644 --- a/app/models/active_prompt/message.rb +++ b/app/models/active_prompt/message.rb @@ -5,7 +5,7 @@ class Message < ApplicationRecord belongs_to :prompt, class_name: "ActivePrompt::Prompt", inverse_of: :messages - enum :role, { system: "system", user: "user", assistant: "assistant", tool: "tool" }, prefix: true + enum :role, %i[system user assistant tool], prefix: true validates :role, :content, presence: true end end diff --git a/db/migrate/20251127000000_create_active_prompt_core.rb b/db/migrate/20251127000000_create_active_prompt_core.rb index 6ced3a6e..f9944883 100644 --- a/db/migrate/20251127000000_create_active_prompt_core.rb +++ b/db/migrate/20251127000000_create_active_prompt_core.rb @@ -18,7 +18,7 @@ def change t.json :metadata, null: false, default: {} t.timestamps end - add_index :active_prompt_messages, [:prompt_id, :position] + add_index :active_prompt_messages, [:prompt_id, :position], name: "idx_ap_messages_prompt_position" create_table :active_prompt_actions do |t| t.references :prompt, null: false, foreign_key: { to_table: :active_prompt_prompts } @@ -29,7 +29,7 @@ def change t.string :status t.timestamps end - add_index :active_prompt_actions, [:prompt_id, :name] + add_index :active_prompt_actions, [:prompt_id, :name], name: "idx_ap_actions_prompt_name" create_table :active_prompt_contexts do |t| t.string :agent_type, null: false diff --git a/test/active_prompt/indexes_test.rb b/test/active_prompt/indexes_test.rb new file mode 100644 index 00000000..23e6b773 --- /dev/null +++ b/test/active_prompt/indexes_test.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true +require "test_helper" + +class ActivePromptIndexesTest < ActiveSupport::TestCase + def test_messages_prompt_position_index_named + index_names = ActiveRecord::Base.connection.indexes(:active_prompt_messages).map(&:name) + assert_includes index_names, "idx_ap_messages_prompt_position" + end + + def test_actions_prompt_name_index_named + index_names = ActiveRecord::Base.connection.indexes(:active_prompt_actions).map(&:name) + assert_includes index_names, "idx_ap_actions_prompt_name" + end +end diff --git a/test/dummy/Gemfile.lock b/test/dummy/Gemfile.lock index ad51db1f..4423bd93 100644 --- a/test/dummy/Gemfile.lock +++ b/test/dummy/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: ../../.. specs: - activeagent (0.6.3) + activeagent (1.0.1) actionpack (>= 7.2, <= 9.0) actionview (>= 7.2, <= 9.0) activejob (>= 7.2, <= 9.0) @@ -102,6 +102,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) + cgi (0.5.1) concurrent-ruby (1.3.5) connection_pool (2.5.4) crass (1.0.6) @@ -112,15 +113,6 @@ GEM drb (2.2.3) erb (5.1.1) erubi (1.13.1) - event_stream_parser (1.0.0) - faraday (2.14.0) - faraday-net_http (>= 2.0, < 3.5) - json - logger - faraday-multipart (1.1.1) - multipart-post (~> 2.0) - faraday-net_http (3.4.1) - net-http (>= 0.5.0) globalid (1.3.0) activesupport (>= 6.1) i18n (1.14.7) @@ -148,9 +140,6 @@ GEM mini_mime (1.1.5) minitest (5.26.0) msgpack (1.8.0) - multipart-post (2.4.1) - net-http (0.6.0) - uri net-imap (0.5.12) date net-protocol @@ -177,6 +166,10 @@ GEM racc (~> 1.4) nokogiri (1.18.10-x86_64-linux-musl) racc (~> 1.4) + openai (0.43.0) + base64 + cgi + connection_pool pp (0.6.3) prettyprint prettyprint (0.2.0) @@ -234,10 +227,6 @@ GEM reline (0.6.2) io-console (~> 0.5) rexml (3.4.4) - ruby-openai (8.3.0) - event_stream_parser (>= 0.3.0, < 2.0.0) - faraday (>= 1) - faraday-multipart (>= 1) rubyzip (3.2.0) securerandom (0.4.1) selenium-webdriver (4.36.0) @@ -293,14 +282,14 @@ PLATFORMS DEPENDENCIES activeagent! - anthropic (~> 1.1) + anthropic (~> 1.12) bootsnap capybara debug jbuilder + openai (~> 0.34) puma (>= 5.0) rails (~> 8.0.2.1) - ruby-openai (~> 8.3) selenium-webdriver sqlite3 (>= 2.1) tzinfo-data diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 0b853544..c2a66718 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -3,8 +3,7 @@ require "rails" # Pick the frameworks you want: require "active_model/railtie" -$LOAD_PATH.unshift File.expand_path("../../../lib", __dir__) -require "active_prompt" +require_relative "../../../lib/active_prompt" require "active_job/railtie" require "active_record/railtie" require "active_storage/engine" diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index c60310c3..8b194b7c 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -19,35 +19,35 @@ end create_table "posts", force: :cascade do |t| + t.string "title", null: false t.text "content" - t.datetime "created_at", null: false - t.boolean "published" + t.integer "user_id" + t.boolean "published", default: false t.datetime "published_at" - t.string "title", null: false + t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.integer "user_id" t.index ["published"], name: "index_posts_on_published" t.index ["user_id"], name: "index_posts_on_user_id" end create_table "profiles", force: :cascade do |t| + t.integer "user_id" t.text "bio" - t.datetime "created_at", null: false t.string "location" + t.string "website" t.json "social_links" + t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.integer "user_id" - t.string "website" t.index ["user_id"], name: "index_profiles_on_user_id", unique: true end create_table "users", force: :cascade do |t| - t.boolean "active" - t.integer "age" - t.datetime "created_at", null: false - t.string "email", null: false t.string "name", null: false + t.string "email", null: false + t.integer "age" t.string "role", default: "user" + t.boolean "active", default: true + t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true end