aven 0.0.3
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +35 -0
- data/Rakefile +19 -0
- data/app/assets/stylesheets/aven/application.css +14 -0
- data/app/assets/stylesheets/aven/application.tailwind.css +7 -0
- data/app/assets/stylesheets/aven/tailwind.css +224 -0
- data/app/channels/aven/chat/thread_channel.rb +39 -0
- data/app/components/aven/application_view_component.rb +15 -0
- data/app/components/aven/views/admin/dashboard/index/component.html.erb +1 -0
- data/app/components/aven/views/admin/dashboard/index/component.rb +5 -0
- data/app/components/aven/views/articles/edit/component.html.erb +14 -0
- data/app/components/aven/views/articles/edit/component.rb +14 -0
- data/app/components/aven/views/articles/form/component.html.erb +45 -0
- data/app/components/aven/views/articles/form/component.rb +27 -0
- data/app/components/aven/views/articles/index/component.html.erb +93 -0
- data/app/components/aven/views/articles/index/component.rb +29 -0
- data/app/components/aven/views/articles/new/component.html.erb +13 -0
- data/app/components/aven/views/articles/new/component.rb +14 -0
- data/app/components/aven/views/articles/show/component.html.erb +110 -0
- data/app/components/aven/views/articles/show/component.rb +34 -0
- data/app/components/aven/views/oauth/error/component.html.erb +44 -0
- data/app/components/aven/views/oauth/error/component.rb +30 -0
- data/app/components/aven/views/static/index/component.html.erb +17 -0
- data/app/components/aven/views/static/index/component.rb +16 -0
- data/app/components/aven/views/static/index/controller.js +7 -0
- data/app/controllers/aven/admin/base.rb +16 -0
- data/app/controllers/aven/admin/dashboard_controller.rb +9 -0
- data/app/controllers/aven/agentic/agents_controller.rb +56 -0
- data/app/controllers/aven/agentic/documents_controller.rb +51 -0
- data/app/controllers/aven/agentic/mcp_controller.rb +124 -0
- data/app/controllers/aven/agentic/tools_controller.rb +37 -0
- data/app/controllers/aven/ai/text_controller.rb +41 -0
- data/app/controllers/aven/application_controller.rb +27 -0
- data/app/controllers/aven/articles_controller.rb +114 -0
- data/app/controllers/aven/auth_controller.rb +12 -0
- data/app/controllers/aven/chat/threads_controller.rb +67 -0
- data/app/controllers/aven/oauth/auth0_controller.rb +84 -0
- data/app/controllers/aven/oauth/base_controller.rb +183 -0
- data/app/controllers/aven/oauth/documentation/auth0.md +387 -0
- data/app/controllers/aven/oauth/documentation/entra_id.md +608 -0
- data/app/controllers/aven/oauth/documentation/github.md +329 -0
- data/app/controllers/aven/oauth/documentation/google.md +253 -0
- data/app/controllers/aven/oauth/entra_id_controller.rb +92 -0
- data/app/controllers/aven/oauth/github_controller.rb +91 -0
- data/app/controllers/aven/oauth/google_controller.rb +64 -0
- data/app/controllers/aven/static_controller.rb +7 -0
- data/app/controllers/aven/tags_controller.rb +44 -0
- data/app/controllers/aven/workspaces_controller.rb +20 -0
- data/app/controllers/concerns/aven/authentication.rb +49 -0
- data/app/controllers/concerns/aven/controller_helpers.rb +38 -0
- data/app/helpers/aven/application_helper.rb +16 -0
- data/app/javascript/aven/application.js +3 -0
- data/app/javascript/aven/controllers/application.js +5 -0
- data/app/javascript/aven/controllers/index.js +11 -0
- data/app/jobs/aven/agentic/document_embedding_job.rb +28 -0
- data/app/jobs/aven/agentic/document_ocr_job.rb +28 -0
- data/app/jobs/aven/application_job.rb +4 -0
- data/app/jobs/aven/chat/calculate_cost_job.rb +26 -0
- data/app/jobs/aven/chat/run_job.rb +27 -0
- data/app/mailers/aven/application_mailer.rb +6 -0
- data/app/models/aven/agentic/agent.rb +76 -0
- data/app/models/aven/agentic/agent_document.rb +37 -0
- data/app/models/aven/agentic/agent_tool.rb +37 -0
- data/app/models/aven/agentic/document.rb +162 -0
- data/app/models/aven/agentic/document_embedding.rb +39 -0
- data/app/models/aven/agentic/tool.rb +106 -0
- data/app/models/aven/agentic/tool_parameter.rb +56 -0
- data/app/models/aven/application_record.rb +5 -0
- data/app/models/aven/article.rb +86 -0
- data/app/models/aven/article_attachment.rb +18 -0
- data/app/models/aven/article_relationship.rb +26 -0
- data/app/models/aven/chat/message.rb +135 -0
- data/app/models/aven/chat/thread.rb +159 -0
- data/app/models/aven/import/entry.rb +45 -0
- data/app/models/aven/import/item_link.rb +36 -0
- data/app/models/aven/import/processor.rb +123 -0
- data/app/models/aven/import.rb +102 -0
- data/app/models/aven/item/embed.rb +54 -0
- data/app/models/aven/item/embeddable.rb +141 -0
- data/app/models/aven/item/linkable.rb +212 -0
- data/app/models/aven/item/schema/builder.rb +139 -0
- data/app/models/aven/item/schemaed.rb +252 -0
- data/app/models/aven/item/schemas/base.rb +108 -0
- data/app/models/aven/item.rb +128 -0
- data/app/models/aven/item_link.rb +43 -0
- data/app/models/aven/item_schema.rb +87 -0
- data/app/models/aven/log.rb +66 -0
- data/app/models/aven/loggable.rb +20 -0
- data/app/models/aven/user.rb +40 -0
- data/app/models/aven/workspace.rb +93 -0
- data/app/models/aven/workspace_role.rb +46 -0
- data/app/models/aven/workspace_user.rb +54 -0
- data/app/models/aven/workspace_user_role.rb +38 -0
- data/app/models/concerns/aven/agentic/document_embeddable.rb +58 -0
- data/app/models/concerns/aven/searchable.rb +61 -0
- data/app/services/aven/agentic/dynamic_tool_builder.rb +81 -0
- data/app/services/aven/agentic/mcp/adapter.rb +77 -0
- data/app/services/aven/agentic/mcp/result_formatter.rb +57 -0
- data/app/services/aven/agentic/mcp/server_factory.rb +43 -0
- data/app/services/aven/agentic/ocr/base_extractor.rb +39 -0
- data/app/services/aven/agentic/ocr/excel_extractor.rb +43 -0
- data/app/services/aven/agentic/ocr/image_extractor.rb +22 -0
- data/app/services/aven/agentic/ocr/pdf_extractor.rb +48 -0
- data/app/services/aven/agentic/ocr/processor.rb +36 -0
- data/app/services/aven/agentic/ocr/textract_client.rb +131 -0
- data/app/services/aven/agentic/ocr/word_extractor.rb +34 -0
- data/app/services/aven/agentic/tool_result_formatter.rb +76 -0
- data/app/services/aven/agentic/tools/base.rb +55 -0
- data/app/services/aven/agentic/tools/concerns/boolean_filtering.rb +40 -0
- data/app/services/aven/agentic/tools/concerns/enum_filtering.rb +47 -0
- data/app/services/aven/agentic/tools/concerns/geo_filtering.rb +56 -0
- data/app/services/aven/agentic/tools/concerns/range_filtering.rb +51 -0
- data/app/services/aven/chat/broadcaster.rb +59 -0
- data/app/services/aven/chat/config.rb +93 -0
- data/app/services/aven/chat/message_builder.rb +42 -0
- data/app/services/aven/chat/orchestrator.rb +69 -0
- data/app/services/aven/chat/runner.rb +105 -0
- data/app/services/aven/chat/title_generator.rb +61 -0
- data/app/services/aven/external/gmail_client.rb +173 -0
- data/app/services/aven/external/google_contacts_client.rb +95 -0
- data/app/views/layouts/aven/admin.html.erb +16 -0
- data/app/views/layouts/aven/application.html.erb +18 -0
- data/config/importmap.rb +16 -0
- data/config/routes.rb +63 -0
- data/db/migrate/20200101000001_create_aven_users.rb +19 -0
- data/db/migrate/20200101000002_create_aven_workspaces.rb +14 -0
- data/db/migrate/20200101000003_create_aven_workspace_users.rb +12 -0
- data/db/migrate/20200101000004_create_aven_workspace_roles.rb +13 -0
- data/db/migrate/20200101000005_create_aven_workspace_user_roles.rb +12 -0
- data/db/migrate/20200101000006_create_aven_logs.rb +21 -0
- data/db/migrate/20200101000009_create_aven_items.rb +17 -0
- data/db/migrate/20200101000010_create_aven_item_links.rb +17 -0
- data/db/migrate/20200101000011_create_aven_agentic_tools.rb +19 -0
- data/db/migrate/20200101000012_create_aven_agentic_tool_parameters.rb +20 -0
- data/db/migrate/20200101000013_create_aven_agentic_documents.rb +22 -0
- data/db/migrate/20200101000014_create_aven_agentic_document_embeddings.rb +18 -0
- data/db/migrate/20200101000015_create_aven_agentic_agents.rb +18 -0
- data/db/migrate/20200101000016_create_aven_agentic_agent_tools.rb +13 -0
- data/db/migrate/20200101000017_create_aven_agentic_agent_documents.rb +13 -0
- data/db/migrate/20200101000018_create_aven_chat_threads.rb +19 -0
- data/db/migrate/20200101000019_create_aven_chat_messages.rb +26 -0
- data/db/migrate/20200101000020_add_pg_search_support.rb +21 -0
- data/db/migrate/20200101000021_create_aven_item_schemas.rb +18 -0
- data/db/migrate/20200101000022_create_aven_imports.rb +23 -0
- data/db/migrate/20200101000023_create_aven_import_entries.rb +13 -0
- data/db/migrate/20200101000024_create_aven_import_item_links.rb +13 -0
- data/db/migrate/20200101000025_create_aven_articles.rb +19 -0
- data/db/migrate/20200101000026_create_aven_article_attachments.rb +13 -0
- data/db/migrate/20200101000027_create_aven_article_relationships.rb +15 -0
- data/lib/aven/configuration.rb +87 -0
- data/lib/aven/engine.rb +43 -0
- data/lib/aven/model/tenant_model.rb +91 -0
- data/lib/aven/model.rb +6 -0
- data/lib/aven/version.rb +3 -0
- data/lib/aven.rb +8 -0
- data/lib/tasks/annotate_rb.rake +10 -0
- data/lib/tasks/aven_tasks.rake +21 -0
- metadata +426 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenAgenticAgents < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_agentic_agents do |t|
|
|
6
|
+
t.references :workspace, null: false, foreign_key: { to_table: :aven_workspaces }
|
|
7
|
+
t.string :label, null: false
|
|
8
|
+
t.string :slug
|
|
9
|
+
t.text :system_prompt
|
|
10
|
+
t.text :user_facing_question
|
|
11
|
+
t.boolean :enabled, default: true, null: false
|
|
12
|
+
t.timestamps
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
add_index :aven_agentic_agents, [:workspace_id, :slug], unique: true
|
|
16
|
+
add_index :aven_agentic_agents, :enabled
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenAgenticAgentTools < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_agentic_agent_tools do |t|
|
|
6
|
+
t.references :agent, null: false, foreign_key: { to_table: :aven_agentic_agents }
|
|
7
|
+
t.references :tool, null: false, foreign_key: { to_table: :aven_agentic_tools }
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :aven_agentic_agent_tools, [:agent_id, :tool_id], unique: true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenAgenticAgentDocuments < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_agentic_agent_documents do |t|
|
|
6
|
+
t.references :agent, null: false, foreign_key: { to_table: :aven_agentic_agents }
|
|
7
|
+
t.references :document, null: false, foreign_key: { to_table: :aven_agentic_documents }
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :aven_agentic_agent_documents, [:agent_id, :document_id], unique: true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenChatThreads < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_chat_threads do |t|
|
|
6
|
+
t.references :workspace, null: false, foreign_key: { to_table: :aven_workspaces }
|
|
7
|
+
t.references :user, null: false, foreign_key: { to_table: :aven_users }
|
|
8
|
+
t.references :agent, foreign_key: { to_table: :aven_agentic_agents }
|
|
9
|
+
t.string :title
|
|
10
|
+
t.jsonb :tools, default: nil # Locked tool names array
|
|
11
|
+
t.jsonb :documents, default: nil # Locked document IDs array
|
|
12
|
+
t.text :context_markdown
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
add_index :aven_chat_threads, [:workspace_id, :user_id]
|
|
17
|
+
add_index :aven_chat_threads, :created_at
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenChatMessages < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_chat_messages do |t|
|
|
6
|
+
t.references :thread, null: false, foreign_key: { to_table: :aven_chat_threads }
|
|
7
|
+
t.references :parent, foreign_key: { to_table: :aven_chat_messages }
|
|
8
|
+
t.string :role, null: false # user, assistant, tool, system
|
|
9
|
+
t.string :status, default: "pending" # pending, streaming, success, error
|
|
10
|
+
t.text :content
|
|
11
|
+
t.string :model
|
|
12
|
+
t.integer :input_tokens, default: 0
|
|
13
|
+
t.integer :output_tokens, default: 0
|
|
14
|
+
t.integer :total_tokens, default: 0
|
|
15
|
+
t.decimal :cost_usd, precision: 10, scale: 6, default: 0.0
|
|
16
|
+
t.datetime :started_at
|
|
17
|
+
t.datetime :completed_at
|
|
18
|
+
t.jsonb :tool_call, default: nil # Tool call details
|
|
19
|
+
t.timestamps
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
add_index :aven_chat_messages, :role
|
|
23
|
+
add_index :aven_chat_messages, :status
|
|
24
|
+
add_index :aven_chat_messages, [:thread_id, :created_at]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddPgSearchSupport < ActiveRecord::Migration[8.0]
|
|
4
|
+
def up
|
|
5
|
+
# Enable pg_trgm for fuzzy matching
|
|
6
|
+
enable_extension "pg_trgm"
|
|
7
|
+
|
|
8
|
+
# Create pg_search_documents table for multi-search
|
|
9
|
+
create_table :pg_search_documents do |t|
|
|
10
|
+
t.text :content
|
|
11
|
+
t.belongs_to :searchable, polymorphic: true, index: true
|
|
12
|
+
t.belongs_to :workspace, foreign_key: { to_table: :aven_workspaces }, index: true
|
|
13
|
+
t.timestamps null: false
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def down
|
|
18
|
+
drop_table :pg_search_documents
|
|
19
|
+
disable_extension "pg_trgm"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenItemSchemas < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_item_schemas do |t|
|
|
6
|
+
t.references :workspace, null: false, foreign_key: { to_table: :aven_workspaces }
|
|
7
|
+
t.string :slug, null: false
|
|
8
|
+
t.jsonb :schema, null: false, default: {}
|
|
9
|
+
t.jsonb :fields, null: false, default: {}
|
|
10
|
+
t.jsonb :embeds, null: false, default: {}
|
|
11
|
+
t.jsonb :links, null: false, default: {}
|
|
12
|
+
t.timestamps
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
add_index :aven_item_schemas, [:workspace_id, :slug], unique: true
|
|
16
|
+
add_index :aven_item_schemas, :slug
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenImports < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_imports do |t|
|
|
6
|
+
t.references :workspace, null: false, foreign_key: { to_table: :aven_workspaces }
|
|
7
|
+
t.string :source, null: false
|
|
8
|
+
t.string :status, null: false, default: "pending"
|
|
9
|
+
t.integer :total_count, default: 0
|
|
10
|
+
t.integer :processed_count, default: 0
|
|
11
|
+
t.integer :imported_count, default: 0
|
|
12
|
+
t.integer :skipped_count, default: 0
|
|
13
|
+
t.text :error_message
|
|
14
|
+
t.jsonb :errors_log, default: []
|
|
15
|
+
t.datetime :started_at
|
|
16
|
+
t.datetime :completed_at
|
|
17
|
+
t.timestamps
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
add_index :aven_imports, :source
|
|
21
|
+
add_index :aven_imports, :status
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenImportEntries < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_import_entries do |t|
|
|
6
|
+
t.references :import, null: false, foreign_key: { to_table: :aven_imports }
|
|
7
|
+
t.jsonb :data, null: false, default: {}
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :aven_import_entries, :data, using: :gin
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenImportItemLinks < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_import_item_links do |t|
|
|
6
|
+
t.references :entry, null: false, foreign_key: { to_table: :aven_import_entries }
|
|
7
|
+
t.references :item, null: false, foreign_key: { to_table: :aven_items }
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :aven_import_item_links, [:entry_id, :item_id], unique: true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenArticles < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_articles do |t|
|
|
6
|
+
t.references :workspace, null: false, foreign_key: { to_table: :aven_workspaces }
|
|
7
|
+
t.references :author, null: true, foreign_key: { to_table: :aven_users }
|
|
8
|
+
t.string :title, null: false
|
|
9
|
+
t.string :slug
|
|
10
|
+
t.text :intro
|
|
11
|
+
t.text :description
|
|
12
|
+
t.datetime :published_at
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
add_index :aven_articles, [:workspace_id, :slug], unique: true
|
|
17
|
+
add_index :aven_articles, :published_at
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenArticleAttachments < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_article_attachments do |t|
|
|
6
|
+
t.references :article, null: false, foreign_key: { to_table: :aven_articles }
|
|
7
|
+
t.integer :position, default: 0, null: false
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :aven_article_attachments, [:article_id, :position]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateAvenArticleRelationships < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :aven_article_relationships do |t|
|
|
6
|
+
t.references :article, null: false, foreign_key: { to_table: :aven_articles }
|
|
7
|
+
t.references :related_article, null: false, foreign_key: { to_table: :aven_articles }
|
|
8
|
+
t.integer :position, default: 0
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
add_index :aven_article_relationships, [:article_id, :related_article_id], unique: true, name: "idx_article_relationships_unique"
|
|
13
|
+
add_index :aven_article_relationships, [:article_id, :position]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Aven
|
|
2
|
+
class Configuration
|
|
3
|
+
attr_accessor :authenticated_root_path
|
|
4
|
+
attr_accessor :oauth_providers
|
|
5
|
+
attr_accessor :agentic
|
|
6
|
+
attr_accessor :ocr
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@authenticated_root_path = nil
|
|
10
|
+
@oauth_providers = {}
|
|
11
|
+
@agentic = AgenticConfiguration.new
|
|
12
|
+
@ocr = OcrConfiguration.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Configure OAuth providers
|
|
16
|
+
#
|
|
17
|
+
# @param provider [Symbol] The OAuth provider name (:github, :google, etc.)
|
|
18
|
+
# @param credentials [Hash] Configuration hash with:
|
|
19
|
+
# - :client_id [String] OAuth client ID
|
|
20
|
+
# - :client_secret [String] OAuth client secret
|
|
21
|
+
# - :scope [String] Optional. OAuth scopes to request
|
|
22
|
+
# - Any other provider-specific options
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# config.configure_oauth(:github, {
|
|
26
|
+
# client_id: "abc123",
|
|
27
|
+
# client_secret: "secret",
|
|
28
|
+
# scope: "user:email,repo,workflow"
|
|
29
|
+
# })
|
|
30
|
+
def configure_oauth(provider, credentials = {})
|
|
31
|
+
@oauth_providers[provider.to_sym] = credentials
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Resolves authenticated_root_path, calling it if it's a lambda/proc
|
|
35
|
+
#
|
|
36
|
+
# @return [String] The resolved path
|
|
37
|
+
def resolve_authenticated_root_path
|
|
38
|
+
return nil if @authenticated_root_path.nil?
|
|
39
|
+
|
|
40
|
+
@authenticated_root_path.respond_to?(:call) ? @authenticated_root_path.call : @authenticated_root_path
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Agentic configuration (LLM, tools, chat)
|
|
45
|
+
class AgenticConfiguration
|
|
46
|
+
attr_accessor :default_model
|
|
47
|
+
attr_accessor :system_prompt
|
|
48
|
+
attr_accessor :tools_enabled
|
|
49
|
+
attr_accessor :mcp_enabled
|
|
50
|
+
attr_accessor :mcp_api_token
|
|
51
|
+
|
|
52
|
+
def initialize
|
|
53
|
+
@default_model = "claude-sonnet-4-5-20250929"
|
|
54
|
+
@system_prompt = "You are a helpful assistant."
|
|
55
|
+
@tools_enabled = true
|
|
56
|
+
@mcp_enabled = false
|
|
57
|
+
@mcp_api_token = nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# OCR configuration
|
|
62
|
+
class OcrConfiguration
|
|
63
|
+
attr_accessor :provider
|
|
64
|
+
attr_accessor :aws_region
|
|
65
|
+
attr_accessor :aws_access_key_id
|
|
66
|
+
attr_accessor :aws_secret_access_key
|
|
67
|
+
|
|
68
|
+
def initialize
|
|
69
|
+
@provider = nil # :textract, :google_vision, etc.
|
|
70
|
+
@aws_region = nil
|
|
71
|
+
@aws_access_key_id = nil
|
|
72
|
+
@aws_secret_access_key = nil
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class << self
|
|
77
|
+
attr_writer :configuration
|
|
78
|
+
|
|
79
|
+
def configuration
|
|
80
|
+
@configuration ||= Configuration.new
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def configure
|
|
84
|
+
yield(configuration)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
data/lib/aven/engine.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require "importmap-rails"
|
|
2
|
+
require "view_component-contrib"
|
|
3
|
+
require "dry-effects"
|
|
4
|
+
require "json_skooma"
|
|
5
|
+
require "aeno"
|
|
6
|
+
require "friendly_id"
|
|
7
|
+
require "acts-as-taggable-on"
|
|
8
|
+
require "aven/model"
|
|
9
|
+
|
|
10
|
+
module Aven
|
|
11
|
+
class << self
|
|
12
|
+
attr_accessor :importmap
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Engine < ::Rails::Engine
|
|
16
|
+
isolate_namespace Aven
|
|
17
|
+
|
|
18
|
+
Aeno::EngineHelpers.setup_assets(self, namespace: Aven)
|
|
19
|
+
Aeno::EngineHelpers.setup_importmap(self, namespace: Aven)
|
|
20
|
+
|
|
21
|
+
# Append engine migrations to the main app
|
|
22
|
+
initializer :append_migrations do |app|
|
|
23
|
+
unless app.root.to_s.include?("test/dummy")
|
|
24
|
+
config.paths["db/migrate"].expanded.each do |expanded_path|
|
|
25
|
+
app.config.paths["db/migrate"] << expanded_path
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Include engine route helpers, authentication, and controller helpers in controllers and views
|
|
31
|
+
initializer "aven.helpers" do
|
|
32
|
+
ActiveSupport.on_load(:action_controller) do
|
|
33
|
+
include Aven::Engine.routes.url_helpers
|
|
34
|
+
include Aven::Authentication
|
|
35
|
+
include Aven::ControllerHelpers
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
ActiveSupport.on_load(:action_view) do
|
|
39
|
+
include Aven::Engine.routes.url_helpers
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module Aven
|
|
2
|
+
module Model
|
|
3
|
+
# TenantModel provides workspace multi-tenancy support for ActiveRecord models.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# class Server < ApplicationRecord
|
|
7
|
+
# include Aven::TenantModel
|
|
8
|
+
# end
|
|
9
|
+
#
|
|
10
|
+
# This will:
|
|
11
|
+
# - Add belongs_to :workspace association
|
|
12
|
+
# - Validate workspace_id column exists
|
|
13
|
+
# - Register model with Aven::Workspace
|
|
14
|
+
# - Add workspace scoping helpers
|
|
15
|
+
#
|
|
16
|
+
# Inspired by Flipper's Model::ActiveRecord pattern.
|
|
17
|
+
module TenantModel
|
|
18
|
+
extend ActiveSupport::Concern
|
|
19
|
+
|
|
20
|
+
included do
|
|
21
|
+
# Validate workspace_id column exists at include time (skip during migrations)
|
|
22
|
+
if table_exists? && !column_names.include?("workspace_id")
|
|
23
|
+
raise ArgumentError,
|
|
24
|
+
"#{name} includes Aven::TenantModel but does not have a workspace_id column. " \
|
|
25
|
+
"Add a workspace_id column to #{table_name} first."
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Add belongs_to association if not already defined
|
|
29
|
+
unless reflect_on_association(:workspace)
|
|
30
|
+
belongs_to :workspace, class_name: "Aven::Workspace"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Register this model as a tenant model
|
|
34
|
+
Aven::Workspace.register_tenant_model(self)
|
|
35
|
+
|
|
36
|
+
# Add scopes for workspace querying
|
|
37
|
+
scope :in_workspace, ->(workspace) { where(workspace_id: workspace.id) }
|
|
38
|
+
scope :for_workspace, ->(workspace) { where(workspace_id: workspace.id) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Returns a unique identifier combining class name and workspace_id
|
|
42
|
+
# Useful for caching keys, logging, permissions, etc.
|
|
43
|
+
#
|
|
44
|
+
# Example:
|
|
45
|
+
# server.workspace_tenant_id #=> "Server;123"
|
|
46
|
+
def workspace_tenant_id
|
|
47
|
+
"#{self.class.base_class.name};#{workspace_id}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Check if this model is workspace-scoped
|
|
51
|
+
def workspace_scoped?
|
|
52
|
+
true
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Returns workspace association name for this model type
|
|
56
|
+
def workspace_association_name
|
|
57
|
+
self.class.workspace_association_name
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
module ClassMethods
|
|
61
|
+
# Make workspace association optional
|
|
62
|
+
# Call this in your model if workspace can be nil
|
|
63
|
+
#
|
|
64
|
+
# Example:
|
|
65
|
+
# class DnsCredential < ApplicationRecord
|
|
66
|
+
# include Aven::TenantModel
|
|
67
|
+
# workspace_optional!
|
|
68
|
+
# end
|
|
69
|
+
def workspace_optional!
|
|
70
|
+
_reflect_on_association(:workspace).options[:optional] = true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Returns the association name that Workspace will use for this model
|
|
74
|
+
# Example: Server => :servers, DnsCredential => :dns_credentials
|
|
75
|
+
def workspace_association_name
|
|
76
|
+
name.underscore.pluralize.to_sym
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Check if this model has a unique workspace constraint
|
|
80
|
+
# Used to determine if Workspace should use has_one vs has_many
|
|
81
|
+
def unique_per_workspace?
|
|
82
|
+
return false unless table_exists?
|
|
83
|
+
|
|
84
|
+
connection.indexes(table_name).any? { |idx|
|
|
85
|
+
idx.unique && idx.columns == [ "workspace_id" ]
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/aven/model.rb
ADDED
data/lib/aven/version.rb
ADDED
data/lib/aven.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# This rake task was added by annotate_rb gem.
|
|
2
|
+
|
|
3
|
+
# Can set `ANNOTATERB_SKIP_ON_DB_TASKS` to be anything to skip this
|
|
4
|
+
is_dummy = Rails.application.class.module_parent_name == "Dummy"
|
|
5
|
+
|
|
6
|
+
if Rails.env.development? && ENV["ANNOTATERB_SKIP_ON_DB_TASKS"].nil? && is_dummy
|
|
7
|
+
require "annotate_rb"
|
|
8
|
+
|
|
9
|
+
AnnotateRb::Core.load_rake_tasks
|
|
10
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# desc "Explaining what the task does"
|
|
2
|
+
namespace :aven do
|
|
3
|
+
desc "run tailwind"
|
|
4
|
+
task :tailwind_engine_watch do
|
|
5
|
+
require "tailwindcss-rails"
|
|
6
|
+
|
|
7
|
+
command = [
|
|
8
|
+
Tailwindcss::Commands.compile_command.first,
|
|
9
|
+
"-i", Aven::Engine.root.join("app/assets/stylesheets/aven/application.tailwind.css").to_s,
|
|
10
|
+
"-o", Aven::Engine.root.join("app/assets/stylesheets/aven/tailwind.css").to_s,
|
|
11
|
+
"-w",
|
|
12
|
+
"--content", [
|
|
13
|
+
Aven::Engine.root.join("app/components/**/*.rb").to_s,
|
|
14
|
+
Aven::Engine.root.join("app/components/**/*.erb").to_s
|
|
15
|
+
].join(",")
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
p command
|
|
19
|
+
system(*command)
|
|
20
|
+
end
|
|
21
|
+
end
|