jl-ecms-client 0.2.8__py3-none-any.whl → 0.2.23__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jl-ecms-client might be problematic. Click here for more details.

Files changed (40) hide show
  1. {jl_ecms_client-0.2.8.dist-info → jl_ecms_client-0.2.23.dist-info}/METADATA +6 -1
  2. jl_ecms_client-0.2.23.dist-info/RECORD +67 -0
  3. mirix/__init__.py +41 -0
  4. mirix/client/client.py +1 -1
  5. mirix/constants.py +251 -0
  6. mirix/errors.py +238 -0
  7. mirix/functions/__init__.py +0 -0
  8. mirix/functions/ast_parsers.py +113 -0
  9. mirix/functions/function_sets/__init__.py +1 -0
  10. mirix/functions/function_sets/base.py +330 -0
  11. mirix/functions/function_sets/extras.py +271 -0
  12. mirix/functions/function_sets/memory_tools.py +933 -0
  13. mirix/functions/functions.py +199 -0
  14. mirix/functions/helpers.py +311 -0
  15. mirix/functions/schema_generator.py +511 -0
  16. mirix/helpers/json_helpers.py +3 -3
  17. mirix/log.py +163 -0
  18. mirix/schemas/agent.py +1 -1
  19. mirix/schemas/block.py +1 -1
  20. mirix/schemas/embedding_config.py +0 -3
  21. mirix/schemas/enums.py +12 -0
  22. mirix/schemas/episodic_memory.py +1 -1
  23. mirix/schemas/knowledge_vault.py +1 -1
  24. mirix/schemas/memory.py +1 -1
  25. mirix/schemas/message.py +1 -1
  26. mirix/schemas/mirix_request.py +1 -1
  27. mirix/schemas/procedural_memory.py +1 -1
  28. mirix/schemas/providers.py +1 -1
  29. mirix/schemas/resource_memory.py +1 -1
  30. mirix/schemas/sandbox_config.py +1 -3
  31. mirix/schemas/semantic_memory.py +1 -1
  32. mirix/schemas/tool.py +241 -241
  33. mirix/schemas/user.py +3 -3
  34. mirix/settings.py +280 -0
  35. mirix/system.py +261 -0
  36. jl_ecms_client-0.2.8.dist-info/RECORD +0 -53
  37. mirix/client/constants.py +0 -60
  38. {jl_ecms_client-0.2.8.dist-info → jl_ecms_client-0.2.23.dist-info}/WHEEL +0 -0
  39. {jl_ecms_client-0.2.8.dist-info → jl_ecms_client-0.2.23.dist-info}/licenses/LICENSE +0 -0
  40. {jl_ecms_client-0.2.8.dist-info → jl_ecms_client-0.2.23.dist-info}/top_level.txt +0 -0
mirix/schemas/agent.py CHANGED
@@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional, Union
3
3
 
4
4
  from pydantic import BaseModel, Field, field_validator
5
5
 
6
- from mirix.client.constants import DEFAULT_EMBEDDING_CHUNK_SIZE
6
+ from mirix.constants import DEFAULT_EMBEDDING_CHUNK_SIZE
7
7
  from mirix.helpers import ToolRulesSolver
8
8
  from mirix.schemas.block import CreateBlock
9
9
  from mirix.schemas.embedding_config import EmbeddingConfig
mirix/schemas/block.py CHANGED
@@ -3,7 +3,7 @@ from typing import Optional
3
3
  from pydantic import BaseModel, Field, model_validator
4
4
  from typing_extensions import Self
5
5
 
6
- from mirix.client.constants import CORE_MEMORY_BLOCK_CHAR_LIMIT
6
+ from mirix.constants import CORE_MEMORY_BLOCK_CHAR_LIMIT
7
7
  from mirix.schemas.mirix_base import MirixBase
8
8
 
9
9
  # block of the LLM context
@@ -2,9 +2,6 @@ from typing import Literal, Optional
2
2
 
3
3
  from pydantic import BaseModel, Field
4
4
 
