camel-ai 0.2.59__py3-none-any.whl → 0.2.82__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 (506) hide show
  1. camel/__init__.py +3 -3
  2. camel/agents/__init__.py +2 -2
  3. camel/agents/_types.py +9 -4
  4. camel/agents/_utils.py +40 -2
  5. camel/agents/base.py +2 -2
  6. camel/agents/chat_agent.py +5012 -902
  7. camel/agents/critic_agent.py +2 -2
  8. camel/agents/deductive_reasoner_agent.py +56 -56
  9. camel/agents/embodied_agent.py +2 -2
  10. camel/agents/knowledge_graph_agent.py +20 -20
  11. camel/agents/mcp_agent.py +39 -36
  12. camel/agents/multi_hop_generator_agent.py +3 -3
  13. camel/agents/programmed_agent_instruction.py +2 -2
  14. camel/agents/repo_agent.py +4 -3
  15. camel/agents/role_assignment_agent.py +2 -2
  16. camel/agents/search_agent.py +2 -2
  17. camel/agents/task_agent.py +2 -2
  18. camel/agents/tool_agents/__init__.py +2 -2
  19. camel/agents/tool_agents/base.py +2 -2
  20. camel/agents/tool_agents/hugging_face_tool_agent.py +3 -3
  21. camel/benchmarks/__init__.py +2 -2
  22. camel/benchmarks/apibank.py +5 -5
  23. camel/benchmarks/apibench.py +2 -2
  24. camel/benchmarks/base.py +2 -2
  25. camel/benchmarks/browsecomp.py +44 -33
  26. camel/benchmarks/gaia.py +17 -13
  27. camel/benchmarks/mock_website/README.md +94 -0
  28. camel/benchmarks/mock_website/mock_web.py +299 -0
  29. camel/benchmarks/mock_website/requirements.txt +3 -0
  30. camel/benchmarks/mock_website/shopping_mall/app.py +465 -0
  31. camel/benchmarks/mock_website/task.json +104 -0
  32. camel/benchmarks/nexus.py +3 -3
  33. camel/benchmarks/ragbench.py +2 -2
  34. camel/bots/__init__.py +2 -2
  35. camel/bots/discord/__init__.py +2 -2
  36. camel/bots/discord/discord_app.py +2 -2
  37. camel/bots/discord/discord_installation.py +2 -2
  38. camel/bots/discord/discord_store.py +3 -3
  39. camel/bots/slack/__init__.py +2 -2
  40. camel/bots/slack/models.py +4 -4
  41. camel/bots/slack/slack_app.py +2 -2
  42. camel/bots/telegram_bot.py +2 -2
  43. camel/configs/__init__.py +26 -2
  44. camel/configs/aihubmix_config.py +90 -0
  45. camel/configs/aiml_config.py +2 -2
  46. camel/configs/amd_config.py +70 -0
  47. camel/configs/anthropic_config.py +8 -7
  48. camel/configs/base_config.py +2 -2
  49. camel/configs/bedrock_config.py +5 -3
  50. camel/configs/cerebras_config.py +98 -0
  51. camel/configs/cohere_config.py +3 -3
  52. camel/configs/cometapi_config.py +106 -0
  53. camel/configs/crynux_config.py +94 -0
  54. camel/configs/deepseek_config.py +9 -8
  55. camel/configs/gemini_config.py +6 -4
  56. camel/configs/groq_config.py +6 -4
  57. camel/configs/internlm_config.py +6 -4
  58. camel/configs/litellm_config.py +2 -2
  59. camel/configs/lmstudio_config.py +6 -4
  60. camel/configs/minimax_config.py +95 -0
  61. camel/configs/mistral_config.py +3 -3
  62. camel/configs/modelscope_config.py +5 -3
  63. camel/configs/moonshot_config.py +2 -2
  64. camel/configs/nebius_config.py +105 -0
  65. camel/configs/netmind_config.py +2 -2
  66. camel/configs/novita_config.py +2 -2
  67. camel/configs/nvidia_config.py +2 -2
  68. camel/configs/ollama_config.py +2 -2
  69. camel/configs/openai_config.py +8 -3
  70. camel/configs/openrouter_config.py +6 -4
  71. camel/configs/ppio_config.py +2 -2
  72. camel/configs/qianfan_config.py +85 -0
  73. camel/configs/qwen_config.py +2 -2
  74. camel/configs/reka_config.py +3 -3
  75. camel/configs/samba_config.py +8 -6
  76. camel/configs/sglang_config.py +2 -2
  77. camel/configs/siliconflow_config.py +2 -2
  78. camel/configs/togetherai_config.py +2 -2
  79. camel/configs/vllm_config.py +4 -2
  80. camel/configs/watsonx_config.py +2 -2
  81. camel/configs/yi_config.py +6 -4
  82. camel/configs/zhipuai_config.py +6 -4
  83. camel/{data_collector → data_collectors}/__init__.py +2 -2
  84. camel/{data_collector → data_collectors}/alpaca_collector.py +19 -10
  85. camel/{data_collector → data_collectors}/base.py +2 -2
  86. camel/{data_collector → data_collectors}/sharegpt_collector.py +3 -3
  87. camel/datagen/__init__.py +2 -2
  88. camel/datagen/cot_datagen.py +32 -37
  89. camel/datagen/evol_instruct/__init__.py +2 -2
  90. camel/datagen/evol_instruct/evol_instruct.py +2 -2
  91. camel/datagen/evol_instruct/scorer.py +24 -25
  92. camel/datagen/evol_instruct/templates.py +48 -48
  93. camel/datagen/self_improving_cot.py +5 -5
  94. camel/datagen/self_instruct/__init__.py +2 -2
  95. camel/datagen/self_instruct/filter/__init__.py +2 -2
  96. camel/datagen/self_instruct/filter/filter_function.py +2 -2
  97. camel/datagen/self_instruct/filter/filter_registry.py +2 -2
  98. camel/datagen/self_instruct/filter/instruction_filter.py +2 -2
  99. camel/datagen/self_instruct/self_instruct.py +2 -2
  100. camel/datagen/self_instruct/templates.py +47 -47
  101. camel/datagen/source2synth/__init__.py +2 -2
  102. camel/datagen/source2synth/data_processor.py +2 -2
  103. camel/datagen/source2synth/models.py +2 -2
  104. camel/datagen/source2synth/user_data_processor_config.py +2 -2
  105. camel/datahubs/__init__.py +2 -2
  106. camel/datahubs/base.py +2 -2
  107. camel/datahubs/huggingface.py +2 -2
  108. camel/datahubs/models.py +2 -2
  109. camel/datasets/__init__.py +2 -2
  110. camel/datasets/base_generator.py +41 -12
  111. camel/datasets/few_shot_generator.py +18 -18
  112. camel/datasets/models.py +3 -3
  113. camel/datasets/self_instruct_generator.py +2 -2
  114. camel/datasets/static_dataset.py +152 -2
  115. camel/embeddings/__init__.py +2 -2
  116. camel/embeddings/azure_embedding.py +2 -2
  117. camel/embeddings/base.py +2 -2
  118. camel/embeddings/gemini_embedding.py +2 -2
  119. camel/embeddings/jina_embedding.py +10 -3
  120. camel/embeddings/mistral_embedding.py +2 -2
  121. camel/embeddings/openai_compatible_embedding.py +2 -2
  122. camel/embeddings/openai_embedding.py +2 -2
  123. camel/embeddings/sentence_transformers_embeddings.py +4 -4
  124. camel/embeddings/together_embedding.py +2 -2
  125. camel/embeddings/vlm_embedding.py +11 -4
  126. camel/environments/__init__.py +14 -2
  127. camel/environments/models.py +2 -2
  128. camel/environments/multi_step.py +2 -2
  129. camel/environments/rlcards_env.py +860 -0
  130. camel/environments/single_step.py +30 -5
  131. camel/environments/tic_tac_toe.py +3 -3
  132. camel/extractors/__init__.py +2 -2
  133. camel/extractors/base.py +2 -2
  134. camel/extractors/python_strategies.py +2 -2
  135. camel/generators.py +2 -2
  136. camel/human.py +2 -2
  137. camel/interpreters/__init__.py +4 -2
  138. camel/interpreters/base.py +16 -3
  139. camel/interpreters/docker/Dockerfile +53 -7
  140. camel/interpreters/docker_interpreter.py +70 -11
  141. camel/interpreters/e2b_interpreter.py +59 -11
  142. camel/interpreters/internal_python_interpreter.py +81 -4
  143. camel/interpreters/interpreter_error.py +2 -2
  144. camel/interpreters/ipython_interpreter.py +23 -5
  145. camel/interpreters/microsandbox_interpreter.py +395 -0
  146. camel/interpreters/subprocess_interpreter.py +36 -4
  147. camel/loaders/__init__.py +17 -5
  148. camel/loaders/apify_reader.py +2 -2
  149. camel/loaders/base_io.py +2 -2
  150. camel/loaders/base_loader.py +85 -0
  151. camel/loaders/chunkr_reader.py +128 -93
  152. camel/loaders/crawl4ai_reader.py +2 -2
  153. camel/loaders/firecrawl_reader.py +6 -6
  154. camel/loaders/jina_url_reader.py +2 -2
  155. camel/loaders/markitdown.py +2 -2
  156. camel/loaders/mineru_extractor.py +2 -2
  157. camel/loaders/mistral_reader.py +148 -0
  158. camel/loaders/scrapegraph_reader.py +2 -2
  159. camel/loaders/unstructured_io.py +2 -2
  160. camel/logger.py +5 -5
  161. camel/memories/__init__.py +2 -2
  162. camel/memories/agent_memories.py +86 -3
  163. camel/memories/base.py +36 -2
  164. camel/memories/blocks/__init__.py +2 -2
  165. camel/memories/blocks/chat_history_block.py +126 -9
  166. camel/memories/blocks/vectordb_block.py +10 -3
  167. camel/memories/context_creators/__init__.py +2 -2
  168. camel/memories/context_creators/score_based.py +31 -239
  169. camel/memories/records.py +98 -13
  170. camel/messages/__init__.py +2 -2
  171. camel/messages/base.py +193 -46
  172. camel/messages/conversion/__init__.py +2 -2
  173. camel/messages/conversion/alpaca.py +2 -2
  174. camel/messages/conversion/conversation_models.py +2 -2
  175. camel/messages/conversion/sharegpt/__init__.py +2 -2
  176. camel/messages/conversion/sharegpt/function_call_formatter.py +2 -2
  177. camel/messages/conversion/sharegpt/hermes/__init__.py +2 -2
  178. camel/messages/conversion/sharegpt/hermes/hermes_function_formatter.py +2 -2
  179. camel/messages/func_message.py +54 -17
  180. camel/models/__init__.py +18 -2
  181. camel/models/_utils.py +3 -3
  182. camel/models/aihubmix_model.py +83 -0
  183. camel/models/aiml_model.py +11 -18
  184. camel/models/amd_model.py +101 -0
  185. camel/models/anthropic_model.py +127 -20
  186. camel/models/aws_bedrock_model.py +12 -35
  187. camel/models/azure_openai_model.py +263 -63
  188. camel/models/base_audio_model.py +5 -3
  189. camel/models/base_model.py +195 -26
  190. camel/models/cerebras_model.py +83 -0
  191. camel/models/cohere_model.py +81 -21
  192. camel/models/cometapi_model.py +83 -0
  193. camel/models/crynux_model.py +87 -0
  194. camel/models/deepseek_model.py +61 -59
  195. camel/models/fish_audio_model.py +8 -2
  196. camel/models/gemini_model.py +439 -30
  197. camel/models/groq_model.py +11 -19
  198. camel/models/internlm_model.py +11 -18
  199. camel/models/litellm_model.py +94 -34
  200. camel/models/lmstudio_model.py +17 -20
  201. camel/models/minimax_model.py +83 -0
  202. camel/models/mistral_model.py +84 -19
  203. camel/models/model_factory.py +49 -6
  204. camel/models/model_manager.py +33 -11
  205. camel/models/modelscope_model.py +13 -193
  206. camel/models/moonshot_model.py +195 -21
  207. camel/models/nebius_model.py +83 -0
  208. camel/models/nemotron_model.py +19 -9
  209. camel/models/netmind_model.py +11 -18
  210. camel/models/novita_model.py +11 -18
  211. camel/models/nvidia_model.py +11 -18
  212. camel/models/ollama_model.py +14 -21
  213. camel/models/openai_audio_models.py +2 -2
  214. camel/models/openai_compatible_model.py +234 -27
  215. camel/models/openai_model.py +255 -39
  216. camel/models/openrouter_model.py +11 -19
  217. camel/models/ppio_model.py +11 -18
  218. camel/models/qianfan_model.py +89 -0
  219. camel/models/qwen_model.py +13 -193
  220. camel/models/reka_model.py +90 -21
  221. camel/models/reward/__init__.py +2 -2
  222. camel/models/reward/base_reward_model.py +2 -2
  223. camel/models/reward/evaluator.py +2 -2
  224. camel/models/reward/nemotron_model.py +2 -2
  225. camel/models/reward/skywork_model.py +2 -2
  226. camel/models/samba_model.py +117 -49
  227. camel/models/sglang_model.py +162 -42
  228. camel/models/siliconflow_model.py +12 -35
  229. camel/models/stub_model.py +10 -7
  230. camel/models/togetherai_model.py +11 -18
  231. camel/models/vllm_model.py +10 -18
  232. camel/models/volcano_model.py +16 -20
  233. camel/models/watsonx_model.py +69 -19
  234. camel/models/yi_model.py +11 -18
  235. camel/models/zhipuai_model.py +70 -18
  236. camel/parsers/__init__.py +18 -0
  237. camel/parsers/mcp_tool_call_parser.py +176 -0
  238. camel/personas/__init__.py +2 -2
  239. camel/personas/persona.py +2 -2
  240. camel/personas/persona_hub.py +2 -2
  241. camel/prompts/__init__.py +2 -2
  242. camel/prompts/ai_society.py +2 -2
  243. camel/prompts/base.py +2 -2
  244. camel/prompts/code.py +2 -2
  245. camel/prompts/evaluation.py +2 -2
  246. camel/prompts/generate_text_embedding_data.py +2 -2
  247. camel/prompts/image_craft.py +2 -2
  248. camel/prompts/misalignment.py +2 -2
  249. camel/prompts/multi_condition_image_craft.py +2 -2
  250. camel/prompts/object_recognition.py +2 -2
  251. camel/prompts/persona_hub.py +3 -3
  252. camel/prompts/prompt_templates.py +2 -2
  253. camel/prompts/role_description_prompt_template.py +2 -2
  254. camel/prompts/solution_extraction.py +8 -8
  255. camel/prompts/task_prompt_template.py +2 -2
  256. camel/prompts/translation.py +2 -2
  257. camel/prompts/video_description_prompt.py +3 -3
  258. camel/responses/__init__.py +2 -2
  259. camel/responses/agent_responses.py +2 -2
  260. camel/retrievers/__init__.py +2 -2
  261. camel/retrievers/auto_retriever.py +23 -3
  262. camel/retrievers/base.py +2 -2
  263. camel/retrievers/bm25_retriever.py +3 -4
  264. camel/retrievers/cohere_rerank_retriever.py +2 -2
  265. camel/retrievers/hybrid_retrival.py +4 -4
  266. camel/retrievers/vector_retriever.py +2 -2
  267. camel/runtimes/Dockerfile.multi-toolkit +90 -0
  268. camel/{runtime → runtimes}/__init__.py +2 -2
  269. camel/runtimes/api.py +153 -0
  270. camel/{runtime → runtimes}/base.py +2 -2
  271. camel/{runtime → runtimes}/configs.py +13 -13
  272. camel/{runtime → runtimes}/daytona_runtime.py +18 -19
  273. camel/{runtime → runtimes}/docker_runtime.py +13 -13
  274. camel/{runtime → runtimes}/llm_guard_runtime.py +28 -28
  275. camel/{runtime → runtimes}/remote_http_runtime.py +12 -12
  276. camel/{runtime → runtimes}/ubuntu_docker_runtime.py +3 -3
  277. camel/{runtime → runtimes}/utils/__init__.py +2 -2
  278. camel/{runtime → runtimes}/utils/function_risk_toolkit.py +2 -2
  279. camel/{runtime → runtimes}/utils/ignore_risk_toolkit.py +2 -2
  280. camel/schemas/__init__.py +2 -2
  281. camel/schemas/base.py +2 -2
  282. camel/schemas/openai_converter.py +3 -3
  283. camel/schemas/outlines_converter.py +2 -2
  284. camel/services/agent_openapi_server.py +380 -0
  285. camel/societies/__init__.py +4 -2
  286. camel/societies/babyagi_playing.py +2 -2
  287. camel/societies/role_playing.py +201 -80
  288. camel/societies/workforce/__init__.py +10 -3
  289. camel/societies/workforce/base.py +9 -5
  290. camel/societies/workforce/events.py +143 -0
  291. camel/societies/workforce/prompts.py +258 -33
  292. camel/societies/workforce/role_playing_worker.py +95 -30
  293. camel/societies/workforce/single_agent_worker.py +659 -30
  294. camel/societies/workforce/structured_output_handler.py +512 -0
  295. camel/societies/workforce/task_channel.py +182 -38
  296. camel/societies/workforce/utils.py +784 -18
  297. camel/societies/workforce/worker.py +96 -28
  298. camel/societies/workforce/workflow_memory_manager.py +1746 -0
  299. camel/societies/workforce/workforce.py +5730 -366
  300. camel/societies/workforce/workforce_callback.py +103 -0
  301. camel/societies/workforce/workforce_logger.py +647 -0
  302. camel/societies/workforce/workforce_metrics.py +33 -0
  303. camel/storages/__init__.py +10 -2
  304. camel/storages/graph_storages/__init__.py +2 -2
  305. camel/storages/graph_storages/base.py +2 -2
  306. camel/storages/graph_storages/graph_element.py +2 -2
  307. camel/storages/graph_storages/nebula_graph.py +4 -4
  308. camel/storages/graph_storages/neo4j_graph.py +7 -7
  309. camel/storages/key_value_storages/__init__.py +2 -2
  310. camel/storages/key_value_storages/base.py +2 -2
  311. camel/storages/key_value_storages/in_memory.py +2 -2
  312. camel/storages/key_value_storages/json.py +17 -4
  313. camel/storages/key_value_storages/mem0_cloud.py +50 -49
  314. camel/storages/key_value_storages/redis.py +2 -2
  315. camel/storages/object_storages/__init__.py +2 -2
  316. camel/storages/object_storages/amazon_s3.py +2 -2
  317. camel/storages/object_storages/azure_blob.py +2 -2
  318. camel/storages/object_storages/base.py +2 -2
  319. camel/storages/object_storages/google_cloud.py +3 -3
  320. camel/storages/vectordb_storages/__init__.py +12 -2
  321. camel/storages/vectordb_storages/base.py +2 -2
  322. camel/storages/vectordb_storages/chroma.py +731 -0
  323. camel/storages/vectordb_storages/faiss.py +712 -0
  324. camel/storages/vectordb_storages/milvus.py +2 -2
  325. camel/storages/vectordb_storages/oceanbase.py +16 -17
  326. camel/storages/vectordb_storages/pgvector.py +349 -0
  327. camel/storages/vectordb_storages/qdrant.py +6 -6
  328. camel/storages/vectordb_storages/surreal.py +372 -0
  329. camel/storages/vectordb_storages/tidb.py +11 -8
  330. camel/storages/vectordb_storages/weaviate.py +714 -0
  331. camel/tasks/__init__.py +2 -2
  332. camel/tasks/task.py +366 -27
  333. camel/tasks/task_prompt.py +3 -3
  334. camel/terminators/__init__.py +2 -2
  335. camel/terminators/base.py +2 -2
  336. camel/terminators/response_terminator.py +2 -2
  337. camel/terminators/token_limit_terminator.py +2 -2
  338. camel/toolkits/__init__.py +58 -10
  339. camel/toolkits/aci_toolkit.py +66 -21
  340. camel/toolkits/arxiv_toolkit.py +8 -8
  341. camel/toolkits/ask_news_toolkit.py +2 -2
  342. camel/toolkits/async_browser_toolkit.py +174 -575
  343. camel/toolkits/audio_analysis_toolkit.py +3 -3
  344. camel/toolkits/base.py +65 -7
  345. camel/toolkits/bohrium_toolkit.py +318 -0
  346. camel/toolkits/browser_toolkit.py +306 -566
  347. camel/toolkits/browser_toolkit_commons.py +568 -0
  348. camel/toolkits/code_execution.py +67 -11
  349. camel/toolkits/context_summarizer_toolkit.py +684 -0
  350. camel/toolkits/craw4ai_toolkit.py +93 -0
  351. camel/toolkits/dappier_toolkit.py +12 -8
  352. camel/toolkits/data_commons_toolkit.py +2 -2
  353. camel/toolkits/dingtalk.py +1135 -0
  354. camel/toolkits/earth_science_toolkit.py +5367 -0
  355. camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
  356. camel/toolkits/excel_toolkit.py +910 -70
  357. camel/toolkits/file_toolkit.py +1402 -0
  358. camel/toolkits/function_tool.py +128 -20
  359. camel/toolkits/github_toolkit.py +148 -43
  360. camel/toolkits/gmail_toolkit.py +1839 -0
  361. camel/toolkits/google_calendar_toolkit.py +40 -6
  362. camel/toolkits/google_drive_mcp_toolkit.py +54 -0
  363. camel/toolkits/google_maps_toolkit.py +2 -2
  364. camel/toolkits/google_scholar_toolkit.py +2 -2
  365. camel/toolkits/human_toolkit.py +36 -12
  366. camel/toolkits/hybrid_browser_toolkit/__init__.py +18 -0
  367. camel/toolkits/hybrid_browser_toolkit/config_loader.py +185 -0
  368. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +246 -0
  369. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +1973 -0
  370. camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
  371. camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +4589 -0
  372. camel/toolkits/hybrid_browser_toolkit/ts/package.json +33 -0
  373. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
  374. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1929 -0
  375. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
  376. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +589 -0
  377. camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
  378. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  379. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  380. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  381. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +129 -0
  382. camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +27 -0
  383. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +319 -0
  384. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1037 -0
  385. camel/toolkits/hybrid_browser_toolkit_py/__init__.py +17 -0
  386. camel/toolkits/hybrid_browser_toolkit_py/actions.py +575 -0
  387. camel/toolkits/hybrid_browser_toolkit_py/agent.py +311 -0
  388. camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +787 -0
  389. camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +490 -0
  390. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +2390 -0
  391. camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +233 -0
  392. camel/toolkits/hybrid_browser_toolkit_py/stealth_script.js +0 -0
  393. camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +1043 -0
  394. camel/toolkits/image_analysis_toolkit.py +3 -3
  395. camel/toolkits/image_generation_toolkit.py +390 -0
  396. camel/toolkits/jina_reranker_toolkit.py +195 -79
  397. camel/toolkits/klavis_toolkit.py +7 -3
  398. camel/toolkits/linkedin_toolkit.py +2 -2
  399. camel/toolkits/markitdown_toolkit.py +104 -0
  400. camel/toolkits/math_toolkit.py +66 -12
  401. camel/toolkits/mcp_toolkit.py +841 -600
  402. camel/toolkits/memory_toolkit.py +7 -3
  403. camel/toolkits/meshy_toolkit.py +2 -2
  404. camel/toolkits/message_agent_toolkit.py +608 -0
  405. camel/toolkits/message_integration.py +724 -0
  406. camel/toolkits/mineru_toolkit.py +2 -2
  407. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  408. camel/toolkits/networkx_toolkit.py +2 -2
  409. camel/toolkits/note_taking_toolkit.py +277 -0
  410. camel/toolkits/notion_mcp_toolkit.py +224 -0
  411. camel/toolkits/notion_toolkit.py +2 -2
  412. camel/toolkits/open_api_specs/biztoc/__init__.py +2 -2
  413. camel/toolkits/open_api_specs/biztoc/ai-plugin.json +1 -1
  414. camel/toolkits/open_api_specs/coursera/__init__.py +2 -2
  415. camel/toolkits/open_api_specs/create_qr_code/__init__.py +2 -2
  416. camel/toolkits/open_api_specs/klarna/__init__.py +2 -2
  417. camel/toolkits/open_api_specs/nasa_apod/__init__.py +2 -2
  418. camel/toolkits/open_api_specs/outschool/__init__.py +2 -2
  419. camel/toolkits/open_api_specs/outschool/ai-plugin.json +1 -1
  420. camel/toolkits/open_api_specs/outschool/openapi.yaml +1 -1
  421. camel/toolkits/open_api_specs/outschool/paths/__init__.py +2 -2
  422. camel/toolkits/open_api_specs/outschool/paths/get_classes.py +2 -2
  423. camel/toolkits/open_api_specs/outschool/paths/search_teachers.py +2 -2
  424. camel/toolkits/open_api_specs/security_config.py +2 -2
  425. camel/toolkits/open_api_specs/speak/__init__.py +2 -2
  426. camel/toolkits/open_api_specs/web_scraper/__init__.py +2 -2
  427. camel/toolkits/open_api_specs/web_scraper/ai-plugin.json +1 -1
  428. camel/toolkits/open_api_specs/web_scraper/paths/__init__.py +2 -2
  429. camel/toolkits/open_api_specs/web_scraper/paths/scraper.py +2 -2
  430. camel/toolkits/open_api_toolkit.py +2 -2
  431. camel/toolkits/openbb_toolkit.py +7 -3
  432. camel/toolkits/origene_mcp_toolkit.py +56 -0
  433. camel/toolkits/page_script.js +86 -74
  434. camel/toolkits/playwright_mcp_toolkit.py +27 -32
  435. camel/toolkits/pptx_toolkit.py +790 -0
  436. camel/toolkits/pubmed_toolkit.py +2 -2
  437. camel/toolkits/pulse_mcp_search_toolkit.py +2 -2
  438. camel/toolkits/pyautogui_toolkit.py +2 -2
  439. camel/toolkits/reddit_toolkit.py +2 -2
  440. camel/toolkits/resend_toolkit.py +168 -0
  441. camel/toolkits/retrieval_toolkit.py +2 -2
  442. camel/toolkits/screenshot_toolkit.py +213 -0
  443. camel/toolkits/search_toolkit.py +539 -146
  444. camel/toolkits/searxng_toolkit.py +2 -2
  445. camel/toolkits/semantic_scholar_toolkit.py +2 -2
  446. camel/toolkits/slack_toolkit.py +108 -58
  447. camel/toolkits/sql_toolkit.py +712 -0
  448. camel/toolkits/stripe_toolkit.py +2 -2
  449. camel/toolkits/sympy_toolkit.py +3 -3
  450. camel/toolkits/task_planning_toolkit.py +134 -0
  451. camel/toolkits/terminal_toolkit/__init__.py +18 -0
  452. camel/toolkits/terminal_toolkit/terminal_toolkit.py +1070 -0
  453. camel/toolkits/terminal_toolkit/utils.py +532 -0
  454. camel/toolkits/thinking_toolkit.py +3 -3
  455. camel/toolkits/twitter_toolkit.py +8 -3
  456. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  457. camel/toolkits/video_analysis_toolkit.py +112 -29
  458. camel/toolkits/video_download_toolkit.py +22 -16
  459. camel/toolkits/weather_toolkit.py +2 -2
  460. camel/toolkits/web_deploy_toolkit.py +1219 -0
  461. camel/toolkits/wechat_official_toolkit.py +483 -0
  462. camel/toolkits/whatsapp_toolkit.py +2 -2
  463. camel/toolkits/wolfram_alpha_toolkit.py +53 -25
  464. camel/toolkits/zapier_toolkit.py +7 -3
  465. camel/types/__init__.py +4 -4
  466. camel/types/agents/__init__.py +2 -2
  467. camel/types/agents/tool_calling_record.py +6 -3
  468. camel/types/enums.py +454 -35
  469. camel/types/mcp_registries.py +2 -2
  470. camel/types/openai_types.py +4 -4
  471. camel/types/unified_model_type.py +43 -6
  472. camel/utils/__init__.py +20 -2
  473. camel/utils/async_func.py +2 -2
  474. camel/utils/chunker/__init__.py +2 -2
  475. camel/utils/chunker/base.py +2 -2
  476. camel/utils/chunker/code_chunker.py +2 -2
  477. camel/utils/chunker/uio_chunker.py +2 -2
  478. camel/utils/commons.py +65 -7
  479. camel/utils/constants.py +5 -2
  480. camel/utils/context_utils.py +1134 -0
  481. camel/utils/deduplication.py +2 -2
  482. camel/utils/filename.py +2 -2
  483. camel/utils/langfuse.py +258 -0
  484. camel/utils/mcp.py +140 -6
  485. camel/utils/mcp_client.py +1056 -0
  486. camel/utils/message_summarizer.py +148 -0
  487. camel/utils/response_format.py +2 -2
  488. camel/utils/token_counting.py +45 -22
  489. camel/utils/tool_result.py +44 -0
  490. camel/verifiers/__init__.py +2 -2
  491. camel/verifiers/base.py +2 -2
  492. camel/verifiers/math_verifier.py +2 -2
  493. camel/verifiers/models.py +2 -2
  494. camel/verifiers/physics_verifier.py +2 -2
  495. camel/verifiers/python_verifier.py +2 -2
  496. {camel_ai-0.2.59.dist-info → camel_ai-0.2.82.dist-info}/METADATA +349 -108
  497. camel_ai-0.2.82.dist-info/RECORD +507 -0
  498. {camel_ai-0.2.59.dist-info → camel_ai-0.2.82.dist-info}/WHEEL +1 -1
  499. {camel_ai-0.2.59.dist-info → camel_ai-0.2.82.dist-info}/licenses/LICENSE +1 -1
  500. camel/loaders/pandas_reader.py +0 -368
  501. camel/runtime/api.py +0 -97
  502. camel/toolkits/dalle_toolkit.py +0 -171
  503. camel/toolkits/file_write_toolkit.py +0 -395
  504. camel/toolkits/openai_agent_toolkit.py +0 -135
  505. camel/toolkits/terminal_toolkit.py +0 -1037
  506. camel_ai-0.2.59.dist-info/RECORD +0 -410
