message_post now returns immediately after collecting attachment data.
The agent HTTP call and reply posting happen in a daemon thread, so
Odoo commits the user's message and the browser confirms receipt right
away -- instead of waiting 10+ seconds for Ollama to respond.
File clarification (no LLM) still posts inline since it's instant.
The background thread opens its own DB cursor to post the bot reply.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All bot messages now built as plain text and converted via _text_to_html()
which escapes content and converts newlines to <br>. This avoids raw HTML
tags appearing literally in Odoo 18 Discuss.
- _describe_zip: returns plain str (no Markup/HTML)
- _post_file_clarification: builds plain text, posts via _text_to_html()
- _find_pending_attachments: strip HTML before phrase matching
- _text_to_html: new helper shared by clarification and agent replies
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- master_agent: thread raw user message into extra_context and peer_data so
expenses_agent can check it directly without relying on LLM intent_summary
- master_agent: when receipts are in extra_context always route to expenses_agent,
so replies like 'skip duplicates' still trigger expense processing
- expenses_agent: _plan() checks peer_data raw_message alongside task so
skip/keep keywords are detected even when master rewrites the intent
- ab_ai_mail: wrap clarification message HTML in Markup() so Odoo does not
re-escape the tags; use <br> instead of <br/>
- ab_ai_mail: convert agent plain-text replies newlines to <br> for proper
line-break rendering in Discuss
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- expenses_agent: extract transaction time (HH:MM) from OCR receipt text
- expenses_agent: _find_semantic_duplicate uses time to rule out false positives (>30 min apart = different receipts)
- expenses_agent: pause when duplicates found, set mode=awaiting_dup_approval, ask user before creating sheet
- expenses_agent: _report formats approval message listing each dup pair with vendor/amount/date/times/filenames
- ab_ai_mail: _find_pending_attachments recognises dup-approval bot message so ZIP re-attaches on user reply
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ollama_backend: add format='json' for 'master' and receipt_parser
callers so llama3.1:8b returns valid JSON instead of plain English
- ab_ai_mail: add debug logging to trace attachment_ids from Discuss;
handle file-only messages and clarification look-back flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Discuss bot now reads ir.attachment from incoming messages; file-only
messages no longer silently dropped
- ZIP files are described (contents listed) and bot asks clarifying
question before acting; user's follow-up reply looks back for pending
attachments so files don't need to be re-uploaded
- receipt_parser: extracts text from ZIP (recursive), JPG/PNG/etc (OCR),
PDF (pdfplumber), HTML, TXT
- expenses_agent: full rewrite fixing broken method signatures; adds
create_expense_sheet / create_expense / attach_receipt flow driven by
LLM receipt parsing (Ollama, HIPAA-locked)
- master_agent: extra_context threads receipts + user_id into directives
- FastAPI /upload multipart endpoint; registered in main.py
- Odoo /ai/upload controller proxies files to agent service
- ab_ai_bot: dispatch_message_with_files() for multipart uploads
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create res.partner for the AI bot (appears in DM contacts)
- Override mail.channel.message_post to intercept direct messages
to the bot partner and forward them to the agent service
- Post the agent reply back into the Discuss channel as the bot
- Add discuss to depends; load res_partner_bot.xml data
Users can now open Discuss -> New Message -> search 'ActiveBlue AI'
to start a conversation with the agent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>