From 3516abf2f8fececd8cdfcf9ddc55667ea48dada9 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Mon, 20 Apr 2026 09:17:39 +0200 Subject: [PATCH 1/5] [ADD] ai_automation --- ai_automation/README.rst | 108 +++++ ai_automation/__init__.py | 1 + ai_automation/__manifest__.py | 21 + ai_automation/models/__init__.py | 2 + ai_automation/models/ai_connection.py | 73 +++ ai_automation/models/ir_actions_server.py | 72 +++ ai_automation/readme/CONTRIBUTORS.md | 2 + ai_automation/readme/DESCRIPTION.md | 3 + ai_automation/readme/USAGE.md | 14 + ai_automation/security/ir.model.access.csv | 3 + ai_automation/static/description/icon.png | Bin 0 -> 9455 bytes ai_automation/static/description/index.html | 458 ++++++++++++++++++ ai_automation/tests/__init__.py | 1 + ai_automation/tests/test_connection_ollama.py | 134 +++++ ai_automation/views/ai_connection.xml | 72 +++ ai_automation/views/ir_actions_server.xml | 42 ++ 16 files changed, 1006 insertions(+) create mode 100644 ai_automation/README.rst create mode 100644 ai_automation/__init__.py create mode 100644 ai_automation/__manifest__.py create mode 100644 ai_automation/models/__init__.py create mode 100644 ai_automation/models/ai_connection.py create mode 100644 ai_automation/models/ir_actions_server.py create mode 100644 ai_automation/readme/CONTRIBUTORS.md create mode 100644 ai_automation/readme/DESCRIPTION.md create mode 100644 ai_automation/readme/USAGE.md create mode 100644 ai_automation/security/ir.model.access.csv create mode 100644 ai_automation/static/description/icon.png create mode 100644 ai_automation/static/description/index.html create mode 100644 ai_automation/tests/__init__.py create mode 100644 ai_automation/tests/test_connection_ollama.py create mode 100644 ai_automation/views/ai_connection.xml create mode 100644 ai_automation/views/ir_actions_server.xml diff --git a/ai_automation/README.rst b/ai_automation/README.rst new file mode 100644 index 00000000..cf7a7923 --- /dev/null +++ b/ai_automation/README.rst @@ -0,0 +1,108 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +============= +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/license-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/16.0/ai_automation + :alt: OCA/ai +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/ai-16-0/ai-16-0-ai_automation + :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=16.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 `_. +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Dixmit + +Contributors +------------ + +- `Dixmit `__ + + - Enric Tobella + +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 `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/ai_automation/__init__.py b/ai_automation/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/ai_automation/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/ai_automation/__manifest__.py b/ai_automation/__manifest__.py new file mode 100644 index 00000000..07d0262b --- /dev/null +++ b/ai_automation/__manifest__.py @@ -0,0 +1,21 @@ +# 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": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Dixmit,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/ai", + "depends": ["ai_tool"], + "external_dependencies": { + "python": ["ollama"], + }, + "data": [ + "views/ir_actions_server.xml", + "security/ir.model.access.csv", + "views/ai_connection.xml", + ], + "demo": [], +} diff --git a/ai_automation/models/__init__.py b/ai_automation/models/__init__.py new file mode 100644 index 00000000..f2ab448f --- /dev/null +++ b/ai_automation/models/__init__.py @@ -0,0 +1,2 @@ +from . import ai_connection +from . import ir_actions_server diff --git a/ai_automation/models/ai_connection.py b/ai_automation/models/ai_connection.py new file mode 100644 index 00000000..0419c58d --- /dev/null +++ b/ai_automation/models/ai_connection.py @@ -0,0 +1,73 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import json + +import ollama + +from odoo import fields, models + + +class AiConnection(models.Model): + _name = "ai.connection" + _description = "AI Connection" + + name = fields.Char(required=True) + kind = fields.Selection([("ollama", "Ollama")], required=True, default="ollama") + active = fields.Boolean(default=True) + url = fields.Char(groups="base.group_system") + model = fields.Char(groups="base.group_system") + + def _run(self, prompt, tools=None, record=None): + return getattr(self, f"_run_{self.kind}")(prompt, tools=tools, record=record) + + def _run_ollama(self, prompt, tools=None, messages=None, record=None): + tool_definition = [] + for tool in tools or []: + definition = tool._get_tool_definition() + input_schema = definition["inputSchema"] + input_schema["additionalProperties"] = False + tool_definition.append( + { + "type": "function", + "function": { + "name": definition["name"], + "description": definition["description"], + "parameters": input_schema, + }, + } + ) + ollama_client = ollama.Client(**self._get_ollama_client_parameters()) + if messages is None: + messages = [] + messages.append({"role": "user", "content": prompt}) + while True: + response = ollama_client.chat( + model=self.model, + messages=messages, + tools=tool_definition, + ) + if not response.message.tool_calls: + return response.message.content + messages.append(response.message) + for call in response.message.tool_calls: + tool = tools.filtered(lambda t: t.name == call.function.name) + tool_output = tool._execute_tool( + record=record, **call.function.arguments + ) + if isinstance(tool_output, dict): + tool_output = json.dumps(tool_output) + messages.append( + { + "role": "tool", + "tool_name": call.function.name, + "content": tool_output, + } + ) + + def _get_ollama_client_parameters(self): + """ + We provide this hook so people can modify the client and other configurations + like headers and so on. + """ + return {"host": self.url, "headers": {}} diff --git a/ai_automation/models/ir_actions_server.py b/ai_automation/models/ir_actions_server.py new file mode 100644 index 00000000..cbcb4f88 --- /dev/null +++ b/ai_automation/models/ir_actions_server.py @@ -0,0 +1,72 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from lxml import etree + +from odoo import api, fields, models + +from odoo.addons.web_editor.models.ir_qweb_fields import html_to_text + + +class IrActionsServer(models.Model): + + _inherit = "ir.actions.server" + + state = fields.Selection( + selection_add=[("ai_oca", "AI OCA Action")], ondelete={"ai_oca": "cascade"} + ) + ai_connection_id = fields.Many2one( + "ai.connection", string="AI Connection", groups="base.group_system" + ) + ai_tool_ids = fields.Many2many( + "ai.tool", + string="AI Tools", + groups="base.group_system", + ) + ai_prompt = fields.Html(string="AI Prompt", sanitize=False) + mailing_model_real = fields.Char(compute="_compute_mailing_model_real") + ai_result_action = fields.Selection( + [ + ("post_message", "Post Message"), + ("update_record", "Update Record"), + ], + string="AI Result Action", + ) + ai_update_record_field_id = fields.Many2one( + "ir.model.fields", + string="AI Update Record Field", + domain="[('model_id', '=', model_id), ('ttype', 'in', ['char', 'text'])]", + ) + + @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): + record = eval_context.get("record") + result = self.ai_connection_id._run( + self._get_ai_oca_prompt(record), tools=self.ai_tool_ids, record=record + ) + self._post_run_action_ai_oca(result, record) + + def _post_run_action_ai_oca(self, result, record): + if self.ai_result_action == "post_message": + self.env["ai.tool"]._ai_post_message(result, record=record) + elif ( + self.ai_result_action == "update_record" + and record + and self.ai_update_record_field_id + ): + record.write({self.ai_update_record_field_id.name: result}) + + def _get_ai_oca_prompt(self, record): + ai_prompt = self.ai_prompt + if record: + ai_prompt = str( + self.env["mail.render.mixin"]._render_template_qweb( + self.ai_prompt, record and record._name, record and record.ids + )[record.id] + ) + return html_to_text(etree.fromstring("" + ai_prompt + "")) diff --git a/ai_automation/readme/CONTRIBUTORS.md b/ai_automation/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..2c066ba7 --- /dev/null +++ b/ai_automation/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- [Dixmit](https://www.dixmit.com) + - Enric Tobella diff --git a/ai_automation/readme/DESCRIPTION.md b/ai_automation/readme/DESCRIPTION.md new file mode 100644 index 00000000..7fa64139 --- /dev/null +++ b/ai_automation/readme/DESCRIPTION.md @@ -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`. diff --git a/ai_automation/readme/USAGE.md b/ai_automation/readme/USAGE.md new file mode 100644 index 00000000..e597ad9a --- /dev/null +++ b/ai_automation/readme/USAGE.md @@ -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. \ No newline at end of file diff --git a/ai_automation/security/ir.model.access.csv b/ai_automation/security/ir.model.access.csv new file mode 100644 index 00000000..9d762bd9 --- /dev/null +++ b/ai_automation/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_ai_connection,access_ai_connection,model_ai_connection,base.group_user,1,0,0,0 +manage_ai_connection,manage_ai_connection,model_ai_connection,base.group_system,1,1,1,0 diff --git a/ai_automation/static/description/icon.png b/ai_automation/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/ai_automation/static/description/index.html b/ai_automation/static/description/index.html new file mode 100644 index 00000000..c8b600b8 --- /dev/null +++ b/ai_automation/static/description/index.html @@ -0,0 +1,458 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Ai Automation

