camel-ai 0.2.71a12__py3-none-any.whl → 0.2.72a0__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.

camel/__init__.py CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  from camel.logger import disable_logging, enable_logging, set_log_level
16
16
 
17
- __version__ = '0.2.71a12'
17
+ __version__ = '0.2.72a0'
18
18
 
19
19
  __all__ = [
20
20
  '__version__',
@@ -20,6 +20,7 @@ from pydantic import BaseModel
20
20
 
21
21
  from camel.configs import MOONSHOT_API_PARAMS, MoonshotConfig
22
22
  from camel.messages import OpenAIMessage
23
+ from camel.models._utils import try_modify_message_with_format
23
24
  from camel.models.openai_compatible_model import OpenAICompatibleModel
24
25
  from camel.types import (
25
26
  ChatCompletion,
@@ -106,6 +107,38 @@ class MoonshotModel(OpenAICompatibleModel):
106
107
  **kwargs,
107
108
  )
108
109
 
110
+ def _prepare_request(
111
+ self,
112
+ messages: List[OpenAIMessage],
113
+ response_format: Optional[Type[BaseModel]] = None,
114
+ tools: Optional[List[Dict[str, Any]]] = None,
115
+ ) -> Dict[str, Any]:
116
+ r"""Prepare the request configuration for Moonshot API.
117
+
118
+ Args:
119
+ messages (List[OpenAIMessage]): Message list with the chat history
120
+ in OpenAI API format.
121
+ response_format (Optional[Type[BaseModel]]): The format of the
122
+ response.
123
+ tools (Optional[List[Dict[str, Any]]]): The schema of the tools to
124
+ use for the request.
125
+
126
+ Returns:
127
+ Dict[str, Any]: The prepared request configuration.
128
+ """
129
+ import copy
130
+
131
+ request_config = copy.deepcopy(self.model_config_dict)
132
+
133
+ if tools:
134
+ request_config["tools"] = tools
135
+ elif response_format:
136
+ # Use the same approach as DeepSeek for structured output
137
+ try_modify_message_with_format(messages[-1], response_format)
138
+ request_config["response_format"] = {"type": "json_object"}
139
+
140
+ return request_config
141
+
109
142
  @observe()
110
143
  async def _arun(
111
144
  self,
@@ -141,10 +174,9 @@ class MoonshotModel(OpenAICompatibleModel):
141
174
  tags=["CAMEL-AI", str(self.model_type)],
142
175
  )
143
176
 
144
- request_config = self.model_config_dict.copy()
145
-
146
- if tools:
147
- request_config["tools"] = tools
177
+ request_config = self._prepare_request(
178
+ messages, response_format, tools
179
+ )
148
180
 
149
181
  return await self._async_client.chat.completions.create(
150
182
  messages=messages,
@@ -1721,23 +1721,51 @@ class Workforce(BaseNode):
1721
1721
 
1722
1722
  def _get_child_nodes_info(self) -> str:
1723
1723
  r"""Get the information of all the child nodes under this node."""
1724
- info = ""
1725
- for child in self._children:
1726
- if isinstance(child, Workforce):
1727
- additional_info = "A Workforce node"
1728
- elif isinstance(child, SingleAgentWorker):
1729
- additional_info = "tools: " + (
1730
- ", ".join(child.worker.tool_dict.keys())
1731
- )
1732
- elif isinstance(child, RolePlayingWorker):
1733
- additional_info = "A Role playing node"
1724
+ return "".join(
1725
+ f"<{child.node_id}>:<{child.description}>:<{self._get_node_info(child)}>\n"
1726
+ for child in self._children
1727
+ )
1728
+
1729
+ def _get_node_info(self, node) -> str:
1730
+ r"""Get descriptive information for a specific node type."""
1731
+ if isinstance(node, Workforce):
1732
+ return "A Workforce node"
1733
+ elif isinstance(node, SingleAgentWorker):
1734
+ return self._get_single_agent_info(node)
1735
+ elif isinstance(node, RolePlayingWorker):
1736
+ return "A Role playing node"
1737
+ else:
1738
+ return "Unknown node"
1739
+
1740
+ def _get_single_agent_info(self, worker: 'SingleAgentWorker') -> str:
1741
+ r"""Get formatted information for a SingleAgentWorker node."""
1742
+ toolkit_tools = self._group_tools_by_toolkit(worker.worker.tool_dict)
1743
+
1744
+ if not toolkit_tools:
1745
+ return "no tools available"
1746
+
1747
+ toolkit_info = []
1748
+ for toolkit_name, tools in sorted(toolkit_tools.items()):
1749
+ tools_str = ', '.join(sorted(tools))
1750
+ toolkit_info.append(f"{toolkit_name}({tools_str})")
1751
+
1752
+ return " | ".join(toolkit_info)
1753
+
1754
+ def _group_tools_by_toolkit(self, tool_dict: dict) -> dict[str, list[str]]:
1755
+ r"""Group tools by their parent toolkit class names."""
1756
+ toolkit_tools: dict[str, list[str]] = {}
1757
+
1758
+ for tool_name, tool in tool_dict.items():
1759
+ if hasattr(tool.func, '__self__'):
1760
+ toolkit_name = tool.func.__self__.__class__.__name__
1734
1761
  else:
1735
- additional_info = "Unknown node"
1736
- info += (
1737
- f"<{child.node_id}>:<{child.description}>:<"
1738
- f"{additional_info}>\n"
1739
- )
1740
- return info
1762
+ toolkit_name = "Standalone"
1763
+
1764
+ if toolkit_name not in toolkit_tools:
1765
+ toolkit_tools[toolkit_name] = []
1766
+ toolkit_tools[toolkit_name].append(tool_name)
1767
+
1768
+ return toolkit_tools
1741
1769
 
1742
1770
  def _get_valid_worker_ids(self) -> set:
1743
1771
  r"""Get all valid worker IDs from child nodes.
@@ -434,23 +434,37 @@ class SearchToolkit(BaseToolkit):
434
434
  (None, 'SEARCH_ENGINE_ID'),
435
435
  ]
436
436
  )
437
- def search_google(self, query: str) -> List[Dict[str, Any]]:
437
+ def search_google(
438
+ self, query: str, search_type: str = "web"
439
+ ) -> List[Dict[str, Any]]:
438
440
  r"""Use Google search engine to search information for the given query.
439
441
 
440
442
  Args:
441
443
  query (str): The query to be searched.
444
+ search_type (str): The type of search to perform. Either "web" for
445
+ web pages or "image" for image search. (default: "web")
442
446
 
443
447
  Returns:
444
448
  List[Dict[str, Any]]: A list of dictionaries where each dictionary
445
- represents a website.
446
- Each dictionary contains the following keys:
449
+ represents a search result.
450
+
451
+ For web search, each dictionary contains:
447
452
  - 'result_id': A number in order.
448
453
  - 'title': The title of the website.
449
454
  - 'description': A brief description of the website.
450
455
  - 'long_description': More detail of the website.
451
456
  - 'url': The URL of the website.
452
457
 
453
- Example:
458
+ For image search, each dictionary contains:
459
+ - 'result_id': A number in order.
460
+ - 'title': The title of the image.
461
+ - 'image_url': The URL of the image.
462
+ - 'display_link': The website hosting the image.
463
+ - 'context_url': The URL of the page containing the image.
464
+ - 'width': Image width in pixels (if available).
465
+ - 'height': Image height in pixels (if available).
466
+
467
+ Example web result:
454
468
  {
455
469
  'result_id': 1,
456
470
  'title': 'OpenAI',
@@ -462,7 +476,17 @@ class SearchToolkit(BaseToolkit):
462
476
  benefit humanity as a whole',
463
477
  'url': 'https://www.openai.com'
464
478
  }
465
- title, description, url of a website.
479
+
480
+ Example image result:
481
+ {
482
+ 'result_id': 1,
483
+ 'title': 'Beautiful Sunset',
484
+ 'image_url': 'https://example.com/image.jpg',
485
+ 'display_link': 'example.com',
486
+ 'context_url': 'https://example.com/page.html',
487
+ 'width': 800,
488
+ 'height': 600
489
+ }
466
490
  """
467
491
  import requests
468
492
 
@@ -477,12 +501,18 @@ class SearchToolkit(BaseToolkit):
477
501
  search_language = "en"
478
502
  # Constructing the URL
479
503
  # Doc: https://developers.google.com/custom-search/v1/using_rest
480
- url = (
504
+ base_url = (
481
505
  f"https://www.googleapis.com/customsearch/v1?"
482
506
  f"key={GOOGLE_API_KEY}&cx={SEARCH_ENGINE_ID}&q={query}&start="
483
507
  f"{start_page_idx}&lr={search_language}&num={self.number_of_result_pages}"
484
508
  )
485
509
 
510
+ # Add searchType parameter for image search
511
+ if search_type == "image":
512
+ url = base_url + "&searchType=image"
513
+ else:
514
+ url = base_url
515
+
486
516
  responses = []
487
517
  # Fetch the results given the URL
488
518
  try:
@@ -494,37 +524,68 @@ class SearchToolkit(BaseToolkit):
494
524
  if "items" in data:
495
525
  search_items = data.get("items")
496
526
 
497
- # Iterate over 10 results found
527
+ # Iterate over results found
498
528
  for i, search_item in enumerate(search_items, start=1):
499
- # Check metatags are present
500
- if "pagemap" not in search_item:
501
- continue
502
- if "metatags" not in search_item["pagemap"]:
503
- continue
504
- if (
505
- "og:description"
506
- in search_item["pagemap"]["metatags"][0]
507
- ):
508
- long_description = search_item["pagemap"]["metatags"][
509
- 0
510
- ]["og:description"]
529
+ if search_type == "image":
530
+ # Process image search results
531
+ title = search_item.get("title")
532
+ image_url = search_item.get("link")
533
+ display_link = search_item.get("displayLink")
534
+
535
+ # Get context URL (page containing the image)
536
+ image_info = search_item.get("image", {})
537
+ context_url = image_info.get("contextLink", "")
538
+
539
+ # Get image dimensions if available
540
+ width = image_info.get("width")
541
+ height = image_info.get("height")
542
+
543
+ response = {
544
+ "result_id": i,
545
+ "title": title,
546
+ "image_url": image_url,
547
+ "display_link": display_link,
548
+ "context_url": context_url,
549
+ }
550
+
551
+ # Add dimensions if available
552
+ if width:
553
+ response["width"] = int(width)
554
+ if height:
555
+ response["height"] = int(height)
556
+
557
+ responses.append(response)
511
558
  else:
512
- long_description = "N/A"
513
- # Get the page title
514
- title = search_item.get("title")
515
- # Page snippet
516
- snippet = search_item.get("snippet")
517
-
518
- # Extract the page url
519
- link = search_item.get("link")
520
- response = {
521
- "result_id": i,
522
- "title": title,
523
- "description": snippet,
524
- "long_description": long_description,
525
- "url": link,
526
- }
527
- responses.append(response)
559
+ # Process web search results (existing logic)
560
+ # Check metatags are present
561
+ if "pagemap" not in search_item:
562
+ continue
563
+ if "metatags" not in search_item["pagemap"]:
564
+ continue
565
+ if (
566
+ "og:description"
567
+ in search_item["pagemap"]["metatags"][0]
568
+ ):
569
+ long_description = search_item["pagemap"][
570
+ "metatags"
571
+ ][0]["og:description"]
572
+ else:
573
+ long_description = "N/A"
574
+ # Get the page title
575
+ title = search_item.get("title")
576
+ # Page snippet
577
+ snippet = search_item.get("snippet")
578
+
579
+ # Extract the page url
580
+ link = search_item.get("link")
581
+ response = {
582
+ "result_id": i,
583
+ "title": title,
584
+ "description": snippet,
585
+ "long_description": long_description,
586
+ "url": link,
587
+ }
588
+ responses.append(response)
528
589
  else:
529
590
  error_info = data.get("error", {})
530
591
  logger.error(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camel-ai
3
- Version: 0.2.71a12
3
+ Version: 0.2.72a0
4
4
  Summary: Communicative Agents for AI Society Study
5
5
  Project-URL: Homepage, https://www.camel-ai.org/
6
6
  Project-URL: Repository, https://github.com/camel-ai/camel
@@ -1,4 +1,4 @@
1
- camel/__init__.py,sha256=oUT4aFlY7oLE0uiLwy27soTCR0nroQM7pxRzeU3iGKQ,902
1
+ camel/__init__.py,sha256=wLBIcsBrpiqBVm22ZM1QiqPDGdAJarjbYDk7mQbmAiw,901
2
2
  camel/generators.py,sha256=JRqj9_m1PF4qT6UtybzTQ-KBT9MJQt18OAAYvQ_fr2o,13844
3
3
  camel/human.py,sha256=Xg8x1cS5KK4bQ1SDByiHZnzsRpvRP-KZViNvmu38xo4,5475
4
4
  camel/logger.py,sha256=WgEwael_eT6D-lVAKHpKIpwXSTjvLbny5jbV1Ab8lnA,5760
@@ -193,7 +193,7 @@ camel/models/mistral_model.py,sha256=ipOVPk2boGqyGAypgKeQ9syaP0znKFQQSOqeVtockjk
193
193
  camel/models/model_factory.py,sha256=8b-LEXovPnpmD3GFKOdbtcgjCwpa91IPCJxikPxhdMs,12114
194
194
  camel/models/model_manager.py,sha256=ln3bCV_QWM3V5BrwKwjmxIeRN8ojIvPEBMMHun0MliU,9942
195
195
  camel/models/modelscope_model.py,sha256=meO7KCAwZtHpUVgwtuKe0j4jYh0IWsxa8e3mwyhGLvg,10804
196
- camel/models/moonshot_model.py,sha256=BNkKcEPMieMZwClRT4w-D4crZ5Ovs8tLdK5Kxm41hWg,6465
196
+ camel/models/moonshot_model.py,sha256=sghzSd9Ya7AysHYW5gqVSUTThusvwFWFeLRj-6okkLk,7662
197
197
  camel/models/nemotron_model.py,sha256=PzRuQoAEmBRZ2wcotQ8-MRz5wYachKa_CUNenMQg-3U,3091
198
198
  camel/models/netmind_model.py,sha256=YKHfntqsKqBxfh6qryn4L7CzHOIAYtyPXwJNK6NxNi4,4276
199
199
  camel/models/novita_model.py,sha256=V-g0Wrf1Zh1il6oPKh1LVy_U0nveOwJq9YBVzGp4GOI,4238
@@ -280,7 +280,7 @@ camel/societies/workforce/structured_output_handler.py,sha256=xr8szFN86hg3jQ825a
280
280
  camel/societies/workforce/task_channel.py,sha256=GWHaGQBpjTzdKbWoBYAQzzAiLKRKRXa6beqtc4cg-Is,7611
281
281
  camel/societies/workforce/utils.py,sha256=THgNHSeZsNVnjTzQTur3qCJhi72MrDS8X2gPET174cI,8434
282
282
  camel/societies/workforce/worker.py,sha256=MtUqYkTC9V-PIIRwSkKiB9w_YSu92iOpoha2rktEiQ0,6248
283
- camel/societies/workforce/workforce.py,sha256=bu6RAtDRM50C1mu5P6qeAPAsMmKI9bp8082NzYSC11s,139558
283
+ camel/societies/workforce/workforce.py,sha256=kD6j6h81cNjeGQMECDCMIUiS8OSy1nVF7Ef2IDAiea0,140636
284
284
  camel/societies/workforce/workforce_logger.py,sha256=0YT__ys48Bgn0IICKIZBmSWhON-eA1KShebjCdn5ppE,24525
285
285
  camel/storages/__init__.py,sha256=RwpEyvxpMbJzVDZJJygeBg4AzyYMkTjjkfB53hTuqGo,2141
286
286
  camel/storages/graph_storages/__init__.py,sha256=G29BNn651C0WTOpjCl4QnVM-4B9tcNh8DdmsCiONH8Y,948
@@ -366,7 +366,7 @@ camel/toolkits/pulse_mcp_search_toolkit.py,sha256=uLUpm19uC_4xLJow0gGVS9f-5T5EW2
366
366
  camel/toolkits/pyautogui_toolkit.py,sha256=Q810fm8cFvElRory7B74aqS2YV6BOpdRE6jkewoM8xc,16093
367
367
  camel/toolkits/reddit_toolkit.py,sha256=x0XAT1zQJVNHUr1R1HwWCgIlkamU-kPmbfb_H1WIv-w,8036
368
368
  camel/toolkits/retrieval_toolkit.py,sha256=BKjEyOqW3cGEPTS5yHPYb-Qg795iNNPIs1wjowfuq3U,3825
369
- camel/toolkits/search_toolkit.py,sha256=FyIL85qfeTiDCmDD-9H8tnhiRY1ZmnGlkZiW5uRcSR4,44884
369
+ camel/toolkits/search_toolkit.py,sha256=_Gvb-h3BImexrIFHT0BvmdosOuIgR_IZvERPdf190K8,47615
370
370
  camel/toolkits/searxng_toolkit.py,sha256=a2GtE4FGSrmaIVvX6Yide-abBYD1wsHqitnDlx9fdVg,7664
371
371
  camel/toolkits/semantic_scholar_toolkit.py,sha256=Rh7eA_YPxV5pvPIzhjjvpr3vtlaCniJicrqzkPWW9_I,11634
372
372
  camel/toolkits/slack_toolkit.py,sha256=ZT6Ndlce2qjGsyZaNMfQ54nSEi7DOC9Ro7YqtK-u5O4,11651
@@ -446,7 +446,7 @@ camel/verifiers/math_verifier.py,sha256=tA1D4S0sm8nsWISevxSN0hvSVtIUpqmJhzqfbuMo
446
446
  camel/verifiers/models.py,sha256=GdxYPr7UxNrR1577yW4kyroRcLGfd-H1GXgv8potDWU,2471
447
447
  camel/verifiers/physics_verifier.py,sha256=c1grrRddcrVN7szkxhv2QirwY9viIRSITWeWFF5HmLs,30187
448
448
  camel/verifiers/python_verifier.py,sha256=ogTz77wODfEcDN4tMVtiSkRQyoiZbHPY2fKybn59lHw,20558
449
- camel_ai-0.2.71a12.dist-info/METADATA,sha256=mzylMnRqVIeUBQcBvV7jR6CYS3zVtdkOus7lv-_pU9k,49999
450
- camel_ai-0.2.71a12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
451
- camel_ai-0.2.71a12.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
452
- camel_ai-0.2.71a12.dist-info/RECORD,,
449
+ camel_ai-0.2.72a0.dist-info/METADATA,sha256=JsM9sjR0ozHqZrsduo84JEf-3s9a1M2wALAbhI9Fw-Y,49998
450
+ camel_ai-0.2.72a0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
451
+ camel_ai-0.2.72a0.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
452
+ camel_ai-0.2.72a0.dist-info/RECORD,,