Fixes https://linear.app/chatwoot/issue/CW-7559/inbox-limit-abuse
## Why
The regular inbox API checked limits in the controller, but WhatsApp
embedded signup creates inboxes through a service using `Inbox.create!`.
That let Enterprise account inbox limits be skipped for embedded signup.
## What this change does
- Adds an Inbox create-time validation hook in OSS and implements the
limit check in the Enterprise Inbox module.
- Removes the duplicate controller/helper limit check so the model is
the single enforcement point.
- Preserves the existing `402 Payment Required` API response for account
inbox limit failures.
- Keeps updates to existing inboxes allowed when an account is already
at its inbox limit.
## Validation
- `bundle exec rspec
spec/controllers/api/v1/accounts/inboxes_controller_spec.rb
spec/enterprise/models/inbox_spec.rb`
# Pull Request Template
## Description
Fixes:
https://linear.app/chatwoot/issue/CW-7167/label-suggestions-bad-ux
## Type of change
Please delete options that are not relevant.
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
# Pull Request Template
## Description
- Validates openai key while configuring hooks
- added backfill logic
Fixes # (issue)
## Type of change
- [x] New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
locally
<img width="1710" height="1234" alt="CleanShot 2026-04-15 at 16 15
02@2x"
src="https://github.com/user-attachments/assets/3d319fe0-19f9-4fd0-9308-74987daac2e1"
/>
<img width="2884" height="1136" alt="CleanShot 2026-05-11 at 19 22
53@2x"
src="https://github.com/user-attachments/assets/5eae8650-985b-4c4a-af42-35f7175ff52d"
/>
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Vishnu Narayanan <iamwishnu@gmail.com>
When a new account finishes onboarding we want to land them on a
dashboard with a working web widget already configured, branded, named,
and assigned to them, instead of an empty inbox list. This PR adds the
services that produce that widget. **No user-visible change yet:** the
services are dormant until the trigger and background job are wired up
in the follow-up PR.
## Context
Milestone 1 added `Account::BrandingEnrichmentJob`, which calls
context.dev during signup and stores brand data on
`account.custom_attributes['brand_info']`, plus the new onboarding form
that captures `domain`, `name`, `industry`, etc. Milestone 2 starts
using that data, and the first thing we want is a web widget
materialized automatically. Splitting the service layer from the
orchestration plumbing (Redis key, `onboarding_step` extension,
controller wiring, ActionCable) keeps this diff focused and lets the
LLM/widget logic merge independently.
## How to test
Run against an existing account that already has `brand_info` populated.
```ruby
account = Account.find(<account_id>)
user = account.administrators.first
inbox = WidgetCreationService.new(account, user).perform
inbox.channel.widget_color # color from brand_info, or '#1f93ff'
inbox.channel.welcome_title # brand_info[:title], or account.name
inbox.channel.welcome_tagline # LLM tagline (Enterprise + system key set),
# else brand_info[:slogan]/[:description]/nil
inbox.inbox_members.pluck(:user_id)
```
Toggle `InstallationConfig['CAPTAIN_OPEN_AI_API_KEY']` to flip between
LLM and brand-text tagline paths. To verify failure isolation, raise
inside `Captain::Llm::WidgetTaglineService#perform` and confirm widget
creation still succeeds with the fallback tagline.
Removes sentry flooding of unnecessary rubyllm logs of wrong API key.
Logs only system api key error since it would be P0.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Pull Request Template
## Description
Add account setting and store_accessor for
`captain_force_legacy_auto_resolve`.
Enterprise job now skips LLM evaluation when this flag is true and falls
back to legacy time-based resolution. Add spec to cover the fallback.
## Type of change
We recently rolled out Captain deciding if a conversation is resolved or
not. While it is an improvement for majority of customers, some still
prefer the old way of auto-resolving based on inactivity. This PR adds a
check.
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
legacy_auto_resolve = true
<img width="1282" height="848" alt="CleanShot 2026-03-13 at 19 55 55@2x"
src="https://github.com/user-attachments/assets/dfdcc5d5-6d21-462b-87a6-a5e1b1290a8b"
/>
legacy_auto_resolve = false
<img width="1268" height="864" alt="CleanShot 2026-03-13 at 20 00 50@2x"
src="https://github.com/user-attachments/assets/f4719ec6-922a-4c3b-bc45-7b29eaced565"
/>
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
# Pull Request Template
## Description
Add an api_key override so internal conversation completions prefers
using the system API key and do not consume customer OpenAI credits.
## Type of change
Please delete options that are not relevant.
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
specs and locally
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
# Pull Request Template
## Description
captain decides if conversation should be resolved or open
Fixes
https://linear.app/chatwoot/issue/AI-91/make-captain-resolution-time-configurable
Update: Added 2 entries in reporting events:
`conversation_captain_handoff` and `conversation_captain_resolved`
## Type of change
Please delete options that are not relevant.
- [x] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
LLM call decides that conversation is resolved, drops a private note
<img width="1228" height="438" alt="image"
src="https://github.com/user-attachments/assets/fb2cf1e9-4b2b-458b-a1e2-45c53d6a0158"
/>
LLM call decides conversation is still open as query was not resolved
<img width="1215" height="573" alt="image"
src="https://github.com/user-attachments/assets/2d1d5322-f567-487e-954e-11ab0798d11c"
/>
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Sojan Jose <sojan@pepalo.com>
Add a temporary `captain_disable_auto_resolve` boolean setting on
accounts to prevent Captain from resolving conversations. Guards both
the scheduled resolution job and the assistant's resolve tool.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
# Pull Request Template
## Description
Adds a new built-in tool that allows Captain scenarios to resolve
conversations programmatically. This enables automated workflows like
the misdirected contact deflector to close conversations after handling
them, while still allowing human review via label filtering.
## Type of change
Please delete options that are not relevant.
- [x] New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
tested by mentioning it to be used in captain v2 scenario
<img width="1180" height="828" alt="image"
src="https://github.com/user-attachments/assets/e70baf96-0c70-407e-af2c-328500ac5434"
/>
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tanmay Deep Sharma <32020192+tds-1@users.noreply.github.com>
- We previously had this spec inside the enterprise folder which wouldn't be picked up by our build process, so moving to the correct folder instead.
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>