The bot DM flow silently failed because ab_ai_mail.message_post override bails when no active ab.ai.bot row exists, and the agent service loaded 0 agents from an empty ab.ai.agent.registry. Both tables stayed empty because nothing populated them. The post_init/post_migrate hook now seeds: - One active ab.ai.bot pointing at http://activeblue-agent:8001 - The 8 specialist agents (finance, accounting, crm, sales, project, elearning, expenses, hr) plus master, all on the ollama backend Idempotent: skips rows that already exist.
95 lines
3.5 KiB
Python
95 lines
3.5 KiB
Python
from . import models, controllers
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
DEFAULT_AGENTS = [
|
|
('master', 'Routing / orchestration'),
|
|
('finance', 'Finance reporting and analysis'),
|
|
('accounting', 'Accounting, journals, reconciliation'),
|
|
('crm', 'CRM, leads, opportunities'),
|
|
('sales', 'Sales orders, quotations, customers'),
|
|
('project', 'Project management and tasks'),
|
|
('elearning', 'eLearning courses and content'),
|
|
('expenses', 'Expense reports and approvals'),
|
|
('hr', 'Human Resources, employees, time off'),
|
|
]
|
|
|
|
|
|
def _ensure_default_bot_and_registry(env):
|
|
"""Seed an active ab.ai.bot row and the default agent registry entries."""
|
|
Bot = env['ab.ai.bot']
|
|
if not Bot.search([], limit=1):
|
|
Bot.create({
|
|
'display_name': 'ActiveBlue AI',
|
|
'agent_service_url': 'http://activeblue-agent:8001',
|
|
'privacy_mode': 'local',
|
|
'active': True,
|
|
})
|
|
_logger.info('Seeded default ab.ai.bot row')
|
|
|
|
Registry = env['ab.ai.agent.registry']
|
|
for name, domain in DEFAULT_AGENTS:
|
|
if not Registry.search([('agent_name', '=', name)], limit=1):
|
|
Registry.create({
|
|
'agent_name': name,
|
|
'domain': domain,
|
|
'active': True,
|
|
'backend': 'ollama',
|
|
})
|
|
_logger.info('Ensured %d default agent registry entries', len(DEFAULT_AGENTS))
|
|
|
|
|
|
def _ensure_ai_bot_user(env):
|
|
"""Create the ActiveBlue AI internal user so it appears in Discuss DM search.
|
|
|
|
Skips invitation email (no_reset_password) and marks the user as already
|
|
logged-in (res_users_log row) so it shows as Confirmed instead of Pending.
|
|
Also ensures the external ID exists so `env.ref('activeblue_ai.partner_activeblue_ai')`
|
|
resolves in the discuss.channel message override.
|
|
"""
|
|
User = env['res.users'].with_context(no_reset_password=True)
|
|
user = User.search([('login', 'in', ('activeblue_ai_bot', 'activeblue_ai_bot@local'))], limit=1)
|
|
if not user:
|
|
user = User.create({
|
|
'name': 'ActiveBlue AI',
|
|
'login': 'activeblue_ai_bot',
|
|
'groups_id': [(6, 0, [env.ref('base.group_user').id])],
|
|
'share': False,
|
|
'active': True,
|
|
})
|
|
_logger.info('Created ActiveBlue AI bot user id=%d', user.id)
|
|
|
|
# Ensure external ID -> partner mapping (needed by ab_ai_mail.py override)
|
|
imd = env['ir.model.data']
|
|
existing = imd.search([
|
|
('module', '=', 'activeblue_ai'),
|
|
('name', '=', 'partner_activeblue_ai'),
|
|
], limit=1)
|
|
if existing:
|
|
existing.write({'model': 'res.partner', 'res_id': user.partner_id.id})
|
|
else:
|
|
imd.create({
|
|
'module': 'activeblue_ai',
|
|
'name': 'partner_activeblue_ai',
|
|
'model': 'res.partner',
|
|
'res_id': user.partner_id.id,
|
|
'noupdate': True,
|
|
})
|
|
|
|
# Clear "Pending Invitations" state by writing a res_users_log row.
|
|
# In Odoo 18 the user state is computed from the existence of a log entry.
|
|
env.cr.execute(
|
|
"SELECT 1 FROM res_users_log WHERE create_uid = %s LIMIT 1",
|
|
(user.id,),
|
|
)
|
|
if not env.cr.fetchone():
|
|
env.cr.execute(
|
|
"INSERT INTO res_users_log (create_uid, create_date, write_uid, write_date) "
|
|
"VALUES (%s, NOW(), %s, NOW())",
|
|
(user.id, user.id),
|
|
)
|
|
_logger.info('Marked ActiveBlue AI bot user id=%d as confirmed', user.id)
|
|
|
|
_ensure_default_bot_and_registry(env)
|