5
- from mirix.log import get_logger
6
-
7
- logger = get_logger(__name__)
8
5
 
9
6
  class EmbeddingConfig(BaseModel):
10
7
  """
mirix/schemas/enums.py CHANGED
@@ -1,6 +1,18 @@
1
1
  from enum import Enum
2
2
 
3
3
 
4
+ class ToolType(str, Enum):
5
+ """Types of tools in Mirix"""
6
+ CUSTOM = "custom"
7
+ MIRIX_CORE = "mirix_core"
8
+ MIRIX_CODER_CORE = "mirix_coder_core"
9
+ MIRIX_MEMORY_CORE = "mirix_memory_core"
10
+ MIRIX_EXTRA = "mirix_extra"
11
+ MIRIX_MCP = "mirix_mcp"
12
+ MIRIX_MULTI_AGENT_CORE = "mirix_multi_agent_core"
13
+ USER_DEFINED = "user_defined"
14
+
15
+
4
16
  class ProviderType(str, Enum):
5
17
  anthropic = "anthropic"
6
18
 
@@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional
4
4
  from pydantic import Field, field_validator
5
5
 
6
6
  from mirix.client.utils import get_utc_time
7
- from mirix.client.constants import MAX_EMBEDDING_DIM
7
+ from mirix.constants import MAX_EMBEDDING_DIM
8
8
  from mirix.schemas.embedding_config import EmbeddingConfig
9
9
  from mirix.schemas.mirix_base import MirixBase
10
10
 
@@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional
4
4
  from pydantic import Field, field_validator
5
5
 
6
6
  from mirix.client.utils import get_utc_time
7
- from mirix.client.constants import MAX_EMBEDDING_DIM
7
+ from mirix.constants import MAX_EMBEDDING_DIM
8
8
  from mirix.schemas.embedding_config import EmbeddingConfig
9
9
  from mirix.schemas.mirix_base import MirixBase
10
10
 
mirix/schemas/memory.py CHANGED
@@ -7,7 +7,7 @@ from pydantic import BaseModel, Field
7
7
  if TYPE_CHECKING:
8
8
  from mirix.schemas.agent import AgentState
9
9
 
10
- from mirix.client.constants import CORE_MEMORY_BLOCK_CHAR_LIMIT
10
+ from mirix.constants import CORE_MEMORY_BLOCK_CHAR_LIMIT
11
11
  from mirix.schemas.block import Block
12
12
  from mirix.schemas.message import Message
13
13
  from mirix.schemas.openai.chat_completion_request import Tool
mirix/schemas/message.py CHANGED
@@ -10,7 +10,7 @@ from typing import Any, Dict, List, Literal, Optional, Union
10
10
 
11
11
  from pydantic import BaseModel, Field, field_validator
12
12
 
13
- from mirix.client.constants import (
13
+ from mirix.constants import (
14
14
  DEFAULT_MESSAGE_TOOL,
15
15
  DEFAULT_MESSAGE_TOOL_KWARG,
16
16
  TOOL_CALL_ID_MAX_LEN,
@@ -2,7 +2,7 @@ from typing import List
2
2
 
3
3
  from pydantic import BaseModel, Field
4
4
 
5
- from mirix.client.constants import DEFAULT_MESSAGE_TOOL, DEFAULT_MESSAGE_TOOL_KWARG
5
+ from mirix.constants import DEFAULT_MESSAGE_TOOL, DEFAULT_MESSAGE_TOOL_KWARG
6
6
  from mirix.schemas.message import MessageCreate
7
7
 
8
8
 
@@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional
4
4
  from pydantic import Field, field_validator
5
5
 
6
6
  from mirix.client.utils import get_utc_time
7
- from mirix.client.constants import MAX_EMBEDDING_DIM
7
+ from mirix.constants import MAX_EMBEDDING_DIM
8
8
  from mirix.schemas.embedding_config import EmbeddingConfig
9
9
  from mirix.schemas.mirix_base import MirixBase
10
10
 
@@ -3,7 +3,7 @@ from typing import List, Optional
3
3
 
4
4
  from pydantic import Field, model_validator
5
5
 
6
- from mirix.client.constants import LLM_MAX_TOKENS, MIN_CONTEXT_WINDOW
6
+ from mirix.constants import LLM_MAX_TOKENS, MIN_CONTEXT_WINDOW
7
7
  from mirix.llm_api.azure_openai import (
8
8
  get_azure_chat_completions_endpoint,
9
9
  get_azure_embeddings_endpoint,
@@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional
3
3
 
4
4
  from pydantic import Field, field_validator
5
5
 
6
- from mirix.client.constants import MAX_EMBEDDING_DIM
6
+ from mirix.constants import MAX_EMBEDDING_DIM
7
7
  from mirix.schemas.embedding_config import EmbeddingConfig
8
8
  from mirix.schemas.mirix_base import MirixBase
9
9
  from mirix.client.utils import get_utc_time
@@ -8,12 +8,9 @@ from pydantic import BaseModel, Field, model_validator
8
8
  from mirix.schemas.agent import AgentState
9
9
  from mirix.schemas.mirix_base import MirixBase, OrmMetadataBase
10
10
  from mirix.settings import tool_settings
11
- from mirix.log import get_logger
12
11
 
13
12
 
14
13
  # Sandbox Config
15
-
16
- logger = get_logger(__name__)
17
14
  class SandboxType(str, Enum):
18
15
  E2B = "e2b"
19
16
  LOCAL = "local"
@@ -73,6 +70,7 @@ class E2BSandboxConfig(BaseModel):
73
70
  Assign a default template value if the template field is not provided.
74
71
  """
