Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d421da3537 | ||
|
|
b31b220885 | ||
|
|
5f689518af | ||
|
|
c630a609aa | ||
|
|
5d1713485c | ||
|
|
1dde9329dd | ||
|
|
bf76fd3769 | ||
|
|
a9a113bace | ||
|
|
65e3f8231f | ||
|
|
f2d3a6ee4f | ||
|
|
b67dbf3761 | ||
|
|
a49521c9d6 |
@@ -0,0 +1,11 @@
|
|||||||
|
class Api::V1::Accounts::Captain::ConfigController < Api::V1::Accounts::BaseController
|
||||||
|
before_action :current_account
|
||||||
|
|
||||||
|
def show
|
||||||
|
render json: {
|
||||||
|
providers: Llm::ConfigService.providers,
|
||||||
|
models: Llm::ConfigService.models,
|
||||||
|
features: Llm::ConfigService.all_features_config
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -92,7 +92,10 @@ class Api::V1::AccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def settings_params
|
def settings_params
|
||||||
params.permit(:auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting, :audio_transcriptions, :auto_resolve_label)
|
permitted = params.permit(:auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting, :audio_transcriptions, :auto_resolve_label)
|
||||||
|
permitted[:captain_models] = params[:captain_models].to_unsafe_h if params[:captain_models].present?
|
||||||
|
permitted[:captain_features] = params[:captain_features].to_unsafe_h if params[:captain_features].present?
|
||||||
|
permitted
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_signup_enabled
|
def check_signup_enabled
|
||||||
|
|||||||
@@ -53,9 +53,11 @@ class Account < ApplicationRecord
|
|||||||
validates_with JsonSchemaValidator,
|
validates_with JsonSchemaValidator,
|
||||||
schema: SETTINGS_PARAMS_SCHEMA,
|
schema: SETTINGS_PARAMS_SCHEMA,
|
||||||
attribute_resolver: ->(record) { record.settings }
|
attribute_resolver: ->(record) { record.settings }
|
||||||
|
validate :validate_captain_models
|
||||||
|
|
||||||
store_accessor :settings, :auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting
|
store_accessor :settings, :auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting
|
||||||
store_accessor :settings, :audio_transcriptions, :auto_resolve_label
|
store_accessor :settings, :audio_transcriptions, :auto_resolve_label
|
||||||
|
store_accessor :settings, :captain_models, :captain_features
|
||||||
|
|
||||||
has_many :account_users, dependent: :destroy_async
|
has_many :account_users, dependent: :destroy_async
|
||||||
has_many :agent_bot_inboxes, dependent: :destroy_async
|
has_many :agent_bot_inboxes, dependent: :destroy_async
|
||||||
@@ -159,8 +161,46 @@ class Account < ApplicationRecord
|
|||||||
ISO_639.find(account_locale)&.english_name&.downcase || 'english'
|
ISO_639.find(account_locale)&.english_name&.downcase || 'english'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def captain_preferences
|
||||||
|
{
|
||||||
|
models: captain_models_with_defaults,
|
||||||
|
features: captain_features_with_defaults
|
||||||
|
}.with_indifferent_access
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def captain_models_with_defaults
|
||||||
|
stored_models = captain_models || {}
|
||||||
|
Llm::ConfigService.feature_keys.each_with_object({}) do |feature_key, result|
|
||||||
|
stored_value = stored_models[feature_key]
|
||||||
|
result[feature_key] = if stored_value.present? && Llm::ConfigService.valid_model_for_feature?(feature_key, stored_value)
|
||||||
|
stored_value
|
||||||
|
else
|
||||||
|
Llm::ConfigService.default_model_for_feature(feature_key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def captain_features_with_defaults
|
||||||
|
stored_features = captain_features || {}
|
||||||
|
Llm::ConfigService.feature_keys.index_with do |feature_key|
|
||||||
|
stored_features[feature_key] == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_captain_models
|
||||||
|
return if captain_models.blank?
|
||||||
|
|
||||||
|
captain_models.each do |feature_key, model_name|
|
||||||
|
next if model_name.blank?
|
||||||
|
next if Llm::ConfigService.valid_model_for_feature?(feature_key, model_name)
|
||||||
|
|
||||||
|
allowed_models = Llm::ConfigService.models_for_feature(feature_key)
|
||||||
|
errors.add(:captain_models, "'#{model_name}' is not a valid model for #{feature_key}. Allowed: #{allowed_models.join(', ')}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def notify_creation
|
def notify_creation
|
||||||
Rails.configuration.dispatcher.dispatch(ACCOUNT_CREATED, Time.zone.now, account: self)
|
Rails.configuration.dispatcher.dispatch(ACCOUNT_CREATED, Time.zone.now, account: self)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -25,3 +25,4 @@ json.name @account.name
|
|||||||
json.support_email @account.support_email
|
json.support_email @account.support_email
|
||||||
json.status @account.status
|
json.status @account.status
|
||||||
json.cache_keys @account.cache_keys
|
json.cache_keys @account.cache_keys
|
||||||
|
json.captain_preferences @account.captain_preferences
|
||||||
|
|||||||
+177
-177
@@ -15,58 +15,58 @@
|
|||||||
|
|
||||||
# ------- Branding Related Config ------- #
|
# ------- Branding Related Config ------- #
|
||||||
- name: INSTALLATION_NAME
|
- name: INSTALLATION_NAME
|
||||||
value: 'Chatwoot'
|
value: "Chatwoot"
|
||||||
display_title: 'Installation Name'
|
display_title: "Installation Name"
|
||||||
description: 'The installation wide name that would be used in the dashboard, title etc.'
|
description: "The installation wide name that would be used in the dashboard, title etc."
|
||||||
- name: LOGO_THUMBNAIL
|
- name: LOGO_THUMBNAIL
|
||||||
value: '/brand-assets/logo_thumbnail.svg'
|
value: "/brand-assets/logo_thumbnail.svg"
|
||||||
display_title: 'Logo Thumbnail'
|
display_title: "Logo Thumbnail"
|
||||||
description: 'The thumbnail that would be used for favicon (512px X 512px)'
|
description: "The thumbnail that would be used for favicon (512px X 512px)"
|
||||||
- name: LOGO
|
- name: LOGO
|
||||||
value: '/brand-assets/logo.svg'
|
value: "/brand-assets/logo.svg"
|
||||||
display_title: 'Logo'
|
display_title: "Logo"
|
||||||
description: 'The logo that would be used on the dashboard, login page etc.'
|
description: "The logo that would be used on the dashboard, login page etc."
|
||||||
- name: LOGO_DARK
|
- name: LOGO_DARK
|
||||||
value: '/brand-assets/logo_dark.svg'
|
value: "/brand-assets/logo_dark.svg"
|
||||||
display_title: 'Logo Dark Mode'
|
display_title: "Logo Dark Mode"
|
||||||
description: 'The logo that would be used on the dashboard, login page etc. for dark mode'
|
description: "The logo that would be used on the dashboard, login page etc. for dark mode"
|
||||||
- name: BRAND_URL
|
- name: BRAND_URL
|
||||||
value: 'https://www.chatwoot.com'
|
value: "https://www.chatwoot.com"
|
||||||
display_title: 'Brand URL'
|
display_title: "Brand URL"
|
||||||
description: 'The URL that would be used in emails under the section “Powered By”'
|
description: "The URL that would be used in emails under the section “Powered By”"
|
||||||
- name: WIDGET_BRAND_URL
|
- name: WIDGET_BRAND_URL
|
||||||
value: 'https://www.chatwoot.com'
|
value: "https://www.chatwoot.com"
|
||||||
display_title: 'Widget Brand URL'
|
display_title: "Widget Brand URL"
|
||||||
description: 'The URL that would be used in the widget under the section “Powered By”'
|
description: "The URL that would be used in the widget under the section “Powered By”"
|
||||||
- name: BRAND_NAME
|
- name: BRAND_NAME
|
||||||
value: 'Chatwoot'
|
value: "Chatwoot"
|
||||||
display_title: 'Brand Name'
|
display_title: "Brand Name"
|
||||||
description: 'The name that would be used in emails and the widget'
|
description: "The name that would be used in emails and the widget"
|
||||||
- name: TERMS_URL
|
- name: TERMS_URL
|
||||||
value: 'https://www.chatwoot.com/terms-of-service'
|
value: "https://www.chatwoot.com/terms-of-service"
|
||||||
display_title: 'Terms URL'
|
display_title: "Terms URL"
|
||||||
description: 'The terms of service URL displayed in Signup Page'
|
description: "The terms of service URL displayed in Signup Page"
|
||||||
- name: PRIVACY_URL
|
- name: PRIVACY_URL
|
||||||
value: 'https://www.chatwoot.com/privacy-policy'
|
value: "https://www.chatwoot.com/privacy-policy"
|
||||||
display_title: 'Privacy URL'
|
display_title: "Privacy URL"
|
||||||
description: 'The privacy policy URL displayed in the app'
|
description: "The privacy policy URL displayed in the app"
|
||||||
- name: DISPLAY_MANIFEST
|
- name: DISPLAY_MANIFEST
|
||||||
value: true
|
value: true
|
||||||
display_title: 'Chatwoot Metadata'
|
display_title: "Chatwoot Metadata"
|
||||||
description: 'Display default Chatwoot metadata like favicons and upgrade warnings'
|
description: "Display default Chatwoot metadata like favicons and upgrade warnings"
|
||||||
type: boolean
|
type: boolean
|
||||||
# ------- End of Branding Related Config ------- #
|
# ------- End of Branding Related Config ------- #
|
||||||
|
|
||||||
# ------- Signup & Account Related Config ------- #
|
# ------- Signup & Account Related Config ------- #
|
||||||
- name: ENABLE_ACCOUNT_SIGNUP
|
- name: ENABLE_ACCOUNT_SIGNUP
|
||||||
display_title: 'Enable Account Signup'
|
display_title: "Enable Account Signup"
|
||||||
value: false
|
value: false
|
||||||
description: 'Allow users to signup for new accounts'
|
description: "Allow users to signup for new accounts"
|
||||||
locked: false
|
locked: false
|
||||||
type: boolean
|
type: boolean
|
||||||
- name: CREATE_NEW_ACCOUNT_FROM_DASHBOARD
|
- name: CREATE_NEW_ACCOUNT_FROM_DASHBOARD
|
||||||
value: false
|
value: false
|
||||||
description: 'Allow users to create new accounts from the dashboard'
|
description: "Allow users to create new accounts from the dashboard"
|
||||||
locked: false
|
locked: false
|
||||||
- name: HCAPTCHA_SITE_KEY
|
- name: HCAPTCHA_SITE_KEY
|
||||||
value:
|
value:
|
||||||
@@ -76,127 +76,127 @@
|
|||||||
locked: false
|
locked: false
|
||||||
- name: INSTALLATION_EVENTS_WEBHOOK_URL
|
- name: INSTALLATION_EVENTS_WEBHOOK_URL
|
||||||
value:
|
value:
|
||||||
display_title: 'System events Webhook URL'
|
display_title: "System events Webhook URL"
|
||||||
description: 'The URL to which the system events like new accounts created will be sent'
|
description: "The URL to which the system events like new accounts created will be sent"
|
||||||
locked: false
|
locked: false
|
||||||
- name: WEBHOOK_TIMEOUT
|
- name: WEBHOOK_TIMEOUT
|
||||||
value: 5
|
value: 5
|
||||||
display_title: 'Webhook request timeout (seconds)'
|
display_title: "Webhook request timeout (seconds)"
|
||||||
description: 'Maximum time Chatwoot waits for a webhook response before failing the request'
|
description: "Maximum time Chatwoot waits for a webhook response before failing the request"
|
||||||
locked: false
|
locked: false
|
||||||
- name: DIRECT_UPLOADS_ENABLED
|
- name: DIRECT_UPLOADS_ENABLED
|
||||||
type: boolean
|
type: boolean
|
||||||
value: false
|
value: false
|
||||||
description: 'Enable direct uploads to cloud storage'
|
description: "Enable direct uploads to cloud storage"
|
||||||
locked: false
|
locked: false
|
||||||
- name: MAXIMUM_FILE_UPLOAD_SIZE
|
- name: MAXIMUM_FILE_UPLOAD_SIZE
|
||||||
value: 40
|
value: 40
|
||||||
display_title: 'Attachment size limit (MB)'
|
display_title: "Attachment size limit (MB)"
|
||||||
description: 'Maximum attachment size in MB allowed for uploads'
|
description: "Maximum attachment size in MB allowed for uploads"
|
||||||
locked: false
|
locked: false
|
||||||
# ------- End of Account Related Config ------- #
|
# ------- End of Account Related Config ------- #
|
||||||
|
|
||||||
# ------- Email Related Config ------- #
|
# ------- Email Related Config ------- #
|
||||||
- name: MAILER_INBOUND_EMAIL_DOMAIN
|
- name: MAILER_INBOUND_EMAIL_DOMAIN
|
||||||
display_title: 'Inbound Email Domain'
|
display_title: "Inbound Email Domain"
|
||||||
value:
|
value:
|
||||||
description: 'The domain name to be used for generating conversation continuity emails (reply+id@domain.com)'
|
description: "The domain name to be used for generating conversation continuity emails (reply+id@domain.com)"
|
||||||
locked: false
|
locked: false
|
||||||
- name: MAILER_SUPPORT_EMAIL
|
- name: MAILER_SUPPORT_EMAIL
|
||||||
display_title: 'Support Email'
|
display_title: "Support Email"
|
||||||
value:
|
value:
|
||||||
description: 'The support email address for your installation'
|
description: "The support email address for your installation"
|
||||||
locked: false
|
locked: false
|
||||||
# ------- End of Email Related Config ------- #
|
# ------- End of Email Related Config ------- #
|
||||||
|
|
||||||
# ------- Facebook Channel Related Config ------- #
|
# ------- Facebook Channel Related Config ------- #
|
||||||
- name: FB_APP_ID
|
- name: FB_APP_ID
|
||||||
display_title: 'Facebook App ID'
|
display_title: "Facebook App ID"
|
||||||
locked: false
|
locked: false
|
||||||
- name: FB_VERIFY_TOKEN
|
- name: FB_VERIFY_TOKEN
|
||||||
display_title: 'Facebook Verify Token'
|
display_title: "Facebook Verify Token"
|
||||||
description: 'The verify token used for Facebook Messenger Webhook'
|
description: "The verify token used for Facebook Messenger Webhook"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: FB_APP_SECRET
|
- name: FB_APP_SECRET
|
||||||
display_title: 'Facebook App Secret'
|
display_title: "Facebook App Secret"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: IG_VERIFY_TOKEN
|
- name: IG_VERIFY_TOKEN
|
||||||
display_title: 'Instagram Verify Token'
|
display_title: "Instagram Verify Token"
|
||||||
description: 'The verify token used for Instagram Webhook'
|
description: "The verify token used for Instagram Webhook"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: FACEBOOK_API_VERSION
|
- name: FACEBOOK_API_VERSION
|
||||||
display_title: 'Facebook API Version'
|
display_title: "Facebook API Version"
|
||||||
description: 'Configure this if you want to use a different Facebook API version. Make sure its prefixed with `v`'
|
description: "Configure this if you want to use a different Facebook API version. Make sure its prefixed with `v`"
|
||||||
value: 'v18.0'
|
value: "v18.0"
|
||||||
locked: false
|
locked: false
|
||||||
- name: ENABLE_MESSENGER_CHANNEL_HUMAN_AGENT
|
- name: ENABLE_MESSENGER_CHANNEL_HUMAN_AGENT
|
||||||
display_title: 'Enable human agent'
|
display_title: "Enable human agent"
|
||||||
value: false
|
value: false
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Enable human agent for messenger channel for longer message back period. Needs additional app approval: https://developers.facebook.com/docs/features-reference/human-agent/'
|
description: "Enable human agent for messenger channel for longer message back period. Needs additional app approval: https://developers.facebook.com/docs/features-reference/human-agent/"
|
||||||
type: boolean
|
type: boolean
|
||||||
# ------- End of Facebook Channel Related Config ------- #
|
# ------- End of Facebook Channel Related Config ------- #
|
||||||
|
|
||||||
# ------- WhatsApp Channel Related Config ------- #
|
# ------- WhatsApp Channel Related Config ------- #
|
||||||
- name: WHATSAPP_APP_ID
|
- name: WHATSAPP_APP_ID
|
||||||
display_title: 'WhatsApp App ID'
|
display_title: "WhatsApp App ID"
|
||||||
description: 'The Facebook App ID for WhatsApp Business API integration'
|
description: "The Facebook App ID for WhatsApp Business API integration"
|
||||||
locked: false
|
locked: false
|
||||||
- name: WHATSAPP_CONFIGURATION_ID
|
- name: WHATSAPP_CONFIGURATION_ID
|
||||||
display_title: 'WhatsApp Configuration ID'
|
display_title: "WhatsApp Configuration ID"
|
||||||
description: 'The Configuration ID for WhatsApp Embedded Signup flow (required for embedded signup)'
|
description: "The Configuration ID for WhatsApp Embedded Signup flow (required for embedded signup)"
|
||||||
locked: false
|
locked: false
|
||||||
- name: WHATSAPP_APP_SECRET
|
- name: WHATSAPP_APP_SECRET
|
||||||
display_title: 'WhatsApp App Secret'
|
display_title: "WhatsApp App Secret"
|
||||||
description: 'The App Secret for WhatsApp Embedded Signup flow (required for embedded signup)'
|
description: "The App Secret for WhatsApp Embedded Signup flow (required for embedded signup)"
|
||||||
locked: false
|
locked: false
|
||||||
- name: WHATSAPP_API_VERSION
|
- name: WHATSAPP_API_VERSION
|
||||||
display_title: 'WhatsApp API Version'
|
display_title: "WhatsApp API Version"
|
||||||
description: 'Configure this if you want to use a different WhatsApp API version. Make sure its prefixed with `v`'
|
description: "Configure this if you want to use a different WhatsApp API version. Make sure its prefixed with `v`"
|
||||||
value: 'v22.0'
|
value: "v22.0"
|
||||||
locked: false
|
locked: false
|
||||||
# ------- End of WhatsApp Channel Related Config ------- #
|
# ------- End of WhatsApp Channel Related Config ------- #
|
||||||
|
|
||||||
# MARK: Microsoft Email Channel Config
|
# MARK: Microsoft Email Channel Config
|
||||||
- name: AZURE_APP_ID
|
- name: AZURE_APP_ID
|
||||||
display_title: 'Azure App ID'
|
display_title: "Azure App ID"
|
||||||
description: 'The App ID that will be used to authenticate with customer Microsoft accounts. Find more details on setting up Azure here: https://chwt.app/dev/ms'
|
description: "The App ID that will be used to authenticate with customer Microsoft accounts. Find more details on setting up Azure here: https://chwt.app/dev/ms"
|
||||||
locked: false
|
locked: false
|
||||||
- name: AZURE_APP_SECRET
|
- name: AZURE_APP_SECRET
|
||||||
display_title: 'Azure App Secret'
|
display_title: "Azure App Secret"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
# End of Microsoft Email Channel Config
|
# End of Microsoft Email Channel Config
|
||||||
|
|
||||||
# MARK: Captain Config
|
# MARK: Captain Config
|
||||||
- name: CAPTAIN_OPEN_AI_API_KEY
|
- name: CAPTAIN_OPEN_AI_API_KEY
|
||||||
display_title: 'OpenAI API Key'
|
display_title: "OpenAI API Key"
|
||||||
description: 'The API key used to authenticate requests to OpenAI services for Captain AI.'
|
description: "The API key used to authenticate requests to OpenAI services for Captain AI."
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: CAPTAIN_OPEN_AI_MODEL
|
- name: CAPTAIN_OPEN_AI_MODEL
|
||||||
display_title: 'OpenAI Model'
|
display_title: "OpenAI Model"
|
||||||
description: 'The OpenAI model configured for use in Captain AI. Default: gpt-4o-mini'
|
description: "The OpenAI model configured for use in Captain AI. Default: gpt-4.1-mini"
|
||||||
locked: false
|
locked: false
|
||||||
- name: CAPTAIN_OPEN_AI_ENDPOINT
|
- name: CAPTAIN_OPEN_AI_ENDPOINT
|
||||||
display_title: 'OpenAI API Endpoint (optional)'
|
display_title: "OpenAI API Endpoint (optional)"
|
||||||
description: 'The OpenAI endpoint configured for use in Captain AI. Default: https://api.openai.com/'
|
description: "The OpenAI endpoint configured for use in Captain AI. Default: https://api.openai.com/"
|
||||||
locked: false
|
locked: false
|
||||||
- name: CAPTAIN_EMBEDDING_MODEL
|
- name: CAPTAIN_EMBEDDING_MODEL
|
||||||
display_title: 'Embedding Model (optional)'
|
display_title: "Embedding Model (optional)"
|
||||||
description: 'The embedding model configured for use in Captain AI. Default: text-embedding-3-small'
|
description: "The embedding model configured for use in Captain AI. Default: text-embedding-3-small"
|
||||||
locked: false
|
locked: false
|
||||||
- name: CAPTAIN_FIRECRAWL_API_KEY
|
- name: CAPTAIN_FIRECRAWL_API_KEY
|
||||||
display_title: 'FireCrawl API Key (optional)'
|
display_title: "FireCrawl API Key (optional)"
|
||||||
description: 'The FireCrawl API key for the Captain AI service'
|
description: "The FireCrawl API key for the Captain AI service"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: CAPTAIN_CLOUD_PLAN_LIMITS
|
- name: CAPTAIN_CLOUD_PLAN_LIMITS
|
||||||
display_title: 'Captain Cloud Plan Limits'
|
display_title: "Captain Cloud Plan Limits"
|
||||||
description: 'The limits for the Captain AI service for different plans'
|
description: "The limits for the Captain AI service for different plans"
|
||||||
value:
|
value:
|
||||||
type: code
|
type: code
|
||||||
# End of Captain Config
|
# End of Captain Config
|
||||||
@@ -204,65 +204,65 @@
|
|||||||
# ------- Chatwoot Internal Config for Cloud ----#
|
# ------- Chatwoot Internal Config for Cloud ----#
|
||||||
- name: CHATWOOT_INBOX_TOKEN
|
- name: CHATWOOT_INBOX_TOKEN
|
||||||
value:
|
value:
|
||||||
display_title: 'Inbox Token'
|
display_title: "Inbox Token"
|
||||||
description: 'The Chatwoot Inbox Token for Contact Support in Cloud'
|
description: "The Chatwoot Inbox Token for Contact Support in Cloud"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: CHATWOOT_INBOX_HMAC_KEY
|
- name: CHATWOOT_INBOX_HMAC_KEY
|
||||||
value:
|
value:
|
||||||
display_title: 'Inbox HMAC Key'
|
display_title: "Inbox HMAC Key"
|
||||||
description: 'The Chatwoot Inbox HMAC Key for Contact Support in Cloud'
|
description: "The Chatwoot Inbox HMAC Key for Contact Support in Cloud"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: CHATWOOT_CLOUD_PLANS
|
- name: CHATWOOT_CLOUD_PLANS
|
||||||
display_title: 'Cloud Plans'
|
display_title: "Cloud Plans"
|
||||||
value:
|
value:
|
||||||
description: 'Config to store stripe plans for cloud'
|
description: "Config to store stripe plans for cloud"
|
||||||
- name: CHATWOOT_CLOUD_PLAN_FEATURES
|
- name: CHATWOOT_CLOUD_PLAN_FEATURES
|
||||||
display_title: 'Planwise Features List'
|
display_title: "Planwise Features List"
|
||||||
value:
|
value:
|
||||||
description: 'Config to features and their associated plans'
|
description: "Config to features and their associated plans"
|
||||||
- name: DEPLOYMENT_ENV
|
- name: DEPLOYMENT_ENV
|
||||||
value: self-hosted
|
value: self-hosted
|
||||||
description: 'The deployment environment of the installation, to differentiate between Chatwoot cloud and self-hosted'
|
description: "The deployment environment of the installation, to differentiate between Chatwoot cloud and self-hosted"
|
||||||
- name: ANALYTICS_TOKEN
|
- name: ANALYTICS_TOKEN
|
||||||
value:
|
value:
|
||||||
display_title: 'Analytics Token'
|
display_title: "Analytics Token"
|
||||||
description: 'The PostHog analytics token for Chatwoot cloud'
|
description: "The PostHog analytics token for Chatwoot cloud"
|
||||||
type: secret
|
type: secret
|
||||||
- name: CLEARBIT_API_KEY
|
- name: CLEARBIT_API_KEY
|
||||||
value:
|
value:
|
||||||
display_title: 'Clearbit API Key'
|
display_title: "Clearbit API Key"
|
||||||
description: 'This API key is used for onboarding the users, to pre-fill account data.'
|
description: "This API key is used for onboarding the users, to pre-fill account data."
|
||||||
type: secret
|
type: secret
|
||||||
- name: DASHBOARD_SCRIPTS
|
- name: DASHBOARD_SCRIPTS
|
||||||
value:
|
value:
|
||||||
display_title: 'Dashboard Scripts'
|
display_title: "Dashboard Scripts"
|
||||||
description: 'Scripts are loaded as the last item in the <body> tag'
|
description: "Scripts are loaded as the last item in the <body> tag"
|
||||||
type: code
|
type: code
|
||||||
- name: BLOCKED_EMAIL_DOMAINS
|
- name: BLOCKED_EMAIL_DOMAINS
|
||||||
value:
|
value:
|
||||||
display_title: 'Blocked Email Domains'
|
display_title: "Blocked Email Domains"
|
||||||
description: 'Add a domain per line to block them from signing up, accepts Regex'
|
description: "Add a domain per line to block them from signing up, accepts Regex"
|
||||||
type: code
|
type: code
|
||||||
- name: SKIP_INCOMING_BCC_PROCESSING
|
- name: SKIP_INCOMING_BCC_PROCESSING
|
||||||
value:
|
value:
|
||||||
display_title: 'Skip BCC Processing For'
|
display_title: "Skip BCC Processing For"
|
||||||
description: 'Comma-separated list of account IDs that should be skipped from incoming BCC processing'
|
description: "Comma-separated list of account IDs that should be skipped from incoming BCC processing"
|
||||||
- name: INACTIVE_WHATSAPP_NUMBERS
|
- name: INACTIVE_WHATSAPP_NUMBERS
|
||||||
value: ''
|
value: ""
|
||||||
display_title: 'Inactive WhatsApp Numbers'
|
display_title: "Inactive WhatsApp Numbers"
|
||||||
description: 'Comma-separated list of WhatsApp numbers that should be rejected with a 422 error'
|
description: "Comma-separated list of WhatsApp numbers that should be rejected with a 422 error"
|
||||||
type: code
|
type: code
|
||||||
# ------- End of Chatwoot Internal Config for Cloud ----#
|
# ------- End of Chatwoot Internal Config for Cloud ----#
|
||||||
|
|
||||||
# ------- Chatwoot Internal Config for Self Hosted ----#
|
# ------- Chatwoot Internal Config for Self Hosted ----#
|
||||||
- name: INSTALLATION_PRICING_PLAN
|
- name: INSTALLATION_PRICING_PLAN
|
||||||
value: 'community'
|
value: "community"
|
||||||
description: 'The pricing plan for the installation, retrieved from the billing API'
|
description: "The pricing plan for the installation, retrieved from the billing API"
|
||||||
- name: INSTALLATION_PRICING_PLAN_QUANTITY
|
- name: INSTALLATION_PRICING_PLAN_QUANTITY
|
||||||
value: 0
|
value: 0
|
||||||
description: 'The number of licenses purchased for the installation, retrieved from the billing API'
|
description: "The number of licenses purchased for the installation, retrieved from the billing API"
|
||||||
- name: CHATWOOT_SUPPORT_WEBSITE_TOKEN
|
- name: CHATWOOT_SUPPORT_WEBSITE_TOKEN
|
||||||
value:
|
value:
|
||||||
description: 'The Chatwoot website token, used to identify the Chatwoot inbox and display the "Contact Support" option on the billing page'
|
description: 'The Chatwoot website token, used to identify the Chatwoot inbox and display the "Contact Support" option on the billing page'
|
||||||
@@ -272,7 +272,7 @@
|
|||||||
description: 'The Chatwoot script base URL, to display the "Contact Support" option on the billing page'
|
description: 'The Chatwoot script base URL, to display the "Contact Support" option on the billing page'
|
||||||
- name: CHATWOOT_SUPPORT_IDENTIFIER_HASH
|
- name: CHATWOOT_SUPPORT_IDENTIFIER_HASH
|
||||||
value:
|
value:
|
||||||
description: 'The Chatwoot identifier hash, to validate the contact in the live chat window.'
|
description: "The Chatwoot identifier hash, to validate the contact in the live chat window."
|
||||||
type: secret
|
type: secret
|
||||||
- name: ACCOUNT_SECURITY_NOTIFICATION_WEBHOOK_URL
|
- name: ACCOUNT_SECURITY_NOTIFICATION_WEBHOOK_URL
|
||||||
display_title: Webhook URL to post security analysis
|
display_title: Webhook URL to post security analysis
|
||||||
@@ -282,221 +282,221 @@
|
|||||||
|
|
||||||
# ------- Compliance Related Config ----#
|
# ------- Compliance Related Config ----#
|
||||||
- name: CHATWOOT_INSTANCE_ADMIN_EMAIL
|
- name: CHATWOOT_INSTANCE_ADMIN_EMAIL
|
||||||
display_title: 'Instance Admin Email'
|
display_title: "Instance Admin Email"
|
||||||
value:
|
value:
|
||||||
description: 'The email of the instance administrator to receive compliance-related notifications'
|
description: "The email of the instance administrator to receive compliance-related notifications"
|
||||||
locked: false
|
locked: false
|
||||||
# ------- End of Compliance Related Config ----#
|
# ------- End of Compliance Related Config ----#
|
||||||
|
|
||||||
## ------ Configs added for enterprise clients ------ ##
|
## ------ Configs added for enterprise clients ------ ##
|
||||||
- name: API_CHANNEL_NAME
|
- name: API_CHANNEL_NAME
|
||||||
value:
|
value:
|
||||||
description: 'Custom name for the API channel'
|
description: "Custom name for the API channel"
|
||||||
- name: API_CHANNEL_THUMBNAIL
|
- name: API_CHANNEL_THUMBNAIL
|
||||||
value:
|
value:
|
||||||
description: 'Custom thumbnail for the API channel'
|
description: "Custom thumbnail for the API channel"
|
||||||
- name: LOGOUT_REDIRECT_LINK
|
- name: LOGOUT_REDIRECT_LINK
|
||||||
value: /app/login
|
value: /app/login
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Redirect to a different link after logout'
|
description: "Redirect to a different link after logout"
|
||||||
- name: DISABLE_USER_PROFILE_UPDATE
|
- name: DISABLE_USER_PROFILE_UPDATE
|
||||||
value: false
|
value: false
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Disable rendering profile update page for users'
|
description: "Disable rendering profile update page for users"
|
||||||
## ------ End of Configs added for enterprise clients ------ ##
|
## ------ End of Configs added for enterprise clients ------ ##
|
||||||
|
|
||||||
## ------ Configs added for FCM v1 notifications ------ ##
|
## ------ Configs added for FCM v1 notifications ------ ##
|
||||||
- name: FIREBASE_PROJECT_ID
|
- name: FIREBASE_PROJECT_ID
|
||||||
display_title: 'Firebase Project ID'
|
display_title: "Firebase Project ID"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Firebase project ID'
|
description: "Firebase project ID"
|
||||||
- name: FIREBASE_CREDENTIALS
|
- name: FIREBASE_CREDENTIALS
|
||||||
display_title: 'Firebase Credentials'
|
display_title: "Firebase Credentials"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
description: 'Contents on your firebase credentials json file'
|
description: "Contents on your firebase credentials json file"
|
||||||
## ------ End of Configs added for FCM v1 notifications ------ ##
|
## ------ End of Configs added for FCM v1 notifications ------ ##
|
||||||
|
|
||||||
## ------ Configs added for Linear ------ ##
|
## ------ Configs added for Linear ------ ##
|
||||||
- name: LINEAR_CLIENT_ID
|
- name: LINEAR_CLIENT_ID
|
||||||
display_title: 'Linear Client ID'
|
display_title: "Linear Client ID"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Linear client ID'
|
description: "Linear client ID"
|
||||||
- name: LINEAR_CLIENT_SECRET
|
- name: LINEAR_CLIENT_SECRET
|
||||||
display_title: 'Linear Client Secret'
|
display_title: "Linear Client Secret"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Linear client secret'
|
description: "Linear client secret"
|
||||||
type: secret
|
type: secret
|
||||||
## ------ End of Configs added for Linear ------ ##
|
## ------ End of Configs added for Linear ------ ##
|
||||||
|
|
||||||
## ------ Configs added for Notion ------ ##
|
## ------ Configs added for Notion ------ ##
|
||||||
- name: NOTION_CLIENT_ID
|
- name: NOTION_CLIENT_ID
|
||||||
display_title: 'Notion Client ID'
|
display_title: "Notion Client ID"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Notion client ID'
|
description: "Notion client ID"
|
||||||
- name: NOTION_CLIENT_SECRET
|
- name: NOTION_CLIENT_SECRET
|
||||||
display_title: 'Notion Client Secret'
|
display_title: "Notion Client Secret"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Notion client secret'
|
description: "Notion client secret"
|
||||||
type: secret
|
type: secret
|
||||||
- name: NOTION_VERSION
|
- name: NOTION_VERSION
|
||||||
display_title: 'Notion Version'
|
display_title: "Notion Version"
|
||||||
value: '2022-06-28'
|
value: "2022-06-28"
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Notion version'
|
description: "Notion version"
|
||||||
## ------ End of Configs added for Notion ------ ##
|
## ------ End of Configs added for Notion ------ ##
|
||||||
|
|
||||||
## ------ Configs added for Slack ------ ##
|
## ------ Configs added for Slack ------ ##
|
||||||
- name: SLACK_CLIENT_ID
|
- name: SLACK_CLIENT_ID
|
||||||
display_title: 'Slack Client ID'
|
display_title: "Slack Client ID"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Slack client ID'
|
description: "Slack client ID"
|
||||||
- name: SLACK_CLIENT_SECRET
|
- name: SLACK_CLIENT_SECRET
|
||||||
display_title: 'Slack Client Secret'
|
display_title: "Slack Client Secret"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Slack client secret'
|
description: "Slack client secret"
|
||||||
type: secret
|
type: secret
|
||||||
## ------ End of Configs added for Slack ------ ##
|
## ------ End of Configs added for Slack ------ ##
|
||||||
|
|
||||||
# ------- Shopify Integration Config ------- #
|
# ------- Shopify Integration Config ------- #
|
||||||
- name: SHOPIFY_CLIENT_ID
|
- name: SHOPIFY_CLIENT_ID
|
||||||
display_title: 'Shopify Client ID'
|
display_title: "Shopify Client ID"
|
||||||
description: 'The Client ID (API Key) from your Shopify Partner account'
|
description: "The Client ID (API Key) from your Shopify Partner account"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: SHOPIFY_CLIENT_SECRET
|
- name: SHOPIFY_CLIENT_SECRET
|
||||||
display_title: 'Shopify Client Secret'
|
display_title: "Shopify Client Secret"
|
||||||
description: 'The Client Secret (API Secret Key) from your Shopify Partner account'
|
description: "The Client Secret (API Secret Key) from your Shopify Partner account"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
# ------- End of Shopify Related Config ------- #
|
# ------- End of Shopify Related Config ------- #
|
||||||
|
|
||||||
# ------- Instagram Channel Related Config ------- #
|
# ------- Instagram Channel Related Config ------- #
|
||||||
- name: INSTAGRAM_APP_ID
|
- name: INSTAGRAM_APP_ID
|
||||||
display_title: 'Instagram App ID'
|
display_title: "Instagram App ID"
|
||||||
locked: false
|
locked: false
|
||||||
- name: INSTAGRAM_APP_SECRET
|
- name: INSTAGRAM_APP_SECRET
|
||||||
display_title: 'Instagram App Secret'
|
display_title: "Instagram App Secret"
|
||||||
description: 'The App Secret used for Instagram authentication'
|
description: "The App Secret used for Instagram authentication"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: INSTAGRAM_VERIFY_TOKEN
|
- name: INSTAGRAM_VERIFY_TOKEN
|
||||||
display_title: 'Instagram Verify Token'
|
display_title: "Instagram Verify Token"
|
||||||
description: 'The verify token used for Instagram Webhook'
|
description: "The verify token used for Instagram Webhook"
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: ENABLE_INSTAGRAM_CHANNEL_HUMAN_AGENT
|
- name: ENABLE_INSTAGRAM_CHANNEL_HUMAN_AGENT
|
||||||
display_title: 'Enable human agent for instagram channel'
|
display_title: "Enable human agent for instagram channel"
|
||||||
value: false
|
value: false
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Enable human agent for instagram channel for longer message back period. Needs additional app approval: https://developers.facebook.com/docs/features-reference/human-agent/'
|
description: "Enable human agent for instagram channel for longer message back period. Needs additional app approval: https://developers.facebook.com/docs/features-reference/human-agent/"
|
||||||
type: boolean
|
type: boolean
|
||||||
- name: INSTAGRAM_API_VERSION
|
- name: INSTAGRAM_API_VERSION
|
||||||
display_title: 'Instagram API Version'
|
display_title: "Instagram API Version"
|
||||||
description: 'Configure this if you want to use a different Instagram API version. Make sure its prefixed with `v`'
|
description: "Configure this if you want to use a different Instagram API version. Make sure its prefixed with `v`"
|
||||||
value: 'v22.0'
|
value: "v22.0"
|
||||||
locked: true
|
locked: true
|
||||||
# ------- End of Instagram Channel Related Config ------- #
|
# ------- End of Instagram Channel Related Config ------- #
|
||||||
|
|
||||||
# ------- OG Image Related Config ------- #
|
# ------- OG Image Related Config ------- #
|
||||||
- name: OG_IMAGE_CDN_URL
|
- name: OG_IMAGE_CDN_URL
|
||||||
display_title: 'OG Image CDN URL'
|
display_title: "OG Image CDN URL"
|
||||||
description: 'The CDN URL for serving OG images'
|
description: "The CDN URL for serving OG images"
|
||||||
value: ''
|
value: ""
|
||||||
locked: false
|
locked: false
|
||||||
- name: OG_IMAGE_CLIENT_REF
|
- name: OG_IMAGE_CLIENT_REF
|
||||||
display_title: 'OG Image Client Reference'
|
display_title: "OG Image Client Reference"
|
||||||
description: 'Token used to block unauthorized access to OG images'
|
description: "Token used to block unauthorized access to OG images"
|
||||||
value: ''
|
value: ""
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
# ------- End of OG Image Related Config ------- #
|
# ------- End of OG Image Related Config ------- #
|
||||||
|
|
||||||
## ------ Configs added for Google OAuth ------ ##
|
## ------ Configs added for Google OAuth ------ ##
|
||||||
- name: GOOGLE_OAUTH_CLIENT_ID
|
- name: GOOGLE_OAUTH_CLIENT_ID
|
||||||
display_title: 'Google OAuth Client ID'
|
display_title: "Google OAuth Client ID"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Google OAuth Client ID for email authentication'
|
description: "Google OAuth Client ID for email authentication"
|
||||||
- name: GOOGLE_OAUTH_CLIENT_SECRET
|
- name: GOOGLE_OAUTH_CLIENT_SECRET
|
||||||
display_title: 'Google OAuth Client Secret'
|
display_title: "Google OAuth Client Secret"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Google OAuth Client Secret for email authentication'
|
description: "Google OAuth Client Secret for email authentication"
|
||||||
type: secret
|
type: secret
|
||||||
- name: GOOGLE_OAUTH_REDIRECT_URI
|
- name: GOOGLE_OAUTH_REDIRECT_URI
|
||||||
display_title: 'Google OAuth Redirect URI'
|
display_title: "Google OAuth Redirect URI"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'The redirect URI configured in your Google OAuth app'
|
description: "The redirect URI configured in your Google OAuth app"
|
||||||
- name: ENABLE_GOOGLE_OAUTH_LOGIN
|
- name: ENABLE_GOOGLE_OAUTH_LOGIN
|
||||||
display_title: 'Enable Google OAuth login'
|
display_title: "Enable Google OAuth login"
|
||||||
value: true
|
value: true
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Show Google OAuth as a login option when credentials are configured'
|
description: "Show Google OAuth as a login option when credentials are configured"
|
||||||
type: boolean
|
type: boolean
|
||||||
## ------ End of Configs added for Google OAuth ------ ##
|
## ------ End of Configs added for Google OAuth ------ ##
|
||||||
|
|
||||||
## ------ Configs added for SAML SSO ------ ##
|
## ------ Configs added for SAML SSO ------ ##
|
||||||
- name: ENABLE_SAML_SSO_LOGIN
|
- name: ENABLE_SAML_SSO_LOGIN
|
||||||
display_title: 'Enable SAML SSO login'
|
display_title: "Enable SAML SSO login"
|
||||||
value: true
|
value: true
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Show SAML SSO as a login option. Cannot be disabled if any users are using SAML authentication.'
|
description: "Show SAML SSO as a login option. Cannot be disabled if any users are using SAML authentication."
|
||||||
type: boolean
|
type: boolean
|
||||||
## ------ End of Configs added for SAML SSO ------ ##
|
## ------ End of Configs added for SAML SSO ------ ##
|
||||||
|
|
||||||
## ------ Configs added for Cloudflare ------ ##
|
## ------ Configs added for Cloudflare ------ ##
|
||||||
- name: CLOUDFLARE_API_KEY
|
- name: CLOUDFLARE_API_KEY
|
||||||
display_title: 'Cloudflare API Key'
|
display_title: "Cloudflare API Key"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'API key for Cloudflare account authentication'
|
description: "API key for Cloudflare account authentication"
|
||||||
type: secret
|
type: secret
|
||||||
- name: CLOUDFLARE_ZONE_ID
|
- name: CLOUDFLARE_ZONE_ID
|
||||||
display_title: 'Cloudflare Zone ID'
|
display_title: "Cloudflare Zone ID"
|
||||||
value:
|
value:
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Zone ID for the Cloudflare domain'
|
description: "Zone ID for the Cloudflare domain"
|
||||||
## ------ End of Configs added for Cloudflare ------ ##
|
## ------ End of Configs added for Cloudflare ------ ##
|
||||||
|
|
||||||
## ------ Customizations for Customers ------ ##
|
## ------ Customizations for Customers ------ ##
|
||||||
- name: WIDGET_TOKEN_EXPIRY
|
- name: WIDGET_TOKEN_EXPIRY
|
||||||
display_title: 'Widget Token Expiry'
|
display_title: "Widget Token Expiry"
|
||||||
value: 180
|
value: 180
|
||||||
locked: false
|
locked: false
|
||||||
description: 'Token expiry in days'
|
description: "Token expiry in days"
|
||||||
## ------ End of Customizations for Customers ------ ##
|
## ------ End of Customizations for Customers ------ ##
|
||||||
|
|
||||||
## ----- LLM Observability ---- ##
|
## ----- LLM Observability ---- ##
|
||||||
- name: OTEL_PROVIDER
|
- name: OTEL_PROVIDER
|
||||||
display_title: 'OpenTelemetry Provider'
|
display_title: "OpenTelemetry Provider"
|
||||||
description: 'LLM observability provider (langfuse, langsmith, etc.)'
|
description: "LLM observability provider (langfuse, langsmith, etc.)"
|
||||||
value: ''
|
value: ""
|
||||||
locked: false
|
locked: false
|
||||||
- name: LANGFUSE_PUBLIC_KEY
|
- name: LANGFUSE_PUBLIC_KEY
|
||||||
display_title: 'Langfuse Public Key'
|
display_title: "Langfuse Public Key"
|
||||||
description: 'Public key for Langfuse authentication'
|
description: "Public key for Langfuse authentication"
|
||||||
value: ''
|
value: ""
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: LANGFUSE_SECRET_KEY
|
- name: LANGFUSE_SECRET_KEY
|
||||||
display_title: 'Langfuse Secret Key'
|
display_title: "Langfuse Secret Key"
|
||||||
description: 'Secret key for Langfuse authentication'
|
description: "Secret key for Langfuse authentication"
|
||||||
value: ''
|
value: ""
|
||||||
locked: false
|
locked: false
|
||||||
type: secret
|
type: secret
|
||||||
- name: LANGFUSE_BASE_URL
|
- name: LANGFUSE_BASE_URL
|
||||||
display_title: 'Langfuse Base URL'
|
display_title: "Langfuse Base URL"
|
||||||
description: 'Langfuse endpoint (US: https://us.cloud.langfuse.com, EU: https://cloud.langfuse.com)'
|
description: "Langfuse endpoint (US: https://us.cloud.langfuse.com, EU: https://cloud.langfuse.com)"
|
||||||
value: 'https://us.cloud.langfuse.com'
|
value: "https://us.cloud.langfuse.com"
|
||||||
locked: false
|
locked: false
|
||||||
## ---- End of LLM Observability ---- ##
|
## ---- End of LLM Observability ---- ##
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
providers:
|
||||||
|
openai:
|
||||||
|
display_name: "OpenAI"
|
||||||
|
logo: openai.png
|
||||||
|
|
||||||
|
models:
|
||||||
|
gpt-4.1:
|
||||||
|
provider: openai
|
||||||
|
display_name: "GPT-4.1"
|
||||||
|
credit_multiplier: 0.5
|
||||||
|
gpt-4.1-mini:
|
||||||
|
provider: openai
|
||||||
|
display_name: "GPT-4.1 Mini"
|
||||||
|
credit_multiplier: 0.3
|
||||||
|
gpt-4.1-nano:
|
||||||
|
provider: openai
|
||||||
|
display_name: "GPT-4.1 Nano"
|
||||||
|
credit_multiplier: 0.1
|
||||||
|
gpt-5:
|
||||||
|
provider: openai
|
||||||
|
display_name: "GPT-5"
|
||||||
|
credit_multiplier: 1
|
||||||
|
gpt-5.1:
|
||||||
|
provider: openai
|
||||||
|
display_name: "GPT-5.1"
|
||||||
|
credit_multiplier: 1
|
||||||
|
gpt-5-mini:
|
||||||
|
provider: openai
|
||||||
|
display_name: "GPT-5 Mini"
|
||||||
|
credit_multiplier: 0.8
|
||||||
|
gpt-5-nano:
|
||||||
|
provider: openai
|
||||||
|
display_name: "GPT-5 Nano"
|
||||||
|
credit_multiplier: 0.3
|
||||||
|
gpt-5.2:
|
||||||
|
provider: openai
|
||||||
|
display_name: "GPT-5.2"
|
||||||
|
credit_multiplier: 1
|
||||||
|
|
||||||
|
features:
|
||||||
|
editor:
|
||||||
|
models:
|
||||||
|
[gpt-4.1-mini, gpt-4.1-nano, gpt-5-mini, gpt-4.1, gpt-5, gpt-5.1, gpt-5.2]
|
||||||
|
default: gpt-5-mini
|
||||||
|
assistant:
|
||||||
|
models: [gpt-5-mini, gpt-4.1, gpt-5, gpt-5.1, gpt-5.2]
|
||||||
|
default: gpt-5-mini
|
||||||
|
copilot:
|
||||||
|
models: [gpt-5-mini, gpt-4.1, gpt-5, gpt-5.1, gpt-5.2]
|
||||||
|
default: gpt-5-mini
|
||||||
|
label_suggestion:
|
||||||
|
models: [gpt-4.1-nano, gpt-4.1-mini, gpt-5-mini]
|
||||||
|
default: gpt-4.1-nano
|
||||||
|
# add deprecation_map later
|
||||||
@@ -52,6 +52,7 @@ Rails.application.routes.draw do
|
|||||||
post :bulk_create, on: :collection
|
post :bulk_create, on: :collection
|
||||||
end
|
end
|
||||||
namespace :captain do
|
namespace :captain do
|
||||||
|
resource :config, only: [:show], controller: 'config'
|
||||||
resources :assistants do
|
resources :assistants do
|
||||||
member do
|
member do
|
||||||
post :playground
|
post :playground
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#
|
#
|
||||||
# For all other LLM operations, use Llm::BaseAiService with RubyLLM instead.
|
# For all other LLM operations, use Llm::BaseAiService with RubyLLM instead.
|
||||||
class Llm::LegacyBaseOpenAiService
|
class Llm::LegacyBaseOpenAiService
|
||||||
DEFAULT_MODEL = 'gpt-4o-mini'
|
DEFAULT_MODEL = 'gpt-4.1-mini'
|
||||||
|
|
||||||
attr_reader :client, :model
|
attr_reader :client, :model
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
require 'ruby_llm'
|
require 'ruby_llm'
|
||||||
|
|
||||||
module Llm::Config
|
module Llm::Config
|
||||||
DEFAULT_MODEL = 'gpt-4o-mini'.freeze
|
DEFAULT_MODEL = 'gpt-4.1-mini'.freeze
|
||||||
class << self
|
class << self
|
||||||
def initialized?
|
def initialized?
|
||||||
@initialized ||= false
|
@initialized ||= false
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Llm::ConfigService
|
||||||
|
CONFIG_PATH = Rails.root.join('config/llm.yml').freeze
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def config
|
||||||
|
@config ||= load_config
|
||||||
|
end
|
||||||
|
|
||||||
|
def reload!
|
||||||
|
@config = load_config
|
||||||
|
end
|
||||||
|
|
||||||
|
%w[providers models features].each do |key|
|
||||||
|
define_method(key) do
|
||||||
|
config[key] || {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def models_for_feature(feature_key)
|
||||||
|
features.dig(feature_key.to_s, 'models') || []
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_model_for_feature(feature_key)
|
||||||
|
features.dig(feature_key.to_s, 'default')
|
||||||
|
end
|
||||||
|
|
||||||
|
def model_info(model_name)
|
||||||
|
models[model_name.to_s]
|
||||||
|
end
|
||||||
|
|
||||||
|
def provider_info(provider_name)
|
||||||
|
providers[provider_name.to_s]
|
||||||
|
end
|
||||||
|
|
||||||
|
def feature_keys
|
||||||
|
features.keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_model_for_feature?(feature_key, model_name)
|
||||||
|
allowed_models = models_for_feature(feature_key)
|
||||||
|
allowed_models.include?(model_name.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def feature_config(feature_key)
|
||||||
|
feature = features[feature_key.to_s]
|
||||||
|
return nil unless feature
|
||||||
|
|
||||||
|
{
|
||||||
|
models: feature['models'].filter_map do |model_name|
|
||||||
|
model = models[model_name]
|
||||||
|
next nil unless model
|
||||||
|
|
||||||
|
{
|
||||||
|
id: model_name,
|
||||||
|
display_name: model['display_name'],
|
||||||
|
provider: model['provider'],
|
||||||
|
credit_multiplier: model['credit_multiplier']
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
default: feature['default']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def all_features_config
|
||||||
|
features.keys.index_with do |feature_key|
|
||||||
|
feature_config(feature_key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_config
|
||||||
|
return {} unless File.exist?(CONFIG_PATH)
|
||||||
|
|
||||||
|
YAML.load_file(CONFIG_PATH) || {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Api::V1::Accounts::Captain::Config', type: :request do
|
||||||
|
let(:account) { create(:account) }
|
||||||
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
||||||
|
let(:agent) { create(:user, account: account, role: :agent) }
|
||||||
|
|
||||||
|
def json_response
|
||||||
|
JSON.parse(response.body, symbolize_names: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /api/v1/accounts/{account.id}/captain/config' do
|
||||||
|
context 'when it is an unauthenticated user' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/api/v1/accounts/#{account.id}/captain/config",
|
||||||
|
as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an agent' do
|
||||||
|
it 'returns available AI model options for each feature' do
|
||||||
|
get "/api/v1/accounts/#{account.id}/captain/config",
|
||||||
|
headers: agent.create_new_auth_token,
|
||||||
|
as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
|
||||||
|
%w[editor assistant copilot label_suggestion].each do |feature|
|
||||||
|
expect(json_response.dig(:features, feature.to_sym, :models)).to be_present
|
||||||
|
expect(json_response.dig(:features, feature.to_sym, :default)).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an admin' do
|
||||||
|
it 'returns providers, models, and features configuration' do
|
||||||
|
get "/api/v1/accounts/#{account.id}/captain/config",
|
||||||
|
headers: admin.create_new_auth_token,
|
||||||
|
as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(json_response).to have_key(:providers)
|
||||||
|
expect(json_response).to have_key(:models)
|
||||||
|
expect(json_response).to have_key(:features)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -9,7 +9,7 @@ RSpec.describe Messages::AudioTranscriptionService, type: :service do
|
|||||||
before do
|
before do
|
||||||
# Create required installation configs
|
# Create required installation configs
|
||||||
create(:installation_config, name: 'CAPTAIN_OPEN_AI_API_KEY', value: 'test-api-key')
|
create(:installation_config, name: 'CAPTAIN_OPEN_AI_API_KEY', value: 'test-api-key')
|
||||||
create(:installation_config, name: 'CAPTAIN_OPEN_AI_MODEL', value: 'gpt-4o-mini')
|
create(:installation_config, name: 'CAPTAIN_OPEN_AI_MODEL', value: 'gpt-4.1-mini')
|
||||||
|
|
||||||
# Mock usage limits for transcription to be available
|
# Mock usage limits for transcription to be available
|
||||||
allow(account).to receive(:usage_limits).and_return({ captain: { responses: { current_available: 100 } } })
|
allow(account).to receive(:usage_limits).and_return({ captain: { responses: { current_available: 100 } } })
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ RSpec.describe Integrations::LlmInstrumentation do
|
|||||||
account_id: 123,
|
account_id: 123,
|
||||||
conversation_id: 456,
|
conversation_id: 456,
|
||||||
feature_name: 'reply_suggestion',
|
feature_name: 'reply_suggestion',
|
||||||
model: 'gpt-4o-mini',
|
model: 'gpt-4.1-mini',
|
||||||
messages: [{ 'role' => 'user', 'content' => 'Hello' }],
|
messages: [{ 'role' => 'user', 'content' => 'Hello' }],
|
||||||
temperature: 0.7
|
temperature: 0.7
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ RSpec.describe Integrations::LlmInstrumentation do
|
|||||||
instance.instrument_llm_call(params) { 'result' }
|
instance.instrument_llm_call(params) { 'result' }
|
||||||
|
|
||||||
expect(mock_span).to have_received(:set_attribute).with('gen_ai.provider.name', 'openai')
|
expect(mock_span).to have_received(:set_attribute).with('gen_ai.provider.name', 'openai')
|
||||||
expect(mock_span).to have_received(:set_attribute).with('gen_ai.request.model', 'gpt-4o-mini')
|
expect(mock_span).to have_received(:set_attribute).with('gen_ai.request.model', 'gpt-4.1-mini')
|
||||||
expect(mock_span).to have_received(:set_attribute).with('gen_ai.request.temperature', 0.7)
|
expect(mock_span).to have_received(:set_attribute).with('gen_ai.request.temperature', 0.7)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -218,4 +218,59 @@ RSpec.describe Account do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'captain_preferences' do
|
||||||
|
let(:account) { create(:account) }
|
||||||
|
|
||||||
|
describe 'with no saved preferences' do
|
||||||
|
it 'returns defaults from llm.yml' do
|
||||||
|
prefs = account.captain_preferences
|
||||||
|
|
||||||
|
expect(prefs[:features].values).to all(be false)
|
||||||
|
|
||||||
|
Llm::ConfigService.feature_keys.each do |feature|
|
||||||
|
expect(prefs[:models][feature]).to eq(Llm::ConfigService.default_model_for_feature(feature))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with saved model preferences' do
|
||||||
|
it 'returns saved preferences merged with defaults' do
|
||||||
|
account.update!(captain_models: { 'editor' => 'gpt-4o', 'assistant' => 'gpt-5' })
|
||||||
|
|
||||||
|
prefs = account.captain_preferences
|
||||||
|
|
||||||
|
expect(prefs[:models]['editor']).to eq('gpt-4o')
|
||||||
|
expect(prefs[:models]['assistant']).to eq('gpt-5')
|
||||||
|
expect(prefs[:models]['copilot']).to eq(Llm::ConfigService.default_model_for_feature('copilot'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with saved feature preferences' do
|
||||||
|
it 'returns saved feature states' do
|
||||||
|
account.update!(captain_features: { 'editor' => true, 'assistant' => true })
|
||||||
|
|
||||||
|
prefs = account.captain_preferences
|
||||||
|
|
||||||
|
expect(prefs[:features]['editor']).to be true
|
||||||
|
expect(prefs[:features]['assistant']).to be true
|
||||||
|
expect(prefs[:features]['copilot']).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'validation' do
|
||||||
|
it 'rejects invalid model for a feature' do
|
||||||
|
account.captain_models = { 'label_suggestion' => 'gpt-5' }
|
||||||
|
|
||||||
|
expect(account).not_to be_valid
|
||||||
|
expect(account.errors[:captain_models].first).to include('not a valid model for label_suggestion')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'accepts valid model for a feature' do
|
||||||
|
account.captain_models = { 'editor' => 'gpt-4o', 'label_suggestion' => 'gpt-4.1-nano' }
|
||||||
|
|
||||||
|
expect(account).to be_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user