+ +

Beta License: AGPL-3 OCA/ai Translate me on Weblate Try me on Runboat

+

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

+ +
+

Usage

+

This module adds a new server action type: AI OCA Action.

+

To use it:

+
    +
  1. Go to Settings > Technical > Actions > Server Actions
  2. +
  3. Create a new action and select AI OCA Action as the state
  4. +
  5. Select an AI Connection (Ollama)
  6. +
  7. Define the prompt — supports dynamic placeholders using Qweb syntax +(e.g. {{ object.name }})
  8. +
  9. Optionally select tools the AI can call during execution
  10. +
  11. 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
    • +
    +
  12. +
+

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. +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.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Dixmit
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

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 project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/ai_automation/tests/__init__.py b/ai_automation/tests/__init__.py new file mode 100644 index 00000000..f1aa56d4 --- /dev/null +++ b/ai_automation/tests/__init__.py @@ -0,0 +1 @@ +from . import test_connection_ollama diff --git a/ai_automation/tests/test_connection_ollama.py b/ai_automation/tests/test_connection_ollama.py new file mode 100644 index 00000000..93335c27 --- /dev/null +++ b/ai_automation/tests/test_connection_ollama.py @@ -0,0 +1,134 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from unittest import mock + +from ollama._types import ChatResponse + +from odoo.tests.common import TransactionCase + + +class OllamaClient: + def __init__(self, chat_messages=None): + self.chat_messages = chat_messages or [] + self.current_message = -1 + self.calls = [] + + def chat(self, *args, **kwargs): + self.current_message += 1 + self.calls.append((args, kwargs)) + return ChatResponse.model_validate( + {"message": self.chat_messages[self.current_message]} + ) + + +class TestConnectionOllama(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.connection = cls.env["ai.connection"].create( + { + "name": "Ollama Connection", + "url": "http://my_ollama_server:11434", + "model": "my_ollama_model", + "kind": "ollama", + } + ) + cls.action = cls.env["ir.actions.server"].create( + { + "name": "Test Action", + "model_id": cls.env.ref("base.model_res_partner").id, + "state": "ai_oca", + "ai_connection_id": cls.connection.id, + "ai_tool_ids": [(4, cls.env.ref("ai_tool.current_date").id)], + "ai_prompt": "What is the current date?", + } + ) + cls.partner = cls.env["res.partner"].create({"name": "Test Partner"}) + + def test_execute_action_with_tools(self): + client = OllamaClient( + [ + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "function": { + "name": "get_date", + "arguments": {}, + }, + "id": "1", + } + ], + }, + { + "role": "assistant", + "content": "Thanks it is 2024-01-01", + }, + ] + ) + with mock.patch("ollama.Client", return_value=client): + messages = self.partner.message_ids + self.action.with_context( + active_id=self.partner.id, active_model="res.partner" + ).run() + self.assertEqual(client.current_message, 1) + self.assertEqual(messages, self.partner.message_ids) + + def test_execute_action_post_message(self): + client = OllamaClient( + [ + { + "role": "assistant", + "content": "Thanks it is 2024-01-01", + }, + ] + ) + self.action.ai_result_action = "post_message" + with mock.patch("ollama.Client", return_value=client): + messages = self.partner.message_ids + self.action.with_context( + active_id=self.partner.id, active_model="res.partner" + ).run() + self.assertEqual(client.current_message, 0) + self.assertEqual(len(messages) + 1, len(self.partner.message_ids)) + self.assertRegex( + (self.partner.message_ids - messages).body, r".*2024-01-01.*" + ) + + def test_execute_action_field(self): + client = OllamaClient( + [ + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "function": { + "name": "get_date", + "arguments": {}, + }, + "id": "1", + } + ], + }, + { + "role": "assistant", + "content": "Thanks it is 2024-01-01", + }, + ] + ) + self.action.ai_result_action = "update_record" + self.action.ai_update_record_field_id = self.env.ref( + "base.field_res_partner__comment" + ) + self.partner.comment = "Initial Comment" + with mock.patch("ollama.Client", return_value=client): + messages = self.partner.message_ids + self.action.with_context( + active_id=self.partner.id, active_model="res.partner" + ).run() + self.assertEqual(client.current_message, 1) + self.assertEqual(messages, self.partner.message_ids) + self.assertRegex(self.partner.comment, r".*2024-01-01.*") diff --git a/ai_automation/views/ai_connection.xml b/ai_automation/views/ai_connection.xml new file mode 100644 index 00000000..acf18c19 --- /dev/null +++ b/ai_automation/views/ai_connection.xml @@ -0,0 +1,72 @@ + + + + + + ai.connection + +
+
+ + + + + + + + + + + + + + + + + + + + ai.connection + + + + + + + + + ai.connection + + + + + + + + + + AI Connection + ai.connection + tree,form + [] + {} + + + + AI Connection + + + + + + diff --git a/ai_automation/views/ir_actions_server.xml b/ai_automation/views/ir_actions_server.xml new file mode 100644 index 00000000..cc046e66 --- /dev/null +++ b/ai_automation/views/ir_actions_server.xml @@ -0,0 +1,42 @@ + + + + + + ir.actions.server + + + + + + + + + + + + + + + + + + + + From 5b454e899272fb9374221e5a271b587915ed5bea Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 14 May 2026 08:46:26 +0000 Subject: [PATCH 2/5] [UPD] Update ai_automation.pot --- ai_automation/i18n/ai_automation.pot | 169 +++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 ai_automation/i18n/ai_automation.pot diff --git a/ai_automation/i18n/ai_automation.pot b/ai_automation/i18n/ai_automation.pot new file mode 100644 index 00000000..34f9977b --- /dev/null +++ b/ai_automation/i18n/ai_automation.pot @@ -0,0 +1,169 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * ai_automation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: ai_automation +#: model:ir.actions.act_window,name:ai_automation.ai_connection_act_window +#: model:ir.model,name:ai_automation.model_ai_connection +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_connection_id +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_connection_id +#: model:ir.ui.menu,name:ai_automation.ai_connection_menu +msgid "AI Connection" +msgstr "" + +#. module: ai_automation +#: model_terms:ir.ui.view,arch_db:ai_automation.ir_actions_server_form_view +msgid "AI OCA" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields.selection,name:ai_automation.selection__ir_actions_server__state__ai_oca +msgid "AI OCA Action" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_prompt +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_prompt +msgid "AI Prompt" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_result_action +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_result_action +msgid "AI Result Action" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_tool_ids +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_tool_ids +msgid "AI Tools" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_update_record_field_id +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_update_record_field_id +msgid "AI Update Record Field" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__state +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__state +msgid "Action To Do" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__active +msgid "Active" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__create_uid +msgid "Created by" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__create_date +msgid "Created on" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__display_name +msgid "Display Name" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__id +msgid "ID" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__kind +msgid "Kind" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection____last_update +msgid "Last Modified on" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__write_date +msgid "Last Updated on" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__mailing_model_real +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__mailing_model_real +msgid "Mailing Model Real" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__model +msgid "Model" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__name +msgid "Name" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields.selection,name:ai_automation.selection__ai_connection__kind__ollama +msgid "Ollama" +msgstr "" + +#. module: ai_automation +#: model_terms:ir.ui.view,arch_db:ai_automation.ai_connection_form_view +msgid "Ollama configuration" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields.selection,name:ai_automation.selection__ir_actions_server__ai_result_action__post_message +msgid "Post Message" +msgstr "" + +#. module: ai_automation +#: model:ir.model,name:ai_automation.model_ir_actions_server +msgid "Server Action" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,help:ai_automation.field_ir_actions_server__state +#: model:ir.model.fields,help:ai_automation.field_ir_cron__state +msgid "" +"Type of server action. The following values are available:\n" +"- 'Execute Python Code': a block of python code that will be executed\n" +"- 'Create a new Record': create a new record with new values\n" +"- 'Update a Record': update the values of a record\n" +"- 'Execute several actions': define an action that triggers several other server actions\n" +"- 'Send Email': post a message, a note or send an email (Discuss)\n" +"- 'Add Followers': add followers to a record (Discuss)\n" +"- 'Create Next Activity': create an activity (Discuss)\n" +"- 'Send SMS Text Message': send SMS, log them on documents (SMS)" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields.selection,name:ai_automation.selection__ir_actions_server__ai_result_action__update_record +msgid "Update Record" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__url +msgid "Url" +msgstr "" From f8d450b0b581a7142022fec2d9ff339bfd492208 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 14 May 2026 08:49:14 +0000 Subject: [PATCH 3/5] [BOT] post-merge updates --- ai_automation/README.rst | 2 +- ai_automation/static/description/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ai_automation/README.rst b/ai_automation/README.rst index cf7a7923..f9699887 100644 --- a/ai_automation/README.rst +++ b/ai_automation/README.rst @@ -11,7 +11,7 @@ Ai Automation !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:9db8aa67499c9f7efc73ff5f14809ca6d3df0f99e4eb35df8fff7f4cd3de79d1 + !! source digest: sha256:ac6598665c8047af8125789ebf827e8fd7744751b8aad883a0298b1b3c4be233 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/ai_automation/static/description/index.html b/ai_automation/static/description/index.html index c8b600b8..4039faa5 100644 --- a/ai_automation/static/description/index.html +++ b/ai_automation/static/description/index.html @@ -372,7 +372,7 @@

