-
-
Notifications
You must be signed in to change notification settings - Fork 50
[18.0] [MIG] ai_automation -> ai_server_action #81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 18.0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| ============= | ||
| Ai Automation | ||
| ============= | ||
|
|
||
| .. | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
| !! This file is generated by oca-gen-addon-readme !! | ||
| !! changes will be overwritten. !! | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
| !! source digest: sha256:9db8aa67499c9f7efc73ff5f14809ca6d3df0f99e4eb35df8fff7f4cd3de79d1 | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
|
|
||
| .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png | ||
| :target: https://odoo-community.org/page/development-status | ||
| :alt: Beta | ||
| .. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png | ||
| :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
| :alt: License: AGPL-3 | ||
| .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fai-lightgray.png?logo=github | ||
| :target: https://github.com/OCA/ai/tree/18.0/ai_server_action | ||
| :alt: OCA/ai | ||
| .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png | ||
| :target: https://translation.odoo-community.org/projects/ai-18-0/ai-18-0-ai_server_action | ||
| :alt: Translate me on Weblate | ||
| .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png | ||
| :target: https://runboat.odoo-community.org/builds?repo=OCA/ai&target_branch=18.0 | ||
| :alt: Try me on Runboat | ||
|
|
||
| |badge1| |badge2| |badge3| |badge4| |badge5| | ||
|
|
||
| This module integrates AI connections with Odoo server actions, allowing | ||
| you to define AI-powered automations. By default it provides Ollama | ||
| support, but it can be extended with additional providers by adding new | ||
| ``kind`` options to ``ai.connection``. | ||
|
|
||
| **Table of contents** | ||
|
|
||
| .. contents:: | ||
| :local: | ||
|
|
||
| Usage | ||
| ===== | ||
|
|
||
| This module adds a new server action type: **AI OCA Action**. | ||
|
|
||
| To use it: | ||
|
|
||
| 1. Go to ``Settings > Technical > Actions > Server Actions`` | ||
| 2. Create a new action and select **AI OCA Action** as the state | ||
| 3. Select an AI Connection (Ollama) | ||
| 4. Define the prompt — supports dynamic placeholders using Qweb syntax | ||
| (e.g. ``{{ object.name }}``) | ||
| 5. Optionally select tools the AI can call during execution | ||
| 6. Define what to do with the result: | ||
|
|
||
| - **Post Message**: posts the AI response as a chatter message on the | ||
| record | ||
| - **Update Record**: writes the AI response to a specific field | ||
|
|
||
| To extend with a new AI provider, inherit ``ai.connection`` and add a | ||
| new selection value to ``kind``, then implement the corresponding | ||
| ``_run_{kind}`` method. | ||
|
|
||
| Bug Tracker | ||
| =========== | ||
|
|
||
| Bugs are tracked on `GitHub Issues <https://github.com/OCA/ai/issues>`_. | ||
| In case of trouble, please check there if your issue has already been reported. | ||
| If you spotted it first, help us to smash it by providing a detailed and welcomed | ||
| `feedback <https://github.com/OCA/ai/issues/new?body=module:%20ai_server_action%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
|
||
| Do not contact contributors directly about support or help with technical issues. | ||
|
|
||
| Credits | ||
| ======= | ||
|
|
||
| Authors | ||
| ------- | ||
|
|
||
| * Dixmit | ||
|
|
||
| Contributors | ||
| ------------ | ||
|
|
||
| - `Dixmit <https://www.dixmit.com>`__ | ||
|
|
||
| - Enric Tobella | ||
|
|
||
| - [SDi] (https://sdi.es) | ||
|
|
||
| Maintainers | ||
| ----------- | ||
|
|
||
| This module is maintained by the OCA. | ||
|
|
||
| .. image:: https://odoo-community.org/logo.png | ||
| :alt: Odoo Community Association | ||
| :target: https://odoo-community.org | ||
|
|
||
| OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
| mission is to support the collaborative development of Odoo features and | ||
| promote its widespread use. | ||
|
|
||
| This module is part of the `OCA/ai <https://github.com/OCA/ai/tree/18.0/ai_server_action>`_ project on GitHub. | ||
|
|
||
| You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| from . import models |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Copyright 2026 Dixmit | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
|
||
| { | ||
| "name": "Ai Automation", | ||
| "summary": "Integrate `ai_tools` with server actions to automate tasks using AI.", | ||
| "version": "18.0.1.0.0", | ||
| "license": "AGPL-3", | ||
| "author": "Dixmit,Odoo Community Association (OCA)", | ||
| "website": "https://github.com/OCA/ai", | ||
| "depends": ["ai_connection", "ai_tool"], | ||
| "data": [ | ||
| "views/ir_actions_server.xml", | ||
| ], | ||
| "demo": [], | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| from . import ir_actions_server |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| # Copyright 2026 Dixmit | ||
| # Copyright 2026 SDi - Ángel Moya <amoya@sdi.es> | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
|
||
| from odoo import api, fields, models | ||
| from odoo.tools.mail import html2plaintext, html_sanitize, plaintext2html | ||
|
|
||
| try: | ||
| import markdown | ||
| except ImportError: | ||
| markdown = None | ||
|
|
||
|
|
||
| class IrActionsServer(models.Model): | ||
| _inherit = "ir.actions.server" | ||
|
|
||
| state = fields.Selection( | ||
| selection_add=[("ai_oca", "Run AI Prompt")], | ||
| ondelete={"ai_oca": "cascade"}, | ||
| ) | ||
| ai_connection_id = fields.Many2one( | ||
| "ai.connection", | ||
| string="AI Connection", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know I introduced it, however this string has no sense. Can you remove it 🙏 ? |
||
| groups="base.group_system", | ||
| ) | ||
| ai_tool_ids = fields.Many2many( | ||
| "ai.tool", | ||
| string="AI Tools", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||
| groups="base.group_system", | ||
| ) | ||
| ai_prompt = fields.Html( | ||
| string="AI Prompt", | ||
|
Comment on lines
+24
to
+32
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||
| sanitize=False, | ||
| ) | ||
| mailing_model_real = fields.Char( | ||
| compute="_compute_mailing_model_real", | ||
| ) | ||
| ai_output_mode = fields.Selection( | ||
| [ | ||
| ("post_message", "Post Message"), | ||
| ("update_record", "Update Record"), | ||
| ("store_variable", "Store in Context Variable"), | ||
| ("none", "None"), | ||
| ], | ||
| string="Output Mode", | ||
| default="none", | ||
| groups="base.group_system", | ||
| ) | ||
| ai_update_record_field_id = fields.Many2one( | ||
| "ir.model.fields", | ||
| string="Update Record Field", | ||
| domain=( | ||
| "[('model_id', '=', model_id), " | ||
| "('ttype', 'in', ['char', 'text', 'html'])]" | ||
| ), | ||
| groups="base.group_system", | ||
| ) | ||
| ai_context_variable = fields.Char( | ||
| string="Context Variable", | ||
| groups="base.group_system", | ||
| help=( | ||
| "Name of the variable where the response will be stored " | ||
| "in the evaluation context." | ||
| ), | ||
| ) | ||
|
|
||
| @api.depends("model_id") | ||
| def _compute_mailing_model_real(self): | ||
| for record in self: | ||
| record.mailing_model_real = ( | ||
| record.model_id.model if record.model_id else False | ||
| ) | ||
|
|
||
| def _run_action_ai_oca(self, eval_context=None): | ||
| self.ensure_one() | ||
| eval_context = eval_context or {} | ||
| record = eval_context.get("record") | ||
| prompt = self._get_ai_prompt(record) | ||
| result = self.ai_connection_id._run( | ||
| prompt, | ||
| tools=self.ai_tool_ids, | ||
| record=record, | ||
| )[0] | ||
| self._post_run_action_ai_run(result, eval_context, record) | ||
|
|
||
| def _get_ai_prompt(self, record): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maintain the old function name please |
||
| self.ensure_one() | ||
| prompt = self.ai_prompt or "" | ||
| if record: | ||
| prompt = str( | ||
| self.env["mail.render.mixin"]._render_template_qweb( | ||
| prompt, record._name, record.ids | ||
| )[record.id] | ||
| ) | ||
| return html2plaintext(prompt) | ||
|
|
||
| def _post_run_action_ai_run(self, result, eval_context, record): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you move the function? it is harder to see the changes. |
||
| self.ensure_one() | ||
| if self.ai_output_mode == "post_message" and record and record.exists(): | ||
| body = self._prepare_message_body(result) | ||
| record.message_post(body=body) | ||
| elif self.ai_output_mode == "update_record": | ||
| if record and self.ai_update_record_field_id: | ||
| if markdown and self.ai_update_record_field_id.ttype == "html": | ||
| value = self._prepare_message_body(result) | ||
| else: | ||
| value = result | ||
| record.write({self.ai_update_record_field_id.name: value}) | ||
| elif self.ai_output_mode == "store_variable": | ||
| if self.ai_context_variable: | ||
| eval_context[self.ai_context_variable] = result | ||
|
|
||
| def _prepare_message_body(self, result): | ||
| if markdown: | ||
| return html_sanitize(markdown.markdown(result)) | ||
| return plaintext2html(result) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| [build-system] | ||
| requires = ["whool"] | ||
| build-backend = "whool.buildapi" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| - [Dixmit](https://www.dixmit.com) | ||
| - Enric Tobella | ||
| - [SDi] (https://sdi.es) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| This module integrates AI connections with Odoo server actions, allowing you to | ||
| define AI-powered automations. By default it provides Ollama support, but it can | ||
| be extended with additional providers by adding new `kind` options to `ai.connection`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| This module adds a new server action type: **AI OCA Action**. | ||
|
|
||
| To use it: | ||
| 1. Go to `Settings > Technical > Actions > Server Actions` | ||
| 2. Create a new action and select **AI OCA Action** as the state | ||
| 3. Select an AI Connection (Ollama) | ||
| 4. Define the prompt — supports dynamic placeholders using Qweb syntax (e.g. `{{ object.name }}`) | ||
| 5. Optionally select tools the AI can call during execution | ||
| 6. Define what to do with the result: | ||
| - **Post Message**: posts the AI response as a chatter message on the record | ||
| - **Update Record**: writes the AI response to a specific field | ||
|
|
||
| To extend with a new AI provider, inherit `ai.connection` and add a new selection | ||
| value to `kind`, then implement the corresponding `_run_{kind}` method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more than AI Tools, maybe AI Connection, isn't it?