@@ -1,4 +1,4 @@
1
- # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
1
+ # ========= Copyright 2023-2025 @ CAMEL-AI.org. All Rights Reserved. =========
2
2
  # Licensed under the Apache License, Version 2.0 (the "License");
3
3
  # you may not use this file except in compliance with the License.
4
4
  # You may obtain a copy of the License at
@@ -10,20 +10,178 @@
10
10
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  # See the License for the specific language governing permissions and
12
12
  # limitations under the License.
13
- # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
13
+ # ========= Copyright 2023-2025 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
  from __future__ import annotations
15
15
 
16
- import json
17
- from typing import Any, List
16
+ import asyncio
17
+ import datetime
18
+ import time
19
+ from collections import deque
20
+ from typing import Any, Dict, List, Optional
18
21
 
19
22
  from colorama import Fore
20
23
 
21
24
  from camel.agents import ChatAgent
25
+ from camel.agents.chat_agent import AsyncStreamingChatAgentResponse
26
+ from camel.logger import get_logger
22
27
  from camel.societies.workforce.prompts import PROCESS_TASK_PROMPT
28
+ from camel.societies.workforce.structured_output_handler import (
29
+ StructuredOutputHandler,
30
+ )
23
31
  from camel.societies.workforce.utils import TaskResult
