diff --git a/ai_tool/models/ai_tool.py b/ai_tool/models/ai_tool.py index 82068020..2cfb52c6 100644 --- a/ai_tool/models/ai_tool.py +++ b/ai_tool/models/ai_tool.py @@ -37,7 +37,10 @@ class AiTool(models.Model): ) def _get_tool_definition(self): - func = getattr(self.env[self.model_id.model], self.function_name) + # model_id points to ir.model, which non-admin users cannot read. + # The model name is only metadata, so resolve it as sudo. + model = self.sudo().model_id.model + func = getattr(self.env[model], self.function_name) return { "name": self.name, "description": self.description, @@ -77,18 +80,20 @@ def _ai_post_message_parse_body(self, message): return plaintext2html(message) def _execute_tool(self, *args, record=None, **kwargs): + # model_id points to ir.model, which non-admin users cannot read. + # Resolve the model name as sudo (metadata only); the call below + # still runs with the caller's own rights via self.env[model]. + model = self.sudo().model_id.model if self.kind == "generic": - return getattr(self.env[self.model_id.model], self.function_name)( - *args, **kwargs - ) + return getattr(self.env[model], self.function_name)(*args, **kwargs) if not record: raise ValueError("Record must be provided for non-generic tools") if self.kind == "generic_model": - return getattr(self.env[self.model_id.model], self.function_name)( + return getattr(self.env[model], self.function_name)( *args, record=record, **kwargs ) - elif record._name != self.model_id.model: + elif record._name != model: raise ValueError( - f"Record model {record._name} does not match tool model {self.model_id.model}" + f"Record model {record._name} does not match tool model {model}" ) return getattr(record, self.function_name)(*args, **kwargs) or {} diff --git a/ai_tool/tests/test_ai_tool.py b/ai_tool/tests/test_ai_tool.py index c9090aaf..86c1d991 100644 --- a/ai_tool/tests/test_ai_tool.py +++ b/ai_tool/tests/test_ai_tool.py @@ -47,3 +47,21 @@ def test_post_message_tool_record_different_model(self): tool.kind = "record" with self.assertRaises(ValueError): tool._execute_tool(message="Hello World", record=self.partner) + + def test_tool_non_admin_user(self): + """A plain internal user (no ir.model access) must be able to build a + tool definition and execute a generic tool: resolving the tool's model + is metadata and must not require Administration/Access Rights.""" + user = self.env["res.users"].create( + { + "name": "Ai Tool Plain User", + "login": "ai_tool_plain_user", + "groups_id": [(6, 0, [self.env.ref("base.group_user").id])], + } + ) + self.assertFalse(user.has_group("base.group_system")) + tool = self.env.ref("ai_tool.current_date").with_user(user) + definition = tool._get_tool_definition() + self.assertEqual(definition["name"], "get_date") + result = tool._execute_tool() + self.assertIn("date", result)