- Add support for using labels as an action event for automation
- Fix duplicated conversation_updated event dispatch for labels
Fixes https://github.com/chatwoot/chatwoot/issues/8539 and multiple
issues around duplication related to label change events.
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
The system determines a user’s active account by checking the
`active_at` field in the `account_users` table and selecting the most
recently active account:
```ruby
def active_account_user
account_users.order(active_at: :desc)&.first
end
```
This works fine when all accounts have a valid active_at timestamp.
**Problem**
When a user is added to a new account, the `active_at` value is NULL
(because the account has never been explicitly activated). Ordering by
active_at DESC produces inconsistent results across databases, since
handling of NULL values differs (sometimes treated as high, sometimes
low).
As a result:
- Mobile apps (critical impact): `/profile` returns the wrong account.
The UI keeps showing the old account even after switching, and
restarting does not fix it.
- Web app (accidentally works): Appears correct because the active
account is inferred from the browser URL, but the backend API is still
wrong.
**Root Cause**
- The ordering logic did not account for NULL `active_at`.
- New accounts without active_at sometimes get incorrectly prioritized
as the “active” account.
**Solution**
Explicitly ensure that accounts with NULL active_at are sorted after
accounts with real timestamps by using NULLS LAST:
```ruby
def active_account_user
account_users.order(Arel.sql('active_at DESC NULLS LAST, id DESC'))&.first
end
```
- Accounts with actual `active_at` values will always be prioritized.
- New accounts (with NULL active_at) will be placed at the bottom until
the user explicitly activates them.
- Adding id DESC as a secondary ordering ensures consistent tie-breaking
when multiple accounts have the same `active_at`.
…on (#11584)"
This reverts commit b5ebc47637.
# Pull Request Template
## Description
Please include a summary of the change and issue(s) fixed. Also, mention
relevant motivation, context, and any dependencies that this change
requires.
Fixes # (issue)
## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] 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.
## 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
Fixes https://github.com/chatwoot/chatwoot/issues/11569
## Problem
On platforms like WhatsApp and Facebook Messenger, customers cannot
reply to messages after 24 hours (or other channel-specific messaging
windows). Despite this limitation, the system continued sending CSAT
surveys to customers outside their messaging window, making it
impossible for them to respond.
## Solution
Added a check for `conversation.can_reply?` in the
`should_send_csat_survey?` method. This leverages the existing
`MessageWindowService` which already handles all channel-specific
messaging window logic.
This PR will prevent saving user preferences and online status when impersonating. Previously, these settings could be updated during impersonation, causing the user to see a different view or UI settings.
Fixes https://linear.app/chatwoot/issue/CW-4163/impersonation-improvements
This PR introduces support for optionally exposing more data during LLM
function calls. This will be useful as we expand Copilot’s capabilities.
Changes included:
- Add support for ArticleLlmFormatter
- Add missing specs for ContactLLMFormatter and ArticleLLMFormatter
- Add additional spec for ConversationLLMFormatter based on config
### Summary
- Converts conversation auto-resolution duration from days to minutes
for more
granular control
- Updates validation to allow values from 10 minutes (minimum) to 999
days (maximum)
- Implements smart messaging to show appropriate time units in activity
messages
### Changes
- Created migration to convert existing durations from days to minutes
(x1440)
- Updated conversation resolver to use minutes instead of days
- Added dynamic translation key selection based on duration value
- Updated related specs and documentation
- Added support for displaying durations in days, hours, or minutes
based on value
### Test plan
- Verify account validation accepts new minute-based ranges
- Confirm existing account settings are correctly migrated
- Test auto-resolution works properly with minute values
- Ensure proper time unit display in activity messages
---------
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
## Description
Add account delete option in the user account settings.
Fixes#1555
## Type of change
- [ ] New feature (non-breaking change which adds functionality)


## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own 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
---------
Co-authored-by: Sojan Jose <sojan@pepalo.com>
Co-authored-by: Sojan Jose <sojan.official@gmail.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
# Pull Request Template
## Description
This PR includes,
1. **Sort Accounts List** – Orders the accounts list alphabetically for
better organization.
2. **Add Missing Translations in Automation** – Includes missing
translations for actions, events, and conditions dropdown.
3. **Fix Missing Translation in Macros** – Adds missing translations in
the macros action select dropdown.
4. Translate "Automation System" Username – Ensures the "Automation
System" username is properly translated.
Fixes: https://linear.app/chatwoot/issue/CW-4198/issues-[converso]
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## 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
- [ ] 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
- [ ] Any dependent changes have been merged and published in downstream
modules
This PR implements the following features
- FAQs from conversations will be generated in account language
- Contact notes will be generated in account language
- Copilot chat will respond in user language, unless the agent asks the
question in a different language
## Changes
### Copilot Chat
- Update the prompt to include an instruction for the language, the bot
will reply in asked language, but will default to account language
- Update the `ChatService` class to include pass the language to
`SystemPromptsService`
### FAQ and Contact note generation
- Update contact note generator and conversation generator to include
account locale
- Pass the account locale to `SystemPromptsService`
<details><summary>Screenshots</summary>
#### FAQs being generated in system langauge

#### Copilot responding in system language

</details>
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Pranav <pranav@chatwoot.com>
This PR adds a cleaner re-authorization flow to Microsoft. This PR has
the following changes
1. Use `reauthorization_required` value for Microsoft Channel
2. Refactor `InboxReconnectionRequired` to reuse the `banner` component
3. Refactor `microsoft/Reauthorize.vue` to reuse
`InboxReconnectionRequired` component
4. Update `reauthorizable.rb` to update cache keys if the model has an
inbox
5. Update `microsoft/callbacks_controller.rb` to handle the
reauthorization case with a redirect to the inbox settings page if the
inbox already exists at the time of authorization.
## How Has This Been Tested?
- [x] Local Instance
- [ ] Staging Instance
- [x] Unit tests
## Pending Tasks
- [ ] ~Success Toast~ will do this in a follow-up PR with the screen
## Demo
The following video shows the whole process of creation and
re-authorization of the Microsoft channel
https://www.loom.com/share/e5cd9bd4439c4741b0dcfe66d67f88b3?sid=100f3642-43e4-46b3-8123-88a5dd9d8509
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
We observed some race condition errors in the conversation participation listener while trying to create a conversation participation assignment. This PR handles this error and also adds additional debug information for future.
fixes: https://linear.app/chatwoot/issue/CW-3296/activerecordrecordnotunique-pguniqueviolation-error-duplicate-key
## Changelog
- handles `ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvald` errors so that they won't pollute sentry
- Adds a debug statement to log the cases
- Add previous_changes into the dispatcher so that we know the exact attribute changes which trigger `assignee_changed, team_changed` events ( would be handy in future )
The reload method in our callback was refreshing the object and hence the saved_change_to_assignee_id? Method wasn't working in the following callbacks.
This impacted the listeners subscribing to the event `ASSIGNEE_CHANGE`, `TEAM_CHANGE` etc
* feat: set cache keys for 3 days only
* feat: invalidate should set the latest timestamp
* refactor: cache_keys concern
* remove invalidate_cache method
* refactor reset to set to new value instead of delete
* ensure only one event is dispatched
* feat: set expiry to 24 hours
* chore: make expiry 48 hours
* feat: include destroy event
* feat: set expiry to 72 days
* fix: typo
* test: cache update after `touch`
* test: update cache keys
* refactor: remove after_touch, it's already handled in commit
When looping the conversations in bulk action to assign them to new labels, the existing labels in other conversations were also getting duplicated across all conversations. This PR fixes the issue.
> In the previous implementation, new_labels is appended to the existing labels using the << operator. This operator modifies the original array instead of creating a new one, causing unwanted side effects. More specifically, new_labels is a reference to the original argument array of the method.
Co-authored-by: Sojan <sojan@pepalo.com>
Co-authored-by: Peter Salib <74493166+Peteraymansalib@users.noreply.github.com>
- Add JsonSchemaValidator, which takes a declarative schema and validates it for a given property.
- Add specs for JsonSchemaValidator
- Enable the validator for template_params
* feat: update seed script to include prioritt
* feat: add sort_handler for conversations
* test: sort on priority order
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
* fix: Invalidate cache if any of the related objects change
* Add specs:
* Update context
---------
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
* feat: ignore bots in avg_first_response_time
* feat: ignore bots in avg_first_response count
* feat: add bot handoff event
* feat: add handoff event listener and reporting event
* fix: ignore agent bot in first response
* refactor: calculate first_response with last handoff
* refactor: method defn order
* test: new reporting events
* feat: Revert "feat: ignore bots in avg_first_response count"
This reverts commit de1977c219a2e7a9180dd02272244fe3b3f7ce89.
* feat: Revert "feat: ignore bots in avg_first_response_time"
This reverts commit bb9171945d5e3b2f6015f4f96dd1b76b3efb6987.
* fix: business hour calculation for first_reply
* fix: event_start_time for first_response
* feat: add migration to recompute first_responses
* refactor: separate mute helpers for conversation
* refactor: rename migration
* refactor: migration script
* fix: migration typo
* fix: typo in query
* feat: update schema.rb
* Revert "feat: update schema.rb"
This reverts commit 353ef355f2d956dd219907bb66982dc90ca5d896.
* feat: update schema
* refactor: update events as a batch job
* fix: ignore the event if value is negative
* feat: don't create a new hand-off if it's already present
* refactor: break the action into smaller chunks
* refactor: update reporting listener spec
Handle the case to ensure extra bot handoffs are not created for a give conversation
* fix: import error
---------
Co-authored-by: Vishnu Narayanan <vishnu@chatwoot.com>