24
32
  from camel.societies.workforce.worker import Worker
25
- from camel.tasks.task import Task, TaskState
26
- from camel.utils import print_text_animated
33
+ from camel.societies.workforce.workflow_memory_manager import (
34
+ WorkflowMemoryManager,
35
+ )
36
+ from camel.tasks.task import Task, TaskState, is_task_result_insufficient
37
+ from camel.utils.context_utils import ContextUtility
38
+
39
+ logger = get_logger(__name__)
40
+
41
+
42
+ class AgentPool:
43
+ r"""A pool of agent instances for efficient reuse.
44
+
45
+ This pool manages a collection of pre-cloned agents with automatic
46
+ scaling and idle timeout cleanup.
47
+
48
+ Args:
49
+ base_agent (ChatAgent): The base agent to clone from.
50
+ initial_size (int): Initial number of agents in the pool.
51
+ (default: :obj:`1`)
52
+ max_size (int): Maximum number of agents in the pool.
53
+ (default: :obj:`10`)
54
+ auto_scale (bool): Whether to automatically scale the pool size.
55
+ (default: :obj:`True`)
56
+ idle_timeout (float): Time in seconds after which idle agents are
57
+ removed. (default: :obj:`180.0`)
58
+ cleanup_interval (float): Fixed interval in seconds between cleanup
59
+ checks. (default: :obj:`60.0`)
60
+ """
61
+
62
+ def __init__(
63
+ self,
64
+ base_agent: ChatAgent,
65
+ initial_size: int = 1,
66
+ max_size: int = 10,
67
+ auto_scale: bool = True,
68
+ idle_timeout: float = 180.0,
69
+ cleanup_interval: float = 60.0,
70
+ ):
71
+ self.base_agent = base_agent
72
+ self.max_size = max_size
73
+ self.auto_scale = auto_scale
74
+ self.idle_timeout = idle_timeout
75
+ self.cleanup_interval = cleanup_interval
76
+
77
+ # Pool management
78
+ self._available_agents: deque = deque()
79
+ self._in_use_agents: set = set()
80
+ self._agent_last_used: dict = {}
81
+ self._lock = asyncio.Lock()
82
+ self._condition = asyncio.Condition(self._lock)
83
+
84
+ # Statistics
85
+ self._total_borrows = 0
86
+ self._total_clones_created = 0
87
+ self._pool_hits = 0
88
+ self._agents_cleaned = 0
89
+
90
+ # Initialize pool
91
+ self._initialize_pool(initial_size)
92
+
93
+ def _initialize_pool(self, size: int) -> None:
94
+ r"""Initialize the pool with the specified number of agents."""
95
+ for _ in range(min(size, self.max_size)):
96
+ agent = self._create_fresh_agent()
97
+ self._available_agents.append(agent)
98
+ self._agent_last_used[id(agent)] = time.time()
99
+
100
+ def _create_fresh_agent(self) -> ChatAgent:
101
+ r"""Create a fresh agent instance."""
102
+ agent = self.base_agent.clone(with_memory=False)
103
+ self._total_clones_created += 1
104
+ return agent
105
+
106
+ async def get_agent(self) -> ChatAgent:
107
+ r"""Get an agent from the pool, creating one if necessary."""
108
+ async with self._condition:
109
+ self._total_borrows += 1
110
+
111
+ # Try to get available agent or create new one
112
+ while True:
113
+ if self._available_agents:
114
+ agent = self._available_agents.popleft()
115
+ self._in_use_agents.add(id(agent))
116
+ self._pool_hits += 1
117
+ return agent
118
+
119
+ # Check if we can create a new agent
120
+ if len(self._in_use_agents) < self.max_size or self.auto_scale:
121
+ agent = self._create_fresh_agent()
122
+ self._in_use_agents.add(id(agent))
123
+ return agent
124
+
125
+ # Wait for an agent to be returned
126
+ await self._condition.wait()
127
+
128
+ async def return_agent(self, agent: ChatAgent) -> None:
129
+ r"""Return an agent to the pool."""
130
+ agent_id = id(agent)
131
+
132
+ async with self._condition:
133
+ if agent_id not in self._in_use_agents:
134
+ return
135
+
136
+ self._in_use_agents.discard(agent_id)
137
+
138
+ # Only add back to pool if under max size
139
+ if len(self._available_agents) < self.max_size:
140
+ agent.reset()
141
+ self._agent_last_used[agent_id] = time.time()
142
+ self._available_agents.append(agent)
143
+ # Notify one waiting coroutine that an agent is available
144
+ self._condition.notify()
145
+ else:
146
+ # Remove tracking for agents not returned to pool
147
+ self._agent_last_used.pop(agent_id, None)
148
+
149
+ async def cleanup_idle_agents(self) -> None:
150
+ r"""Remove idle agents from the pool to free memory."""
151
+ if not self.auto_scale:
152
+ return
153
+
154
+ async with self._condition:
155
+ if not self._available_agents:
156
+ return
157
+
158
+ current_time = time.time()
159
+ agents_to_remove = []
160
+
161
+ for agent in list(self._available_agents):
162
+ agent_id = id(agent)
163
+ last_used = self._agent_last_used.get(agent_id, current_time)
164
+ if current_time - last_used > self.idle_timeout:
165
+ agents_to_remove.append(agent)
166
+
167
+ for agent in agents_to_remove:
168
+ self._available_agents.remove(agent)
169
+ self._agent_last_used.pop(id(agent), None)
170
+ self._agents_cleaned += 1
171
+
172
+ def get_stats(self) -> dict:
173
+ r"""Get pool statistics."""
174
+ return {
175
+ "available_agents": len(self._available_agents),
176
+ "in_use_agents": len(self._in_use_agents),
177
+ "pool_size": len(self._available_agents)
178
+ + len(self._in_use_agents),
179
+ "total_borrows": self._total_borrows,
180
+ "total_clones_created": self._total_clones_created,
181
+ "pool_hits": self._pool_hits,
182
+ "hit_rate": self._pool_hits / max(self._total_borrows, 1),
183
+ "agents_cleaned_up": self._agents_cleaned,
184
+ }
27
185
 