Ai Automation

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:9db8aa67499c9f7efc73ff5f14809ca6d3df0f99e4eb35df8fff7f4cd3de79d1 +!! source digest: sha256:ac6598665c8047af8125789ebf827e8fd7744751b8aad883a0298b1b3c4be233 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/ai Translate me on Weblate Try me on Runboat

This module integrates AI connections with Odoo server actions, allowing From 81a415df518046f5a1e2112b4242b395ffc8af3e Mon Sep 17 00:00:00 2001 From: mymage Date: Thu, 14 May 2026 13:16:03 +0000 Subject: [PATCH 4/5] Added translation using Weblate (Italian) --- ai_automation/i18n/it.po | 170 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 ai_automation/i18n/it.po diff --git a/ai_automation/i18n/it.po b/ai_automation/i18n/it.po new file mode 100644 index 00000000..5c882238 --- /dev/null +++ b/ai_automation/i18n/it.po @@ -0,0 +1,170 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * ai_automation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: ai_automation +#: model:ir.actions.act_window,name:ai_automation.ai_connection_act_window +#: model:ir.model,name:ai_automation.model_ai_connection +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_connection_id +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_connection_id +#: model:ir.ui.menu,name:ai_automation.ai_connection_menu +msgid "AI Connection" +msgstr "" + +#. module: ai_automation +#: model_terms:ir.ui.view,arch_db:ai_automation.ir_actions_server_form_view +msgid "AI OCA" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields.selection,name:ai_automation.selection__ir_actions_server__state__ai_oca +msgid "AI OCA Action" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_prompt +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_prompt +msgid "AI Prompt" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_result_action +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_result_action +msgid "AI Result Action" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_tool_ids +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_tool_ids +msgid "AI Tools" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__ai_update_record_field_id +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__ai_update_record_field_id +msgid "AI Update Record Field" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__state +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__state +msgid "Action To Do" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__active +msgid "Active" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__create_uid +msgid "Created by" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__create_date +msgid "Created on" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__display_name +msgid "Display Name" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__id +msgid "ID" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__kind +msgid "Kind" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection____last_update +msgid "Last Modified on" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__write_date +msgid "Last Updated on" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ir_actions_server__mailing_model_real +#: model:ir.model.fields,field_description:ai_automation.field_ir_cron__mailing_model_real +msgid "Mailing Model Real" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__model +msgid "Model" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__name +msgid "Name" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields.selection,name:ai_automation.selection__ai_connection__kind__ollama +msgid "Ollama" +msgstr "" + +#. module: ai_automation +#: model_terms:ir.ui.view,arch_db:ai_automation.ai_connection_form_view +msgid "Ollama configuration" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields.selection,name:ai_automation.selection__ir_actions_server__ai_result_action__post_message +msgid "Post Message" +msgstr "" + +#. module: ai_automation +#: model:ir.model,name:ai_automation.model_ir_actions_server +msgid "Server Action" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,help:ai_automation.field_ir_actions_server__state +#: model:ir.model.fields,help:ai_automation.field_ir_cron__state +msgid "" +"Type of server action. The following values are available:\n" +"- 'Execute Python Code': a block of python code that will be executed\n" +"- 'Create a new Record': create a new record with new values\n" +"- 'Update a Record': update the values of a record\n" +"- 'Execute several actions': define an action that triggers several other server actions\n" +"- 'Send Email': post a message, a note or send an email (Discuss)\n" +"- 'Add Followers': add followers to a record (Discuss)\n" +"- 'Create Next Activity': create an activity (Discuss)\n" +"- 'Send SMS Text Message': send SMS, log them on documents (SMS)" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields.selection,name:ai_automation.selection__ir_actions_server__ai_result_action__update_record +msgid "Update Record" +msgstr "" + +#. module: ai_automation +#: model:ir.model.fields,field_description:ai_automation.field_ai_connection__url +msgid "Url" +msgstr "" From 1093dab882b0178ebac7aa0d92b6b6bd0cdc0669 Mon Sep 17 00:00:00 2001 From: LixFerox Date: Wed, 27 May 2026 14:43:29 +0200 Subject: [PATCH 5/5] [18.0][MIG] ai_automation: migrate to 18.0 --- ai_automation/README.rst | 22 +++++++------ ai_automation/__manifest__.py | 6 ++-- ai_automation/i18n/ai_automation.pot | 2 +- ai_automation/i18n/it.po | 2 +- ai_automation/models/ai_connection.py | 5 +-- ai_automation/models/ir_actions_server.py | 1 - ai_automation/pyproject.toml | 3 ++ ai_automation/readme/CONTRIBUTORS.md | 4 +++ ai_automation/static/description/index.html | 36 ++++++++++----------- ai_automation/views/ai_connection.xml | 20 ++++-------- ai_automation/views/ir_actions_server.xml | 11 ++----- 11 files changed, 54 insertions(+), 58 deletions(-) create mode 100644 ai_automation/pyproject.toml diff --git a/ai_automation/README.rst b/ai_automation/README.rst index f9699887..951b0118 100644 --- a/ai_automation/README.rst +++ b/ai_automation/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ============= Ai Automation ============= @@ -17,17 +13,17 @@ Ai Automation .. |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/license-AGPL--3-blue.png +.. |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/16.0/ai_automation + :target: https://github.com/OCA/ai/tree/18.0/ai_automation :alt: OCA/ai .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/ai-16-0/ai-16-0-ai_automation + :target: https://translation.odoo-community.org/projects/ai-18-0/ai-18-0-ai_automation :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=16.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/ai&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -71,7 +67,7 @@ Bug Tracker Bugs are tracked on `GitHub 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -90,6 +86,12 @@ Contributors - Enric Tobella +- `Vortex Dimensión Digital `__: + + - Jorge Rosado Julián + - Juan L. Sánchez + - Wang Zhong Jiang + Maintainers ----------- @@ -103,6 +105,6 @@ 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 `_ project on GitHub. +This module is part of the `OCA/ai `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/ai_automation/__manifest__.py b/ai_automation/__manifest__.py index 07d0262b..25cbd0a5 100644 --- a/ai_automation/__manifest__.py +++ b/ai_automation/__manifest__.py @@ -3,8 +3,10 @@ { "name": "Ai Automation", - "summary": """Integrate `ai_tools` with server actions to automate tasks using AI.""", - "version": "16.0.1.0.0", + "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", diff --git a/ai_automation/i18n/ai_automation.pot b/ai_automation/i18n/ai_automation.pot index 34f9977b..63e9c9ed 100644 --- a/ai_automation/i18n/ai_automation.pot +++ b/ai_automation/i18n/ai_automation.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" +"Project-Id-Version: Odoo Server 18.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" diff --git a/ai_automation/i18n/it.po b/ai_automation/i18n/it.po index 5c882238..c5ad95bd 100644 --- a/ai_automation/i18n/it.po +++ b/ai_automation/i18n/it.po @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" +"Project-Id-Version: Odoo Server 18.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" diff --git a/ai_automation/models/ai_connection.py b/ai_automation/models/ai_connection.py index 0419c58d..a417068d 100644 --- a/ai_automation/models/ai_connection.py +++ b/ai_automation/models/ai_connection.py @@ -51,7 +51,8 @@ def _run_ollama(self, prompt, tools=None, messages=None, record=None): return response.message.content messages.append(response.message) for call in response.message.tool_calls: - tool = tools.filtered(lambda t: t.name == call.function.name) + function_name = call.function.name + tool = tools.filtered(lambda t, name=function_name: t.name == name) tool_output = tool._execute_tool( record=record, **call.function.arguments ) @@ -60,7 +61,7 @@ def _run_ollama(self, prompt, tools=None, messages=None, record=None): messages.append( { "role": "tool", - "tool_name": call.function.name, + "tool_name": function_name, "content": tool_output, } ) diff --git a/ai_automation/models/ir_actions_server.py b/ai_automation/models/ir_actions_server.py index cbcb4f88..ce65099b 100644 --- a/ai_automation/models/ir_actions_server.py +++ b/ai_automation/models/ir_actions_server.py @@ -8,7 +8,6 @@ class IrActionsServer(models.Model): - _inherit = "ir.actions.server" state = fields.Selection( diff --git a/ai_automation/pyproject.toml b/ai_automation/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/ai_automation/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/ai_automation/readme/CONTRIBUTORS.md b/ai_automation/readme/CONTRIBUTORS.md index 2c066ba7..eaf8ac56 100644 --- a/ai_automation/readme/CONTRIBUTORS.md +++ b/ai_automation/readme/CONTRIBUTORS.md @@ -1,2 +1,6 @@ - [Dixmit](https://www.dixmit.com) - Enric Tobella +- [Vortex Dimensión Digital](https://www.dimensionvortex.com/): + - Jorge Rosado Julián \<\> + - Juan L. Sánchez \<\> + - Wang Zhong Jiang \<\> \ No newline at end of file diff --git a/ai_automation/static/description/index.html b/ai_automation/static/description/index.html index 4039faa5..44f359a0 100644 --- a/ai_automation/static/description/index.html +++ b/ai_automation/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Ai Automation -