75
72
  if data.get("template") is None:
73
+ # Use configured template if available
76
74
  data["template"] = tool_settings.e2b_sandbox_template_id
77
75
  return data
78
76
 
@@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional
3
3
 
4
4
  from pydantic import Field, field_validator
5
5
 
6
- from mirix.client.constants import MAX_EMBEDDING_DIM
6
+ from mirix.constants import MAX_EMBEDDING_DIM
7
7
  from mirix.schemas.embedding_config import EmbeddingConfig
8
8
  from mirix.schemas.mirix_base import MirixBase
9
9
  from mirix.client.utils import get_utc_time
mirix/schemas/tool.py CHANGED
@@ -1,241 +1,241 @@
1
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
2
-
3
- from pydantic import Field, model_validator
4
-
5
- from mirix.client.constants import (
6
- COMPOSIO_TOOL_TAG_NAME,
7
- FUNCTION_RETURN_CHAR_LIMIT,
8
- MIRIX_CORE_TOOL_MODULE_NAME,
9
- MIRIX_EXTRA_TOOL_MODULE_NAME,
10
- MIRIX_MEMORY_TOOL_MODULE_NAME,
11
- )
12
- from mirix.functions.functions import (
13
- derive_openai_json_schema,
14
- get_json_schema_from_module,
15
- )
16
- from mirix.functions.helpers import generate_langchain_tool_wrapper
17
- from mirix.functions.schema_generator import generate_schema_from_args_schema_v2
18
- from mirix.orm.enums import ToolType
19
- from mirix.schemas.mirix_base import MirixBase
20
-
21
- if TYPE_CHECKING:
22
- try:
23
- from langchain_core.tools import BaseTool as LangChainBaseTool
24
- except ImportError:
25
- LangChainBaseTool = Any # type: ignore
26
-
27
-
28
- class BaseTool(MirixBase):
29
- __id_prefix__ = "tool"
30
-
31
-
32
- class Tool(BaseTool):
33
- """
34
- Representation of a tool, which is a function that can be called by the agent.
35
-
36
- Parameters:
37
- id (str): The unique identifier of the tool.
38
- name (str): The name of the function.
39
- tags (List[str]): Metadata tags.
40
- source_code (str): The source code of the function.
41
- json_schema (Dict): The JSON schema of the function.
42
-
43
- """
44
-
45
- id: str = BaseTool.generate_id_field()
46
- tool_type: ToolType = Field(ToolType.CUSTOM, description="The type of the tool.")
47
- description: Optional[str] = Field(None, description="The description of the tool.")
48
- source_type: Optional[str] = Field(None, description="The type of the source code.")
49
- organization_id: Optional[str] = Field(
50
- None,
51
- description="The unique identifier of the organization associated with the tool.",
52
- )
53
- name: Optional[str] = Field(None, description="The name of the function.")
54
- tags: List[str] = Field([], description="Metadata tags.")
55
-
56
- # code
57
- source_code: Optional[str] = Field(
58
- None, description="The source code of the function."
59
- )
60
- json_schema: Optional[Dict] = Field(
61
- None, description="The JSON schema of the function."
62
- )
63
-
64
- # tool configuration
65
- return_char_limit: int = Field(
66
- FUNCTION_RETURN_CHAR_LIMIT,
67
- description="The maximum number of characters in the response.",
68
- )
69
-
70
- # metadata fields
71
- created_by_id: Optional[str] = Field(
72
- None, description="The id of the user that made this Tool."
73
- )
74
- last_updated_by_id: Optional[str] = Field(
75
- None, description="The id of the user that made this Tool."
76
- )
77
-
78
- @model_validator(mode="after")
79
- def populate_missing_fields(self):
80
- """
81
- Populate missing fields: name, description, and json_schema.
82
- """
83
-
84
- if self.tool_type == ToolType.CUSTOM:
85
- # If it's a custom tool, we need to ensure source_code is present
86
- if not self.source_code:
87
- raise ValueError(
88
- f"Custom tool with id={self.id} is missing source_code field."
89
- )
90
-
91
- # Always derive json_schema for freshest possible json_schema
92
- # TODO: Instead of checking the tag, we should having `COMPOSIO` as a specific ToolType
93
- # TODO: We skip this for Composio bc composio json schemas are derived differently
94
- if COMPOSIO_TOOL_TAG_NAME not in self.tags:
95
- self.json_schema = derive_openai_json_schema(
96
- source_code=self.source_code
97
- )
98
- elif self.tool_type in {ToolType.MIRIX_CORE}:
99
- # If it's mirix core tool, we generate the json_schema on the fly here
100
- self.json_schema = get_json_schema_from_module(
101
- module_name=MIRIX_CORE_TOOL_MODULE_NAME, function_name=self.name
102
- )
103
- elif self.tool_type in {ToolType.MIRIX_MEMORY_CORE}:
104
- self.json_schema = get_json_schema_from_module(
105
- module_name=MIRIX_MEMORY_TOOL_MODULE_NAME, function_name=self.name
106
- )
107
- elif self.tool_type in {ToolType.MIRIX_EXTRA}:
108
- self.json_schema = get_json_schema_from_module(
109
- module_name=MIRIX_EXTRA_TOOL_MODULE_NAME, function_name=self.name
110
- )
111
- elif self.tool_type in {ToolType.MIRIX_MCP}:
112
- # MCP tools have their json_schema already provided by MCP tool registry
113
- # Skip validation since these are auto-generated tools
114
- if not self.json_schema:
115
- raise ValueError(f"MCP tool {self.name} is missing json_schema field")
116
-
117
- # Derive name from the JSON schema if not provided
118
- if not self.name:
119
- # TODO: This in theory could error, but name should always be on json_schema
120
- # TODO: Make JSON schema a typed pydantic object
121
- self.name = self.json_schema.get("name")
122
-
123
- # Derive description from the JSON schema if not provided
124
- if not self.description:
125
- # TODO: This in theory could error, but description should always be on json_schema
126
- # TODO: Make JSON schema a typed pydantic object
127
- self.description = self.json_schema.get("description")
128
-
129
- return self
130
-
131
-
132
- class ToolCreate(MirixBase):
133
- name: Optional[str] = Field(
134
- None,
135
- description="The name of the function (auto-generated from source_code if not provided).",
136
- )
137
- description: Optional[str] = Field(None, description="The description of the tool.")
138
- tags: List[str] = Field([], description="Metadata tags.")
139
- source_code: str = Field(..., description="The source code of the function.")
140
- source_type: str = Field("python", description="The source type of the function.")
141
- json_schema: Optional[Dict] = Field(
142
- None,
143
- description="The JSON schema of the function (auto-generated from source_code if not provided)",
144
- )
145
- return_char_limit: int = Field(
146
- FUNCTION_RETURN_CHAR_LIMIT,
147
- description="The maximum number of characters in the response.",
148
- )
149
-
150
- @classmethod
151
- def from_langchain(
152
- cls,
153
- langchain_tool: "LangChainBaseTool",
154
- additional_imports_module_attr_map: dict[str, str] = None,
155
- ) -> "ToolCreate":
156
- """
157
- Class method to create an instance of Tool from a Langchain tool (must be from langchain_community.tools).
158
-
159
- Args:
160
- langchain_tool (LangChainBaseTool): An instance of a LangChain BaseTool (BaseTool from LangChain)
161
- additional_imports_module_attr_map (dict[str, str]): A mapping of module names to attribute name. This is used internally to import all the required classes for the langchain tool. For example, you would pass in `{"langchain_community.utilities": "WikipediaAPIWrapper"}` for `from langchain_community.tools import WikipediaQueryRun`. NOTE: You do NOT need to specify the tool import here, that is done automatically for you.
162
-
163
- Returns:
164
- Tool: A Mirix Tool initialized with attributes derived from the provided LangChain BaseTool object.
165
- """
166
- description = langchain_tool.description
167
- source_type = "python"
168
- tags = ["langchain"]
169
- # NOTE: langchain tools may come from different packages
170
- wrapper_func_name, wrapper_function_str = generate_langchain_tool_wrapper(
171
- langchain_tool, additional_imports_module_attr_map
172
- )
173
- json_schema = generate_schema_from_args_schema_v2(
174
- langchain_tool.args_schema, name=wrapper_func_name, description=description
175
- )
176
-
177
- return cls(
178
- name=wrapper_func_name,
179
- description=description,
180
- source_type=source_type,
181
- tags=tags,
182
- source_code=wrapper_function_str,
183
- json_schema=json_schema,
184
- )
185
-
186
- @classmethod
187
- def load_default_langchain_tools(cls) -> List["ToolCreate"]:
188
- # For now, we only support wikipedia tool
189
- from langchain_community.tools import WikipediaQueryRun
190
- from langchain_community.utilities import WikipediaAPIWrapper
191
-
192
- wikipedia_tool = ToolCreate.from_langchain(
193
- WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()),
194
- {"langchain_community.utilities": "WikipediaAPIWrapper"},
195
- )
196
-
197
- return [wikipedia_tool]
198
-
199
- @classmethod
200
- def load_default_composio_tools(cls) -> List["ToolCreate"]:
201
- pass
202
-
203
- # TODO: Disable composio tools for now
204
- # TODO: Naming is causing issues
205
- # calculator = ToolCreate.from_composio(action_name=Action.MATHEMATICAL_CALCULATOR.name)
206
- # serp_news = ToolCreate.from_composio(action_name=Action.SERPAPI_NEWS_SEARCH.name)
207
- # serp_google_search = ToolCreate.from_composio(action_name=Action.SERPAPI_SEARCH.name)
208
- # serp_google_maps = ToolCreate.from_composio(action_name=Action.SERPAPI_GOOGLE_MAPS_SEARCH.name)
209
-
210
- return []
211
-
212
-
213
- class ToolUpdate(MirixBase):
214
- description: Optional[str] = Field(None, description="The description of the tool.")
215
- name: Optional[str] = Field(None, description="The name of the function.")
216
- tags: Optional[List[str]] = Field(None, description="Metadata tags.")
217
- source_code: Optional[str] = Field(
218
- None, description="The source code of the function."
219
- )
220
- source_type: Optional[str] = Field(None, description="The type of the source code.")
221
- json_schema: Optional[Dict] = Field(
222
- None,
223
- description="The JSON schema of the function (auto-generated from source_code if not provided)",
224
- )
225
- return_char_limit: Optional[int] = Field(
226
- None, description="The maximum number of characters in the response."
227
- )
228
-
229
- class Config:
230
- extra = "ignore" # Allows extra fields without validation errors
231
- # TODO: Remove this, and clean usage of ToolUpdate everywhere else
232
-
233
-
234
- class ToolRunFromSource(MirixBase):
235
- source_code: str = Field(..., description="The source code of the function.")
236
- args: Dict[str, Any] = Field(..., description="The arguments to pass to the tool.")
237
- env_vars: Dict[str, str] = Field(
238
- None, description="The environment variables to pass to the tool."
239
- )
240
- name: Optional[str] = Field(None, description="The name of the tool to run.")
241
- source_type: Optional[str] = Field(None, description="The type of the source code.")
1
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
2
+
3
+ from pydantic import Field, model_validator
4
+
5
+ from mirix.constants import (
6
+ COMPOSIO_TOOL_TAG_NAME,
7
+ FUNCTION_RETURN_CHAR_LIMIT,
8
+ MIRIX_CORE_TOOL_MODULE_NAME,
9
+ MIRIX_EXTRA_TOOL_MODULE_NAME,
10
+ MIRIX_MEMORY_TOOL_MODULE_NAME,
11
+ )
12
+ from mirix.functions.functions import (
13
+ derive_openai_json_schema,
14
+ get_json_schema_from_module,
15
+ )
16
+ from mirix.functions.helpers import generate_langchain_tool_wrapper
17
+ from mirix.functions.schema_generator import generate_schema_from_args_schema_v2
18
+ from mirix.schemas.enums import ToolType
19
+ from mirix.schemas.mirix_base import MirixBase
20
+
21
+ if TYPE_CHECKING:
22
+ try:
23
+ from langchain_core.tools import BaseTool as LangChainBaseTool
24
+ except ImportError:
25
+ LangChainBaseTool = Any # type: ignore
26
+
27
+
28
+ class BaseTool(MirixBase):
29
+ __id_prefix__ = "tool"
30
+
31
+
32
+ class Tool(BaseTool):
33
+ """
34
+ Representation of a tool, which is a function that can be called by the agent.
35
+
36
+ Parameters:
37
+ id (str): The unique identifier of the tool.
38
+ name (str): The name of the function.
39
+ tags (List[str]): Metadata tags.
40
+ source_code (str): The source code of the function.
41
+ json_schema (Dict): The JSON schema of the function.
42
+
43
+ """
44
+
45
+ id: str = BaseTool.generate_id_field()
46
+ tool_type: ToolType = Field(ToolType.CUSTOM, description="The type of the tool.")
47
+ description: Optional[str] = Field(None, description="The description of the tool.")
48
+ source_type: Optional[str] = Field(None, description="The type of the source code.")
49
+ organization_id: Optional[str] = Field(
50
+ None,
51
+ description="The unique identifier of the organization associated with the tool.",
52
+ )
53
+ name: Optional[str] = Field(None, description="The name of the function.")
54
+ tags: List[str] = Field([], description="Metadata tags.")
55
+
56
+ # code
57
+ source_code: Optional[str] = Field(
58
+ None, description="The source code of the function."
59
+ )
60
+ json_schema: Optional[Dict] = Field(
61
+ None, description="The JSON schema of the function."
62
+ )
63
+
64
+ # tool configuration
65
+ return_char_limit: int = Field(
66
+ FUNCTION_RETURN_CHAR_LIMIT,
67
+ description="The maximum number of characters in the response.",
68
+ )
69
+
70
+ # metadata fields
71
+ created_by_id: Optional[str] = Field(
72
+ None, description="The id of the user that made this Tool."
73
+ )
74
+ last_updated_by_id: Optional[str] = Field(
75
+ None, description="The id of the user that made this Tool."
76
+ )
77
+
78
+ @model_validator(mode="after")
79
+ def populate_missing_fields(self):
80
+ """
81
+ Populate missing fields: name, description, and json_schema.
82
+ """
83
+
84
+ if self.tool_type == ToolType.CUSTOM:
85
+ # If it's a custom tool, we need to ensure source_code is present
86
+ if not self.source_code:
87
+ raise ValueError(
88
+ f"Custom tool with id={self.id} is missing source_code field."
89
+ )
90
+
91
+ # Always derive json_schema for freshest possible json_schema
92
+ # TODO: Instead of checking the tag, we should having `COMPOSIO` as a specific ToolType
93
+ # TODO: We skip this for Composio bc composio json schemas are derived differently
94
+ if COMPOSIO_TOOL_TAG_NAME not in self.tags:
95
+ self.json_schema = derive_openai_json_schema(
96
+ source_code=self.source_code
97
+ )
98
+ elif self.tool_type in {ToolType.MIRIX_CORE}:
99
+ # If it's mirix core tool, we generate the json_schema on the fly here
100
+ self.json_schema = get_json_schema_from_module(
101
+ module_name=MIRIX_CORE_TOOL_MODULE_NAME, function_name=self.name
102
+ )
103
+ elif self.tool_type in {ToolType.MIRIX_MEMORY_CORE}:
104
+ self.json_schema = get_json_schema_from_module(
105
+ module_name=MIRIX_MEMORY_TOOL_MODULE_NAME, function_name=self.name
106
+ )
107
+ elif self.tool_type in {ToolType.MIRIX_EXTRA}:
108
+ self.json_schema = get_json_schema_from_module(
109
+ module_name=MIRIX_EXTRA_TOOL_MODULE_NAME, function_name=self.name
110
+ )
111
+ elif self.tool_type in {ToolType.MIRIX_MCP}:
112
+ # MCP tools have their json_schema already provided by MCP tool registry
113
+ # Skip validation since these are auto-generated tools
114
+ if not self.json_schema:
115
+ raise ValueError(f"MCP tool {self.name} is missing json_schema field")
116
+
117
+ # Derive name from the JSON schema if not provided
118
+ if not self.name:
119
+ # TODO: This in theory could error, but name should always be on json_schema
120
+ # TODO: Make JSON schema a typed pydantic object
121
+ self.name = self.json_schema.get("name")
122
+
123
+ # Derive description from the JSON schema if not provided
124
+ if not self.description:
125
+ # TODO: This in theory could error, but description should always be on json_schema
126
+ # TODO: Make JSON schema a typed pydantic object
127
+ self.description = self.json_schema.get("description")
128
+
129
+ return self
130
+
131
+
132
+ class ToolCreate(MirixBase):
133
+ name: Optional[str] = Field(
134
+ None,
135
+ description="The name of the function (auto-generated from source_code if not provided).",
136
+ )
137
+ description: Optional[str] = Field(None, description="The description of the tool.")
138
+ tags: List[str] = Field([], description="Metadata tags.")
139
+ source_code: str = Field(..., description="The source code of the function.")
140
+ source_type: str = Field("python", description="The source type of the function.")
141
+ json_schema: Optional[Dict] = Field(
142
+ None,
143
+ description="The JSON schema of the function (auto-generated from source_code if not provided)",
144
+ )
145
+ return_char_limit: int = Field(
146
+ FUNCTION_RETURN_CHAR_LIMIT,
147
+ description="The maximum number of characters in the response.",
148
+ )
149
+
150
+ @classmethod
151
+ def from_langchain(
152
+ cls,
153
+ langchain_tool: "LangChainBaseTool",
154
+ additional_imports_module_attr_map: dict[str, str] = None,
155
+ ) -> "ToolCreate":
156
+ """
157
+ Class method to create an instance of Tool from a Langchain tool (must be from langchain_community.tools).
158
+
159
+ Args:
160
+ langchain_tool (LangChainBaseTool): An instance of a LangChain BaseTool (BaseTool from LangChain)
161
+ additional_imports_module_attr_map (dict[str, str]): A mapping of module names to attribute name. This is used internally to import all the required classes for the langchain tool. For example, you would pass in `{"langchain_community.utilities": "WikipediaAPIWrapper"}` for `from langchain_community.tools import WikipediaQueryRun`. NOTE: You do NOT need to specify the tool import here, that is done automatically for you.
162
+
163
+ Returns:
164
+ Tool: A Mirix Tool initialized with attributes derived from the provided LangChain BaseTool object.
165
+ """
166
+ description = langchain_tool.description
167
+ source_type = "python"
168
+ tags = ["langchain"]
169
+ # NOTE: langchain tools may come from different packages
170
+ wrapper_func_name, wrapper_function_str = generate_langchain_tool_wrapper(
171
+ langchain_tool, additional_imports_module_attr_map
172
+ )
173
+ json_schema = generate_schema_from_args_schema_v2(
174
+ langchain_tool.args_schema, name=wrapper_func_name, description=description
175
+ )
176
+
177
+ return cls(
178
+ name=wrapper_func_name,
179
+ description=description,
180
+ source_type=source_type,
181
+ tags=tags,
182
+ source_code=wrapper_function_str,
183
+ json_schema=json_schema,
184
+ )
185
+
186
+ @classmethod
187
+ def load_default_langchain_tools(cls) -> List["ToolCreate"]:
188
+ # For now, we only support wikipedia tool
189
+ from langchain_community.tools import WikipediaQueryRun
190
+ from langchain_community.utilities import WikipediaAPIWrapper
191
+
192
+ wikipedia_tool = ToolCreate.from_langchain(
193
+ WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()),
194
+ {"langchain_community.utilities": "WikipediaAPIWrapper"},
195
+ )
196
+
197
+ return [wikipedia_tool]
198
+
199
+ @classmethod
200
+ def load_default_composio_tools(cls) -> List["ToolCreate"]:
201
+ pass
202
+
203
+ # TODO: Disable composio tools for now
204
+ # TODO: Naming is causing issues
205
+ # calculator = ToolCreate.from_composio(action_name=Action.MATHEMATICAL_CALCULATOR.name)
206
+ # serp_news = ToolCreate.from_composio(action_name=Action.SERPAPI_NEWS_SEARCH.name)
207
+ # serp_google_search = ToolCreate.from_composio(action_name=Action.SERPAPI_SEARCH.name)
208
+ # serp_google_maps = ToolCreate.from_composio(action_name=Action.SERPAPI_GOOGLE_MAPS_SEARCH.name)
209
+
210
+ return []
211
+
212
+
213
+ class ToolUpdate(MirixBase):
214
+ description: Optional[str] = Field(None, description="The description of the tool.")
215
+ name: Optional[str] = Field(None, description="The name of the function.")
216
+ tags: Optional[List[str]] = Field(None, description="Metadata tags.")
217
+ source_code: Optional[str] = Field(
218
+ None, description="The source code of the function."
219
+ )
220
+ source_type: Optional[str] = Field(None, description="The type of the source code.")
221
+ json_schema: Optional[Dict] = Field(
222
+ None,
223
+ description="The JSON schema of the function (auto-generated from source_code if not provided)",
224
+ )
225
+ return_char_limit: Optional[int] = Field(
226
+ None, description="The maximum number of characters in the response."
227
+ )
228
+
229
+ class Config:
230
+ extra = "ignore" # Allows extra fields without validation errors
231
+ # TODO: Remove this, and clean usage of ToolUpdate everywhere else
232
+
233
+
234
+ class ToolRunFromSource(MirixBase):
235
+ source_code: str = Field(..., description="The source code of the function.")
236
+ args: Dict[str, Any] = Field(..., description="The arguments to pass to the tool.")
237
+ env_vars: Dict[str, str] = Field(
238
+ None, description="The environment variables to pass to the tool."
239
+ )
240
+ name: Optional[str] = Field(None, description="The name of the tool to run.")
241
+ source_type: Optional[str] = Field(None, description="The type of the source code.")