28
186
 
29
187
  class SingleAgentWorker(Worker):
@@ -32,29 +190,159 @@ class SingleAgentWorker(Worker):
32
190
  Args:
33
191
  description (str): Description of the node.
34
192
  worker (ChatAgent): Worker of the node. A single agent.
193
+ use_agent_pool (bool): Whether to use agent pool for efficiency.
194
+ (default: :obj:`True`)
195
+ pool_initial_size (int): Initial size of the agent pool.
196
+ (default: :obj:`1`)
197
+ pool_max_size (int): Maximum size of the agent pool.
198
+ (default: :obj:`10`)
199
+ auto_scale_pool (bool): Whether to auto-scale the agent pool.
200
+ (default: :obj:`True`)
201
+ use_structured_output_handler (bool, optional): Whether to use the
202
+ structured output handler instead of native structured output.
203
+ When enabled, the workforce will use prompts with structured
204
+ output instructions and regex extraction to parse responses.
205
+ This ensures compatibility with agents that don't reliably
206
+ support native structured output. When disabled, the workforce
207
+ uses the native response_format parameter.
208
+ (default: :obj:`True`)
209
+ context_utility (ContextUtility, optional): Shared context utility
210
+ instance for workflow management. If provided, all workflow
211
+ operations will use this shared instance instead of creating
212
+ a new one. This ensures multiple workers share the same session
213
+ directory. (default: :obj:`None`)
214
+ enable_workflow_memory (bool, optional): Whether to enable workflow
215
+ memory accumulation during task execution. When enabled,
216
+ conversations from all task executions are accumulated for
217
+ potential workflow saving. Set to True if you plan to call
218
+ save_workflow_memories(). (default: :obj:`False`)
35
219
  """
36
220
 
37
221
  def __init__(
38
222
  self,
39
223
  description: str,
40
224
  worker: ChatAgent,
225
+ use_agent_pool: bool = True,
226
+ pool_initial_size: int = 1,
227
+ pool_max_size: int = 10,
228
+ auto_scale_pool: bool = True,
229
+ use_structured_output_handler: bool = True,
230
+ context_utility: Optional[ContextUtility] = None,
231
+ enable_workflow_memory: bool = False,
41
232
  ) -> None:
42
- super().__init__(description)
233
+ node_id = worker.agent_id
234
+ super().__init__(
235
+ description,
236
+ node_id=node_id,
237
+ )
238
+ self.use_structured_output_handler = use_structured_output_handler
239
+ self.structured_handler = (
240
+ StructuredOutputHandler()
241
+ if use_structured_output_handler
242
+ else None
243
+ )
43
244
  self.worker = worker
245
+ self.use_agent_pool = use_agent_pool
246
+ self.enable_workflow_memory = enable_workflow_memory
247
+ self._shared_context_utility = context_utility
248
+ self._context_utility: Optional[ContextUtility] = (
249
+ None # Will be initialized when needed
250
+ )
251
+
252
+ # accumulator agent for collecting conversations
253
+ # from all task processing
254
+ self._conversation_accumulator: Optional[ChatAgent] = None
255
+
256
+ # workflow memory manager for handling workflow operations
257
+ self._workflow_manager: Optional[WorkflowMemoryManager] = None
258
+
259
+ # note: context utility is set on the worker agent during save/load
260
+ # operations to avoid creating session folders during initialization
261
+
262
+ self.agent_pool: Optional[AgentPool] = None
263
+ self._cleanup_task: Optional[asyncio.Task] = None
264
+ # Initialize agent pool if enabled
265
+ if self.use_agent_pool:
266
+ self.agent_pool = AgentPool(
267
+ base_agent=worker,
268
+ initial_size=pool_initial_size,
269
+ max_size=pool_max_size,
270
+ auto_scale=auto_scale_pool,
271
+ )
44
272
 
45
273
  def reset(self) -> Any:
46
274
  r"""Resets the worker to its initial state."""
47
275
  super().reset()
48
276
  self.worker.reset()
49
277
 
278
+ # Reset agent pool if it exists
279
+ if self.agent_pool:
280
+ # Stop cleanup task
281
+ if self._cleanup_task and not self._cleanup_task.done():
282
+ self._cleanup_task.cancel()
283
+
284
+ # Reinitialize pool
285
+ self.agent_pool = AgentPool(
286
+ base_agent=self.worker,
287
+ )
288
+
289
+ async def _get_worker_agent(self) -> ChatAgent:
290
+ r"""Get a worker agent, either from pool or by cloning."""
291
+ if self.use_agent_pool and self.agent_pool:
292
+ return await self.agent_pool.get_agent()
293
+ else:
294
+ # Fallback to original cloning approach
295
+ return self.worker.clone(with_memory=False)
296
+
297
+ async def _return_worker_agent(self, agent: ChatAgent) -> None:
298
+ r"""Return a worker agent to the pool if pooling is enabled."""
299
+ if self.use_agent_pool and self.agent_pool:
300
+ await self.agent_pool.return_agent(agent)
301
+ # If not using pool, agent will be garbage collected
302
+
303
+ def _get_context_utility(self) -> ContextUtility:
304
+ r"""Get context utility with lazy initialization."""
305
+ if self._context_utility is None:
306
+ self._context_utility = (
307
+ self._shared_context_utility
308
+ or ContextUtility.get_workforce_shared()
309
+ )
310
+ return self._context_utility
311
+
312
+ def _get_conversation_accumulator(self) -> ChatAgent:
313
+ r"""Get or create the conversation accumulator agent."""
314
+ if self._conversation_accumulator is None:
315
+ # create a clone of the original worker to serve as accumulator
316
+ self._conversation_accumulator = self.worker.clone(
317
+ with_memory=False
318
+ )
319
+ return self._conversation_accumulator
320
+
321
+ def _get_workflow_manager(self) -> WorkflowMemoryManager:
322
+ r"""Get or create the workflow memory manager."""
323
+ if self._workflow_manager is None:
324
+ context_util = (
325
+ self._shared_context_utility
326
+ if self._shared_context_utility is not None
327
+ else None
328
+ )
329
+ self._workflow_manager = WorkflowMemoryManager(
330
+ worker=self.worker,
331
+ description=self.description,
332
+ context_utility=context_util,
333
+ )
334
+ return self._workflow_manager
335
+
50
336
  async def _process_task(
51
337
  self, task: Task, dependencies: List[Task]
52
338
  ) -> TaskState:
53
- r"""Processes a task with its dependencies.
339
+ r"""Processes a task with its dependencies using an efficient agent
340
+ management system.
54
341
 
55
342
  This method asynchronously processes a given task, considering its
56
- dependencies, by sending a generated prompt to a worker. It updates
57
- the task's result based on the agent's response.
343
+ dependencies, by sending a generated prompt to a worker agent.
344
+ Uses an agent pool for efficiency when enabled, or falls back to
345
+ cloning when pool is disabled.
58
346
 
59
347
  Args:
60
348
  task (Task): The task to process, which includes necessary details
@@ -65,36 +353,377 @@ class SingleAgentWorker(Worker):
65
353
  TaskState: `TaskState.DONE` if processed successfully, otherwise
66
354
  `TaskState.FAILED`.
67
355
  """
