camel-ai 0.2.21__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 camel-ai might be problematic. Click here for more details.

Files changed (116) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/_types.py +41 -0
  3. camel/agents/_utils.py +188 -0
  4. camel/agents/chat_agent.py +570 -965
  5. camel/agents/knowledge_graph_agent.py +7 -1
  6. camel/agents/multi_hop_generator_agent.py +1 -1
  7. camel/configs/base_config.py +10 -13
  8. camel/configs/deepseek_config.py +4 -30
  9. camel/configs/gemini_config.py +5 -31
  10. camel/configs/openai_config.py +14 -32
  11. camel/configs/qwen_config.py +36 -36
  12. camel/datagen/self_improving_cot.py +81 -3
  13. camel/datagen/self_instruct/filter/instruction_filter.py +19 -3
  14. camel/datagen/self_instruct/self_instruct.py +53 -4
  15. camel/datasets/__init__.py +28 -0
  16. camel/datasets/base.py +969 -0
  17. camel/embeddings/openai_embedding.py +10 -1
  18. camel/environments/__init__.py +16 -0
  19. camel/environments/base.py +503 -0
  20. camel/extractors/__init__.py +16 -0
  21. camel/extractors/base.py +263 -0
  22. camel/interpreters/docker/Dockerfile +12 -0
  23. camel/interpreters/docker_interpreter.py +19 -1
  24. camel/interpreters/subprocess_interpreter.py +42 -17
  25. camel/loaders/__init__.py +2 -0
  26. camel/loaders/mineru_extractor.py +250 -0
  27. camel/memories/agent_memories.py +16 -1
  28. camel/memories/blocks/chat_history_block.py +10 -2
  29. camel/memories/blocks/vectordb_block.py +1 -0
  30. camel/memories/context_creators/score_based.py +20 -3
  31. camel/memories/records.py +10 -0
  32. camel/messages/base.py +8 -8
  33. camel/models/__init__.py +2 -0
  34. camel/models/_utils.py +57 -0
  35. camel/models/aiml_model.py +48 -17
  36. camel/models/anthropic_model.py +41 -3
  37. camel/models/azure_openai_model.py +39 -3
  38. camel/models/base_audio_model.py +92 -0
  39. camel/models/base_model.py +132 -4
  40. camel/models/cohere_model.py +88 -11
  41. camel/models/deepseek_model.py +107 -63
  42. camel/models/fish_audio_model.py +18 -8
  43. camel/models/gemini_model.py +133 -15
  44. camel/models/groq_model.py +72 -10
  45. camel/models/internlm_model.py +14 -3
  46. camel/models/litellm_model.py +9 -2
  47. camel/models/mistral_model.py +42 -5
  48. camel/models/model_manager.py +57 -3
  49. camel/models/moonshot_model.py +33 -4
  50. camel/models/nemotron_model.py +32 -3
  51. camel/models/nvidia_model.py +43 -3
  52. camel/models/ollama_model.py +139 -17
  53. camel/models/openai_audio_models.py +87 -2
  54. camel/models/openai_compatible_model.py +37 -3
  55. camel/models/openai_model.py +158 -46
  56. camel/models/qwen_model.py +61 -4
  57. camel/models/reka_model.py +53 -3
  58. camel/models/samba_model.py +209 -4
  59. camel/models/sglang_model.py +153 -14
  60. camel/models/siliconflow_model.py +16 -3
  61. camel/models/stub_model.py +46 -4
  62. camel/models/togetherai_model.py +38 -3
  63. camel/models/vllm_model.py +37 -3
  64. camel/models/yi_model.py +36 -3
  65. camel/models/zhipuai_model.py +38 -3
  66. camel/retrievers/__init__.py +3 -0
  67. camel/retrievers/hybrid_retrival.py +237 -0
  68. camel/toolkits/__init__.py +20 -3
  69. camel/toolkits/arxiv_toolkit.py +2 -1
  70. camel/toolkits/ask_news_toolkit.py +4 -2
  71. camel/toolkits/audio_analysis_toolkit.py +238 -0
  72. camel/toolkits/base.py +22 -3
  73. camel/toolkits/code_execution.py +2 -0
  74. camel/toolkits/dappier_toolkit.py +2 -1
  75. camel/toolkits/data_commons_toolkit.py +38 -12
  76. camel/toolkits/excel_toolkit.py +172 -0
  77. camel/toolkits/function_tool.py +13 -0
  78. camel/toolkits/github_toolkit.py +5 -1
  79. camel/toolkits/google_maps_toolkit.py +2 -1
  80. camel/toolkits/google_scholar_toolkit.py +2 -0
  81. camel/toolkits/human_toolkit.py +0 -3
  82. camel/toolkits/image_analysis_toolkit.py +202 -0
  83. camel/toolkits/linkedin_toolkit.py +3 -2
  84. camel/toolkits/meshy_toolkit.py +3 -2
  85. camel/toolkits/mineru_toolkit.py +178 -0
  86. camel/toolkits/networkx_toolkit.py +240 -0
  87. camel/toolkits/notion_toolkit.py +2 -0
  88. camel/toolkits/openbb_toolkit.py +3 -2
  89. camel/toolkits/page_script.js +376 -0
  90. camel/toolkits/reddit_toolkit.py +11 -3
  91. camel/toolkits/retrieval_toolkit.py +6 -1
  92. camel/toolkits/semantic_scholar_toolkit.py +2 -1
  93. camel/toolkits/stripe_toolkit.py +8 -2
  94. camel/toolkits/sympy_toolkit.py +44 -1
  95. camel/toolkits/video_analysis_toolkit.py +407 -0
  96. camel/toolkits/{video_toolkit.py → video_download_toolkit.py} +21 -25
  97. camel/toolkits/web_toolkit.py +1307 -0
  98. camel/toolkits/whatsapp_toolkit.py +3 -2
  99. camel/toolkits/zapier_toolkit.py +191 -0
  100. camel/types/__init__.py +2 -2
  101. camel/types/agents/__init__.py +16 -0
  102. camel/types/agents/tool_calling_record.py +52 -0
  103. camel/types/enums.py +3 -0
  104. camel/types/openai_types.py +16 -14
  105. camel/utils/__init__.py +2 -1
  106. camel/utils/async_func.py +2 -2
  107. camel/utils/commons.py +114 -1
  108. camel/verifiers/__init__.py +23 -0
  109. camel/verifiers/base.py +340 -0
  110. camel/verifiers/models.py +82 -0
  111. camel/verifiers/python_verifier.py +202 -0
  112. camel_ai-0.2.23.dist-info/METADATA +671 -0
  113. {camel_ai-0.2.21.dist-info → camel_ai-0.2.23.dist-info}/RECORD +127 -99
  114. {camel_ai-0.2.21.dist-info → camel_ai-0.2.23.dist-info}/WHEEL +1 -1
  115. camel_ai-0.2.21.dist-info/METADATA +0 -528
  116. {camel_ai-0.2.21.dist-info → camel_ai-0.2.23.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,376 @@
1
+ var MultimodalWebSurfer = MultimodalWebSurfer || (function() {
2
+ let nextLabel = 10;
3
+
4
+ let roleMapping = {
5
+ "a": "link",
6
+ "area": "link",
7
+ "button": "button",
8
+ "input, type=button": "button",
9
+ "input, type=checkbox": "checkbox",
10
+ "input, type=email": "textbox",
11
+ "input, type=number": "spinbutton",
12
+ "input, type=radio": "radio",
13
+ "input, type=range": "slider",
14
+ "input, type=reset": "button",
15
+ "input, type=search": "searchbox",
16
+ "input, type=submit": "button",
17
+ "input, type=tel": "textbox",
18
+ "input, type=text": "textbox",
19
+ "input, type=url": "textbox",
20
+ "search": "search",
21
+ "select": "combobox",
22
+ "option": "option",
23
+ "textarea": "textbox"
24
+ };
25
+
26
+ let getCursor = function(elm) {
27
+ return window.getComputedStyle(elm)["cursor"];
28
+ };
29
+
30
+ let getInteractiveElements = function() {
31
+
32
+ let results = []
33
+ let roles = ["scrollbar", "searchbox", "slider", "spinbutton", "switch", "tab", "treeitem", "button", "checkbox", "gridcell", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "progressbar", "radio", "textbox", "combobox", "menu", "tree", "treegrid", "grid", "listbox", "radiogroup", "widget"];
34
+ let inertCursors = ["auto", "default", "none", "text", "vertical-text", "not-allowed", "no-drop"];
35
+
36
+ // Get the main interactive elements
37
+ let nodeList = document.querySelectorAll("input, select, textarea, button, [href], [onclick], [contenteditable], [tabindex]:not([tabindex='-1'])");
38
+ for (let i=0; i<nodeList.length; i++) { // Copy to something mutable
39
+ results.push(nodeList[i]);
40
+ }
41
+
42
+ // Anything not already included that has a suitable role
43
+ nodeList = document.querySelectorAll("[role]");
44
+ for (let i=0; i<nodeList.length; i++) { // Copy to something mutable
45
+ if (results.indexOf(nodeList[i]) == -1) {
46
+ let role = nodeList[i].getAttribute("role");
47
+ if (roles.indexOf(role) > -1) {
48
+ results.push(nodeList[i]);
49
+ }
50
+ }
51
+ }
52
+
53
+ // Any element that changes the cursor to something implying interactivity
54
+ nodeList = document.querySelectorAll("*");
55
+ for (let i=0; i<nodeList.length; i++) {
56
+ let node = nodeList[i];
57
+
58
+ // Cursor is default, or does not suggest interactivity
59
+ let cursor = getCursor(node);
60
+ if (inertCursors.indexOf(cursor) >= 0) {
61
+ continue;
62
+ }
63
+
64
+ // Move up to the first instance of this cursor change
65
+ parent = node.parentNode;
66
+ while (parent && getCursor(parent) == cursor) {
67
+ node = parent;
68
+ parent = node.parentNode;
69
+ }
70
+
71
+ // Add the node if it is new
72
+ if (results.indexOf(node) == -1) {
73
+ results.push(node);
74
+ }
75
+ }
76
+
77
+ return results;
78
+ };
79
+
80
+ let labelElements = function(elements) {
81
+ for (let i=0; i<elements.length; i++) {
82
+ if (!elements[i].hasAttribute("__elementId")) {
83
+ elements[i].setAttribute("__elementId", "" + (nextLabel++));
84
+ }
85
+ }
86
+ };
87
+
88
+ let isTopmost = function(element, x, y) {
89
+ let hit = document.elementFromPoint(x, y);
90
+
91
+ // Hack to handle elements outside the viewport
92
+ if (hit === null) {
93
+ return true;
94
+ }
95
+
96
+ while (hit) {
97
+ if (hit == element) return true;
98
+ hit = hit.parentNode;
99
+ }
100
+ return false;
101
+ };
102
+
103
+ let getFocusedElementId = function() {
104
+ let elm = document.activeElement;
105
+ while (elm) {
106
+ if (elm.hasAttribute && elm.hasAttribute("__elementId")) {
107
+ return elm.getAttribute("__elementId");
108
+ }
109
+ elm = elm.parentNode;
110
+ }
111
+ return null;
112
+ };
113
+
114
+ let trimmedInnerText = function(element) {
115
+ if (!element) {
116
+ return "";
117
+ }
118
+ let text = element.innerText;
119
+ if (!text) {
120
+ return "";
121
+ }
122
+ return text.trim();
123
+ };
124
+
125
+ let getApproximateAriaName = function(element) {
126
+ // Check for aria labels
127
+ if (element.hasAttribute("aria-labelledby")) {
128
+ let buffer = "";
129
+ let ids = element.getAttribute("aria-labelledby").split(" ");
130
+ for (let i=0; i<ids.length; i++) {
131
+ let label = document.getElementById(ids[i]);
132
+ if (label) {
133
+ buffer = buffer + " " + trimmedInnerText(label);
134
+ }
135
+ }
136
+ return buffer.trim();
137
+ }
138
+
139
+ if (element.hasAttribute("aria-label")) {
140
+ return element.getAttribute("aria-label");
141
+ }
142
+
143
+ // Check for labels
144
+ if (element.hasAttribute("id")) {
145
+ let label_id = element.getAttribute("id");
146
+ let label = "";
147
+ let labels = document.querySelectorAll("label[for='" + label_id + "']");
148
+ for (let j=0; j<labels.length; j++) {
149
+ label += labels[j].innerText + " ";
150
+ }
151
+ label = label.trim();
152
+ if (label != "") {
153
+ return label;
154
+ }
155
+ }
156
+
157
+ if (element.parentElement && element.parentElement.tagName == "LABEL") {
158
+ return element.parentElement.innerText;
159
+ }
160
+
161
+ // Check for alt text or titles
162
+ if (element.hasAttribute("alt")) {
163
+ return element.getAttribute("alt")
164
+ }
165
+
166
+ if (element.hasAttribute("title")) {
167
+ return element.getAttribute("title")
168
+ }
169
+
170
+ return trimmedInnerText(element);
171
+ };
172
+
173
+ let getApproximateAriaRole = function(element) {
174
+ let tag = element.tagName.toLowerCase();
175
+ if (tag == "input" && element.hasAttribute("type")) {
176
+ tag = tag + ", type=" + element.getAttribute("type");
177
+ }
178
+
179
+ if (element.hasAttribute("role")) {
180
+ return [element.getAttribute("role"), tag];
181
+ }
182
+ else if (tag in roleMapping) {
183
+ return [roleMapping[tag], tag];
184
+ }
185
+ else {
186
+ return ["", tag];
187
+ }
188
+ };
189
+
190
+ let getInteractiveRects = function() {
191
+ labelElements(getInteractiveElements());
192
+ let elements = document.querySelectorAll("[__elementId]");
193
+ let results = {};
194
+ for (let i=0; i<elements.length; i++) {
195
+ let key = elements[i].getAttribute("__elementId");
196
+ let rects = elements[i].getClientRects();
197
+ let ariaRole = getApproximateAriaRole(elements[i]);
198
+ let ariaName = getApproximateAriaName(elements[i]);
199
+ let vScrollable = elements[i].scrollHeight - elements[i].clientHeight >= 1;
200
+
201
+ let record = {
202
+ "tag_name": ariaRole[1],
203
+ "role": ariaRole[0],
204
+ "aria-name": ariaName,
205
+ "v-scrollable": vScrollable,
206
+ "rects": []
207
+ };
208
+
209
+ for (const rect of rects) {
210
+ let x = rect.left + rect.width/2;
211
+ let y = rect.top + rect.height/2;
212
+ if (isTopmost(elements[i], x, y)) {
213
+ record["rects"].push(JSON.parse(JSON.stringify(rect)));
214
+ }
215
+ }
216
+
217
+ if (record["rects"].length > 0) {
218
+ results[key] = record;
219
+ }
220
+ }
221
+ return results;
222
+ };
223
+
224
+ let getVisualViewport = function() {
225
+ let vv = window.visualViewport;
226
+ let de = document.documentElement;
227
+ return {
228
+ "height": vv ? vv.height : 0,
229
+ "width": vv ? vv.width : 0,
230
+ "offsetLeft": vv ? vv.offsetLeft : 0,
231
+ "offsetTop": vv ? vv.offsetTop : 0,
232
+ "pageLeft": vv ? vv.pageLeft : 0,
233
+ "pageTop": vv ? vv.pageTop : 0,
234
+ "scale": vv ? vv.scale : 0,
235
+ "clientWidth": de ? de.clientWidth : 0,
236
+ "clientHeight": de ? de.clientHeight : 0,
237
+ "scrollWidth": de ? de.scrollWidth : 0,
238
+ "scrollHeight": de ? de.scrollHeight : 0
239
+ };
240
+ };
241
+
242
+ let _getMetaTags = function() {
243
+ let meta = document.querySelectorAll("meta");
244
+ let results = {};
245
+ for (let i = 0; i<meta.length; i++) {
246
+ let key = null;
247
+ if (meta[i].hasAttribute("name")) {
248
+ key = meta[i].getAttribute("name");
249
+ }
250
+ else if (meta[i].hasAttribute("property")) {
251
+ key = meta[i].getAttribute("property");
252
+ }
253
+ else {
254
+ continue;
255
+ }
256
+ if (meta[i].hasAttribute("content")) {
257
+ results[key] = meta[i].getAttribute("content");
258
+ }
259
+ }
260
+ return results;
261
+ };
262
+
263
+ let _getJsonLd = function() {
264
+ let jsonld = [];
265
+ let scripts = document.querySelectorAll('script[type="application/ld+json"]');
266
+ for (let i=0; i<scripts.length; i++) {
267
+ jsonld.push(scripts[i].innerHTML.trim());
268
+ }
269
+ return jsonld;
270
+ };
271
+
272
+ // From: https://www.stevefenton.co.uk/blog/2022/12/parse-microdata-with-javascript/
273
+ let _getMicrodata = function() {
274
+ function sanitize(input) {
275
+ return input.replace(/\s/gi, ' ').trim();
276
+ }
277
+
278
+ function addValue(information, name, value) {
279
+ if (information[name]) {
280
+ if (typeof information[name] === 'array') {
281
+ information[name].push(value);
282
+ } else {
283
+ const arr = [];
284
+ arr.push(information[name]);
285
+ arr.push(value);
286
+ information[name] = arr;
287
+ }
288
+ } else {
289
+ information[name] = value;
290
+ }
291
+ }
292
+
293
+ function traverseItem(item, information) {
294
+ const children = item.children;
295
+
296
+ for (let i = 0; i < children.length; i++) {
297
+ const child = children[i];
298
+
299
+ if (child.hasAttribute('itemscope')) {
300
+ if (child.hasAttribute('itemprop')) {
301
+ const itemProp = child.getAttribute('itemprop');
302
+ const itemType = child.getAttribute('itemtype');
303
+
304
+ const childInfo = {
305
+ itemType: itemType
306
+ };
307
+
308
+ traverseItem(child, childInfo);
309
+
310
+ itemProp.split(' ').forEach(propName => {
311
+ addValue(information, propName, childInfo);
312
+ });
313
+ }
314
+
315
+ } else if (child.hasAttribute('itemprop')) {
316
+ const itemProp = child.getAttribute('itemprop');
317
+ itemProp.split(' ').forEach(propName => {
318
+ if (propName === 'url') {
319
+ addValue(information, propName, child.href);
320
+ } else {
321
+ addValue(information, propName, sanitize(child.getAttribute("content") || child.content || child.textContent || child.src || ""));
322
+ }
323
+ });
324
+ traverseItem(child, information);
325
+ } else {
326
+ traverseItem(child, information);
327
+ }
328
+ }
329
+ }
330
+
331
+ const microdata = [];
332
+
333
+ document.querySelectorAll("[itemscope]").forEach(function(elem, i) {
334
+ const itemType = elem.getAttribute('itemtype');
335
+ const information = {
336
+ itemType: itemType
337
+ };
338
+ traverseItem(elem, information);
339
+ microdata.push(information);
340
+ });
341
+
342
+ return microdata;
343
+ };
344
+
345
+ let getPageMetadata = function() {
346
+ let jsonld = _getJsonLd();
347
+ let metaTags = _getMetaTags();
348
+ let microdata = _getMicrodata();
349
+ let results = {}
350
+ if (jsonld.length > 0) {
351
+ try {
352
+ results["jsonld"] = JSON.parse(jsonld);
353
+ }
354
+ catch (e) {
355
+ results["jsonld"] = jsonld;
356
+ }
357
+ }
358
+ if (microdata.length > 0) {
359
+ results["microdata"] = microdata;
360
+ }
361
+ for (let key in metaTags) {
362
+ if (metaTags.hasOwnProperty(key)) {
363
+ results["meta_tags"] = metaTags;
364
+ break;
365
+ }
366
+ }
367
+ return results;
368
+ };
369
+
370
+ return {
371
+ getInteractiveRects: getInteractiveRects,
372
+ getVisualViewport: getVisualViewport,
373
+ getFocusedElementId: getFocusedElementId,
374
+ getPageMetadata: getPageMetadata,
375
+ };
376
+ })();
@@ -14,7 +14,7 @@
14
14
 
15
15
  import os
16
16
  import time
17
- from typing import Any, Dict, List, Union
17
+ from typing import Any, Dict, List, Optional, Union
18
18
 
19
19
  from camel.toolkits import FunctionTool
20
20
  from camel.toolkits.base import BaseToolkit
@@ -30,11 +30,16 @@ class RedditToolkit(BaseToolkit):
30
30
 
31
31
  Attributes:
32
32
  retries (int): Number of retries for API requests in case of failure.
33
- delay (int): Delay between retries in seconds.
33
+ delay (float): Delay between retries in seconds.
34
34
  reddit (Reddit): An instance of the Reddit client.
35
35
  """
36
36
 
37
- def __init__(self, retries: int = 3, delay: int = 0):
37
+ def __init__(
38
+ self,
39
+ retries: int = 3,
40
+ delay: float = 0.0,
41
+ timeout: Optional[float] = None,
42
+ ):
38
43
  r"""Initializes the RedditToolkit with the specified number of retries
39
44
  and delay.
40
45
 
@@ -43,7 +48,10 @@ class RedditToolkit(BaseToolkit):
43
48
  failure. Defaults to `3`.
44
49
  delay (int): Time in seconds to wait between retries. Defaults to
45
50
  `0`.
51
+ timeout (float): Timeout for API requests in seconds. Defaults to
52
+ `None`.
46
53
  """
54
+ super().__init__(timeout=timeout)
47
55
  from praw import Reddit # type: ignore[import-untyped]
48
56
 
49
57
  self.retries = retries
@@ -27,8 +27,13 @@ class RetrievalToolkit(BaseToolkit):
27
27
  storage system based on a specified query.
28
28
  """
29
29
 
30
- def __init__(self, auto_retriever: Optional[AutoRetriever] = None) -> None:
30
+ def __init__(
31
+ self,
32
+ auto_retriever: Optional[AutoRetriever] = None,
33
+ timeout: Optional[float] = None,
34
+ ) -> None:
31
35
  r"""Initializes a new instance of the RetrievalToolkit class."""
36
+ super().__init__(timeout=timeout)
32
37
  self.ar = auto_retriever or AutoRetriever(
33
38
  vector_storage_local_path="camel/temp_storage",
34
39
  storage_type=StorageType.QDRANT,
@@ -26,8 +26,9 @@ class SemanticScholarToolkit(BaseToolkit):
26
26
  API to fetch paper and author data.
27
27
  """
28
28
 
29
- def __init__(self):
29
+ def __init__(self, timeout: Optional[float] = None):
30
30
  r"""Initializes the SemanticScholarToolkit."""
31
+ super().__init__(timeout=timeout)
31
32
  self.base_url = "https://api.semanticscholar.org/graph/v1"
32
33
 
33
34
  def fetch_paper_data_title(
@@ -15,7 +15,7 @@
15
15
  import json
16
16
  import logging
17
17
  import os
18
- from typing import List
18
+ from typing import List, Optional
19
19
 
20
20
  from camel.toolkits import FunctionTool
21
21
  from camel.toolkits.base import BaseToolkit
@@ -41,7 +41,12 @@ class StripeToolkit(BaseToolkit):
41
41
  (None, "STRIPE_API_KEY"),
42
42
  ]
43
43
  )
44
- def __init__(self, retries: int = 3):
44
+ def __init__(
45
+ self,
46
+ retries: int = 3,
47
+ timeout: Optional[float] = None,
48
+ ):
49
+ super().__init__(timeout=timeout)
45
50
  r"""Initializes the StripeToolkit with the specified number of
46
51
  retries.
47
52
 
@@ -49,6 +54,7 @@ class StripeToolkit(BaseToolkit):
49
54
  retries (int,optional): Number of times to retry the request in
50
55
  case of failure. (default: :obj:`3`)
51
56
  """
57
+ super().__init__(timeout=timeout)
52
58
  import stripe
53
59
 
54
60
  stripe.max_network_retries = retries
@@ -28,13 +28,18 @@ class SymPyToolkit(BaseToolkit):
28
28
  and Linear Algebra.
29
29
  """
30
30
 
31
- def __init__(self, default_variable: str = 'x'):
31
+ def __init__(
32
+ self,
33
+ default_variable: str = 'x',
34
+ timeout: Optional[float] = None,
35
+ ):
32
36
  r"""Initializes the toolkit with a default variable and logging.
33
37
 
34
38
  Args:
35
39
  default_variable (str): The default variable for
36
40
  operations (default: :obj: `x`)
37
41
  """
42
+ super().__init__(timeout=timeout)
38
43
  self.default_variable = default_variable
39
44
  logger.info(f"Default variable set to: {self.default_variable}")
40
45
 
@@ -721,6 +726,43 @@ class SymPyToolkit(BaseToolkit):
721
726
  except Exception as e:
722
727
  return self.handle_exception("compute_rank", e)
723
728
 
729
+ def compute_inner_product(
730
+ self, vector1: List[float], vector2: List[float]
731
+ ) -> str:
732
+ r"""Computes the inner (dot) product of two vectors.
733
+
734
+ Args:
735
+ vector1 (List[float]): The first vector as a list of floats.
736
+ vector2 (List[float]): The second vector as a list of floats.
737
+
738
+ Returns:
739
+ str: JSON string containing the inner product in the `"result"`
740
+ field. If an error occurs, the JSON string will include an
741
+ `"error"` field with the corresponding error message.
742
+
743
+ Raises:
744
+ ValueError: If the vectors have different dimensions.
745
+ """
746
+ import sympy as sp
747
+
748
+ try:
749
+ # Convert the lists into sympy Matrix objects (column vectors)
750
+ v1 = sp.Matrix(vector1)
751
+ v2 = sp.Matrix(vector2)
752
+
753
+ # Check that the vectors have the same dimensions.
754
+ if v1.shape != v2.shape:
755
+ raise ValueError(
756
+ "Vectors must have the same dimensions to compute "
757
+ "the inner product."
758
+ )
759
+
760
+ # Compute the dot (inner) product.
761
+ inner_product = v1.dot(v2)
762
+ return json.dumps({"result": str(inner_product)})
763
+ except Exception as e:
764
+ return self.handle_exception("compute_inner_product", e)
765
+
724
766
  def handle_exception(self, func_name: str, error: Exception) -> str:
725
767
  r"""Handles exceptions by logging and returning error details.
726
768
 
@@ -775,4 +817,5 @@ class SymPyToolkit(BaseToolkit):
775
817
  FunctionTool(self.compute_eigenvectors),
776
818
  FunctionTool(self.compute_nullspace),
777
819
  FunctionTool(self.compute_rank),
820
+ FunctionTool(self.compute_inner_product),
778
821
  ]