+
+

Ai Automation

- - -Odoo Community Association - -
-

Ai Automation

-

Beta License: AGPL-3 OCA/ai Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/ai Translate me on Weblate Try me on Runboat

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 @@ -393,7 +388,7 @@

Ai Automation

-

Usage

+

Usage

This module adds a new server action type: AI OCA Action.

To use it:

    @@ -415,32 +410,38 @@

    Usage

    _run_{kind} method.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub 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.

+feedback.

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Dixmit
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -448,11 +449,10 @@

Maintainers

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 project on GitHub.

+

This module is part of the OCA/ai project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

-
diff --git a/ai_automation/views/ai_connection.xml b/ai_automation/views/ai_connection.xml index acf18c19..261ecc95 100644 --- a/ai_automation/views/ai_connection.xml +++ b/ai_automation/views/ai_connection.xml @@ -2,7 +2,6 @@ - ai.connection @@ -16,17 +15,11 @@ - - + + @@ -47,17 +40,17 @@ ai.connection - + - + AI Connection ai.connection - tree,form + list,form [] {} @@ -68,5 +61,4 @@ - diff --git a/ai_automation/views/ir_actions_server.xml b/ai_automation/views/ir_actions_server.xml index cc046e66..bc7b4af5 100644 --- a/ai_automation/views/ir_actions_server.xml +++ b/ai_automation/views/ir_actions_server.xml @@ -2,16 +2,12 @@ - ir.actions.server - + - - -