68
- dependency_tasks_info = self._get_dep_tasks_info(dependencies)
69
- prompt = PROCESS_TASK_PROMPT.format(
70
- content=task.content,
71
- dependency_tasks_info=dependency_tasks_info,
72
- additional_info=task.additional_info,
73
- )
356
+ # Get agent efficiently (from pool or by cloning)
357
+ worker_agent = await self._get_worker_agent()
358
+ response_content = ""
359
+
74
360
  try:
75
- response = await self.worker.astep(
76
- prompt, response_format=TaskResult
361
+ dependency_tasks_info = self._get_dep_tasks_info(dependencies)
362
+ prompt = str(
363
+ PROCESS_TASK_PROMPT.format(
364
+ content=task.content,
365
+ parent_task_content=task.parent.content
366
+ if task.parent
367
+ else "",
368
+ dependency_tasks_info=dependency_tasks_info,
369
+ additional_info=task.additional_info,
370
+ )
371
+ )
372
+
373
+ if self.use_structured_output_handler and self.structured_handler:
374
+ # Use structured output handler for prompt-based extraction
375
+ enhanced_prompt = (
376
+ self.structured_handler.generate_structured_prompt(
377
+ base_prompt=prompt,
378
+ schema=TaskResult,
379
+ examples=[
380
+ {
381
+ "content": "I have successfully completed the "
382
+ "task...",
383
+ "failed": False,
384
+ }
385
+ ],
386
+ additional_instructions="Ensure you provide a clear "
387
+ "description of what was done and whether the task "
388
+ "succeeded or failed.",
389
+ )
390
+ )
391
+ response = await worker_agent.astep(enhanced_prompt)
392
+
393
+ # Handle streaming response
394
+ if isinstance(response, AsyncStreamingChatAgentResponse):
395
+ content = ""
396
+ async for chunk in response:
397
+ if chunk.msg:
398
+ content = chunk.msg.content
399
+ response_content = content
400
+ else:
401
+ # Regular ChatAgentResponse
402
+ response_content = (
403
+ response.msg.content if response.msg else ""
404
+ )
405
+
406
+ task_result = (
407
+ self.structured_handler.parse_structured_response(
408
+ response_text=response_content,
409
+ schema=TaskResult,
410
+ fallback_values={
411
+ "content": "Task processing failed",
412
+ "failed": True,
413
+ },
414
+ )
415
+ )
416
+ else:
417
+ # Use native structured output if supported
418
+ response = await worker_agent.astep(
419
+ prompt, response_format=TaskResult
420
+ )
421
+
422
+ # Handle streaming response for native output
423
+ if isinstance(response, AsyncStreamingChatAgentResponse):
424
+ task_result = None
425
+ async for chunk in response:
426
+ if chunk.msg and chunk.msg.parsed:
427
+ task_result = chunk.msg.parsed
428
+ response_content = chunk.msg.content
429
+ # If no parsed result found in streaming, create fallback
430
+ if task_result is None:
431
+ task_result = TaskResult(
432
+ content="Failed to parse streaming response",
433
+ failed=True,
434
+ )
435
+ else:
436
+ # Regular ChatAgentResponse
437
+ task_result = response.msg.parsed
438
+ response_content = (
439
+ response.msg.content if response.msg else ""
440
+ )
441
+
442
+ # Get token usage from the response
443
+ if isinstance(response, AsyncStreamingChatAgentResponse):
444
+ # For streaming responses, get the final response info
445
+ final_response = await response
446
+ usage_info = final_response.info.get(
447
+ "usage"
448
+ ) or final_response.info.get("token_usage")
449
+ else:
450
+ final_response = response
451
+ usage_info = response.info.get("usage") or response.info.get(
452
+ "token_usage"
453
+ )
454
+ total_tokens = (
455
+ usage_info.get("total_tokens", 0) if usage_info else 0
77
456
  )
457
+
458
+ # collect conversation from working agent to
459
+ # accumulator for workflow memory
460
+ # Only transfer memory if workflow memory is enabled
461
+ if self.enable_workflow_memory:
462
+ accumulator = self._get_conversation_accumulator()
463
+
464
+ # transfer all memory records from working agent to accumulator
465
+ try:
466
+ # retrieve all context records from the working agent
467
+ work_records = worker_agent.memory.retrieve()
468
+
469
+ # write these records to the accumulator's memory
470
+ memory_records = [
471
+ record.memory_record for record in work_records
472
+ ]
473
+ accumulator.memory.write_records(memory_records)
474
+
475
+ logger.debug(
476
+ f"Transferred {len(memory_records)} memory records to "
477
+ f"accumulator"
478
+ )
479
+
480
+ except Exception as e:
481
+ logger.warning(
482
+ f"Failed to transfer conversation to accumulator: {e}"
483
+ )
484
+
78
485
  except Exception as e:
79
- print(
80
- f"{Fore.RED}Error occurred while processing task {task.id}:"
81
- f"\n{e}{Fore.RESET}"
486
+ logger.error(
487
+ f"Error processing task {task.id}: {type(e).__name__}: {e}"
82
488
  )
489
+ # Store error information in task result
490
+ task.result = f"{type(e).__name__}: {e!s}"
83
491
  return TaskState.FAILED
492
+ finally:
493
+ # Return agent to pool or let it be garbage collected
494
+ await self._return_worker_agent(worker_agent)
495
+
496
+ # Populate additional_info with worker attempt details
497
+ if task.additional_info is None:
498
+ task.additional_info = {}
499
+
500
+ # Create worker attempt details with descriptive keys
501
+ worker_attempt_details = {
502
+ "agent_id": getattr(
503
+ worker_agent, "agent_id", worker_agent.role_name
504
+ ),
505
+ "original_worker_id": getattr(
506
+ self.worker, "agent_id", self.worker.role_name
507
+ ),
508
+ "timestamp": str(datetime.datetime.now()),
509
+ "description": f"Attempt by "
510
+ f"{getattr(worker_agent, 'agent_id', worker_agent.role_name)} "
511
+ f"(from pool/clone of "
512
+ f"{getattr(self.worker, 'agent_id', self.worker.role_name)}) "
513
+ f"to process task: {task.content}",
514
+ "response_content": response_content[:50],
515
+ "tool_calls": str(
516
+ final_response.info.get("tool_calls")
517
+ if isinstance(response, AsyncStreamingChatAgentResponse)
518
+ else response.info.get("tool_calls")
519
+ )[:50],
520
+ "total_tokens": total_tokens,
521
+ }
522
+
523
+ # Store the worker attempt in additional_info
524
+ if "worker_attempts" not in task.additional_info:
525
+ task.additional_info["worker_attempts"] = []
526
+ task.additional_info["worker_attempts"].append(worker_attempt_details)
84
527
 
85
- print(f"======\n{Fore.GREEN}Reply from {self}:{Fore.RESET}")
528
+ # Store the actual token usage for this specific task
529
+ task.additional_info["token_usage"] = {"total_tokens": total_tokens}
86
530
 
87
- result_dict = json.loads(response.msg.content)
88
- task_result = TaskResult(**result_dict)
531
+ print(f"======\n{Fore.GREEN}Response from {self}:{Fore.RESET}")
532
+ logger.info(f"Response from {self}:")
89
533
 
90
- color = Fore.RED if task_result.failed else Fore.GREEN
91
- print_text_animated(
92
- f"\n{color}{task_result.content}{Fore.RESET}\n======",
93
- delay=0.005,
534
+ if not self.use_structured_output_handler:
535
+ # Handle native structured output parsing
536
+ if task_result is None:
537
+ logger.error(
538
+ "Error in worker step execution: Invalid task result"
539
+ )
540
+ task_result = TaskResult(
541
+ content="Failed to generate valid task result.",
542
+ failed=True,
543
+ )
544
+
545
+ color = Fore.RED if task_result.failed else Fore.GREEN # type: ignore[union-attr]
546
+ print(
547
+ f"\n{color}{task_result.content}{Fore.RESET}\n======", # type: ignore[union-attr]
94
548
  )
549
+ if task_result.failed: # type: ignore[union-attr]
550
+ logger.error(f"{task_result.content}") # type: ignore[union-attr]
551
+ else:
552
+ logger.info(f"{task_result.content}") # type: ignore[union-attr]
553
+
554
+ task.result = task_result.content # type: ignore[union-attr]
95
555
 
96
- if task_result.failed:
556
+ if task_result.failed: # type: ignore[union-attr]
97
557
  return TaskState.FAILED
98
558
 
99
- task.result = task_result.content
559
+ if is_task_result_insufficient(task):
560
+ logger.warning(
561
+ f"Task {task.id}: Content validation failed - "
562
+ f"task marked as failed"
563
+ )
564
+ return TaskState.FAILED
100
565
  return TaskState.DONE
566
+
567
+ async def _listen_to_channel(self):
568
+ r"""Override to start cleanup task when pool is enabled."""
569
+ # Start cleanup task for agent pool
570
+ if self.use_agent_pool and self.agent_pool:
571
+ self._cleanup_task = asyncio.create_task(self._periodic_cleanup())
572
+
573
+ # Call parent implementation
574
+ await super()._listen_to_channel()
575
+
576
+ # Stop cleanup task
577
+ if self._cleanup_task and not self._cleanup_task.done():
578
+ self._cleanup_task.cancel()
579
+
580
+ async def _periodic_cleanup(self):
581
+ r"""Periodically clean up idle agents from the pool."""
582
+ while True:
583
+ try:
584
+ # Fixed interval cleanup
585
+ if self.agent_pool:
586
+ await asyncio.sleep(self.agent_pool.cleanup_interval)
587
+ await self.agent_pool.cleanup_idle_agents()
588
+ else:
589
+ break
590
+ except asyncio.CancelledError:
591
+ break
592
+ except Exception as e:
593
+ logger.warning(f"Error in pool cleanup: {e}")
594
+
595
+ def get_pool_stats(self) -> Optional[dict]:
596
+ r"""Get agent pool statistics if pool is enabled."""
597
+ if self.use_agent_pool and self.agent_pool:
598
+ return self.agent_pool.get_stats()
599
+ return None
600
+
601
+ def save_workflow_memories(self) -> Dict[str, Any]:
602
+ r"""Save the worker's current workflow memories using agent
603
+ summarization.
604
+
605
+ .. deprecated:: 0.2.80
606
+ Use :meth:`save_workflow_memories_async` for async/await support
607
+ and better integration with parallel workflow saving.
608
+
609
+ This method generates a workflow summary from the worker agent's
610
+ conversation history and saves it to a markdown file. The filename
611
+ is based on either the worker's explicit role_name or the generated
612
+ task_title from the summary.
613
+
614
+ Delegates to WorkflowMemoryManager for all workflow operations.
615
+
616
+ Returns:
617
+ Dict[str, Any]: Result dictionary with keys:
618
+ - status (str): "success" or "error"
619
+ - summary (str): Generated workflow summary
620
+ - file_path (str): Path to saved file
621
+ - worker_description (str): Worker description used
622
+
623
+ See Also:
624
+ :meth:`save_workflow_memories_async`: Async version for better
625
+ performance in parallel workflows.
626
+ """
627
+ import warnings
628
+
629
+ warnings.warn(
630
+ "save_workflow_memories() is synchronous. Consider using "
631
+ "save_workflow_memories_async() for async/await support.",
632
+ DeprecationWarning,
633
+ stacklevel=2,
634
+ )
635
+
636
+ manager = self._get_workflow_manager()
637
+ result = manager.save_workflow(
638
+ conversation_accumulator=self._conversation_accumulator
639
+ )
640
+
641
+ # clean up accumulator after successful save
642
+ if (
643
+ result.get("status") == "success"
644
+ and self._conversation_accumulator is not None
645
+ ):
646
+ logger.info(
647
+ "Cleaning up conversation accumulator after workflow "
648
+ "summarization"
649
+ )
650
+ self._conversation_accumulator = None
651
+
652
+ return result
653
+
654
+ async def save_workflow_memories_async(self) -> Dict[str, Any]:
655
+ r"""Asynchronously save the worker's current workflow memories using
656
+ agent summarization.
657
+
658
+ This is the async version of save_workflow_memories() that uses
659
+ asummarize() for non-blocking LLM calls, enabling parallel
660
+ summarization of multiple workers.
661
+
662
+ Delegates to WorkflowMemoryManager for all workflow operations.
663
+
664
+ Returns:
665
+ Dict[str, Any]: Result dictionary with keys:
666
+ - status (str): "success" or "error"
667
+ - summary (str): Generated workflow summary
668
+ - file_path (str): Path to saved file
669
+ - worker_description (str): Worker description used
670
+ """
671
+ manager = self._get_workflow_manager()
672
+ result = await manager.save_workflow_async(
673
+ conversation_accumulator=self._conversation_accumulator
674
+ )
675
+
676
+ # clean up accumulator after successful save
677
+ if (
678
+ result.get("status") == "success"
679
+ and self._conversation_accumulator is not None
680
+ ):
681
+ logger.info(
682
+ "Cleaning up conversation accumulator after workflow "
683
+ "summarization"
684
+ )
685
+ self._conversation_accumulator = None
686
+
687
+ return result
688
+
689
+ def load_workflow_memories(
690
+ self,
691
+ pattern: Optional[str] = None,
692
+ max_workflows: int = 3,
693
+ session_id: Optional[str] = None,
694
+ use_smart_selection: bool = True,
695
+ ) -> bool:
696
+ r"""Load workflow memories using intelligent agent-based selection.
697
+
698
+ This method uses the worker agent to intelligently select the most
699
+ relevant workflows based on metadata (title, description, tags)
700
+ rather than simple filename pattern matching.
701
+
702
+ Delegates to WorkflowMemoryManager for all workflow operations.
703
+
704
+ Args:
705
+ pattern (Optional[str]): Legacy parameter for backward
706
+ compatibility. When use_smart_selection=False, uses this
707
+ pattern for file matching. Ignored when smart selection
708
+ is enabled.
709
+ max_workflows (int): Maximum number of workflow files to load.
710
+ (default: :obj:`3`)
711
+ session_id (Optional[str]): Specific workforce session ID to load
712
+ from. If None, searches across all sessions.
713
+ (default: :obj:`None`)
714
+ use_smart_selection (bool): Whether to use agent-based intelligent
715
+ workflow selection. When True, uses metadata and LLM to select
716
+ most relevant workflows. When False, falls back to pattern
717
+ matching. (default: :obj:`True`)
718
+
719
+ Returns:
720
+ bool: True if workflow memories were successfully loaded, False
721
+ otherwise.
722
+ """
723
+ manager = self._get_workflow_manager()
724
+ return manager.load_workflows(
725
+ pattern=pattern,
726
+ max_files_to_load=max_workflows,
727
+ session_id=session_id,
728
+ use_smart_selection=use_smart_selection,
729
+ )