camel-ai 0.2.65__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.
- camel/__init__.py +3 -3
- camel/agents/__init__.py +2 -2
- camel/agents/_types.py +9 -4
- camel/agents/_utils.py +40 -2
- camel/agents/base.py +2 -2
- camel/agents/chat_agent.py +4835 -947
- camel/agents/critic_agent.py +2 -2
- camel/agents/deductive_reasoner_agent.py +56 -56
- camel/agents/embodied_agent.py +2 -2
- camel/agents/knowledge_graph_agent.py +20 -20
- camel/agents/mcp_agent.py +35 -36
- camel/agents/multi_hop_generator_agent.py +3 -3
- camel/agents/programmed_agent_instruction.py +2 -2
- camel/agents/repo_agent.py +4 -3
- camel/agents/role_assignment_agent.py +2 -2
- camel/agents/search_agent.py +2 -2
- camel/agents/task_agent.py +2 -2
- camel/agents/tool_agents/__init__.py +2 -2
- camel/agents/tool_agents/base.py +2 -2
- camel/agents/tool_agents/hugging_face_tool_agent.py +3 -3
- camel/benchmarks/__init__.py +2 -2
- camel/benchmarks/apibank.py +5 -5
- camel/benchmarks/apibench.py +2 -2
- camel/benchmarks/base.py +2 -2
- camel/benchmarks/browsecomp.py +44 -33
- camel/benchmarks/gaia.py +17 -13
- camel/benchmarks/mock_website/README.md +1 -3
- camel/benchmarks/mock_website/mock_web.py +2 -2
- camel/benchmarks/mock_website/requirements.txt +1 -1
- camel/benchmarks/mock_website/shopping_mall/app.py +2 -2
- camel/benchmarks/mock_website/task.json +1 -1
- camel/benchmarks/nexus.py +3 -3
- camel/benchmarks/ragbench.py +2 -2
- camel/bots/__init__.py +2 -2
- camel/bots/discord/__init__.py +2 -2
- camel/bots/discord/discord_app.py +2 -2
- camel/bots/discord/discord_installation.py +2 -2
- camel/bots/discord/discord_store.py +3 -3
- camel/bots/slack/__init__.py +2 -2
- camel/bots/slack/models.py +4 -4
- camel/bots/slack/slack_app.py +2 -2
- camel/bots/telegram_bot.py +2 -2
- camel/configs/__init__.py +23 -2
- camel/configs/aihubmix_config.py +90 -0
- camel/configs/aiml_config.py +2 -2
- camel/configs/amd_config.py +70 -0
- camel/configs/anthropic_config.py +2 -2
- camel/configs/base_config.py +2 -2
- camel/configs/bedrock_config.py +5 -3
- camel/configs/cerebras_config.py +98 -0
- camel/configs/cohere_config.py +2 -2
- camel/configs/cometapi_config.py +106 -0
- camel/configs/crynux_config.py +2 -2
- camel/configs/deepseek_config.py +9 -8
- camel/configs/gemini_config.py +6 -4
- camel/configs/groq_config.py +6 -4
- camel/configs/internlm_config.py +6 -4
- camel/configs/litellm_config.py +2 -2
- camel/configs/lmstudio_config.py +6 -4
- camel/configs/minimax_config.py +95 -0
- camel/configs/mistral_config.py +2 -2
- camel/configs/modelscope_config.py +5 -3
- camel/configs/moonshot_config.py +2 -2
- camel/configs/nebius_config.py +105 -0
- camel/configs/netmind_config.py +2 -2
- camel/configs/novita_config.py +2 -2
- camel/configs/nvidia_config.py +2 -2
- camel/configs/ollama_config.py +2 -2
- camel/configs/openai_config.py +5 -3
- camel/configs/openrouter_config.py +6 -4
- camel/configs/ppio_config.py +2 -2
- camel/configs/qianfan_config.py +85 -0
- camel/configs/qwen_config.py +2 -2
- camel/configs/reka_config.py +2 -2
- camel/configs/samba_config.py +6 -4
- camel/configs/sglang_config.py +2 -2
- camel/configs/siliconflow_config.py +2 -2
- camel/configs/togetherai_config.py +2 -2
- camel/configs/vllm_config.py +4 -2
- camel/configs/watsonx_config.py +2 -2
- camel/configs/yi_config.py +6 -4
- camel/configs/zhipuai_config.py +6 -4
- camel/data_collectors/__init__.py +2 -2
- camel/data_collectors/alpaca_collector.py +18 -9
- camel/data_collectors/base.py +2 -2
- camel/data_collectors/sharegpt_collector.py +2 -2
- camel/datagen/__init__.py +2 -2
- camel/datagen/cot_datagen.py +3 -3
- camel/datagen/evol_instruct/__init__.py +2 -2
- camel/datagen/evol_instruct/evol_instruct.py +2 -2
- camel/datagen/evol_instruct/scorer.py +12 -12
- camel/datagen/evol_instruct/templates.py +16 -16
- camel/datagen/self_improving_cot.py +5 -5
- camel/datagen/self_instruct/__init__.py +2 -2
- camel/datagen/self_instruct/filter/__init__.py +2 -2
- camel/datagen/self_instruct/filter/filter_function.py +2 -2
- camel/datagen/self_instruct/filter/filter_registry.py +2 -2
- camel/datagen/self_instruct/filter/instruction_filter.py +2 -2
- camel/datagen/self_instruct/self_instruct.py +2 -2
- camel/datagen/self_instruct/templates.py +47 -47
- camel/datagen/source2synth/__init__.py +2 -2
- camel/datagen/source2synth/data_processor.py +2 -2
- camel/datagen/source2synth/models.py +2 -2
- camel/datagen/source2synth/user_data_processor_config.py +2 -2
- camel/datahubs/__init__.py +2 -2
- camel/datahubs/base.py +2 -2
- camel/datahubs/huggingface.py +2 -2
- camel/datahubs/models.py +2 -2
- camel/datasets/__init__.py +2 -2
- camel/datasets/base_generator.py +41 -12
- camel/datasets/few_shot_generator.py +18 -18
- camel/datasets/models.py +2 -2
- camel/datasets/self_instruct_generator.py +2 -2
- camel/datasets/static_dataset.py +2 -2
- camel/embeddings/__init__.py +2 -2
- camel/embeddings/azure_embedding.py +2 -2
- camel/embeddings/base.py +2 -2
- camel/embeddings/gemini_embedding.py +2 -2
- camel/embeddings/jina_embedding.py +2 -2
- camel/embeddings/mistral_embedding.py +2 -2
- camel/embeddings/openai_compatible_embedding.py +2 -2
- camel/embeddings/openai_embedding.py +2 -2
- camel/embeddings/sentence_transformers_embeddings.py +2 -2
- camel/embeddings/together_embedding.py +2 -2
- camel/embeddings/vlm_embedding.py +2 -2
- camel/environments/__init__.py +14 -2
- camel/environments/models.py +2 -2
- camel/environments/multi_step.py +2 -2
- camel/environments/rlcards_env.py +860 -0
- camel/environments/single_step.py +30 -5
- camel/environments/tic_tac_toe.py +3 -3
- camel/extractors/__init__.py +2 -2
- camel/extractors/base.py +2 -2
- camel/extractors/python_strategies.py +2 -2
- camel/generators.py +2 -2
- camel/human.py +2 -2
- camel/interpreters/__init__.py +4 -2
- camel/interpreters/base.py +2 -2
- camel/interpreters/docker/Dockerfile +14 -24
- camel/interpreters/docker_interpreter.py +5 -4
- camel/interpreters/e2b_interpreter.py +36 -3
- camel/interpreters/internal_python_interpreter.py +53 -4
- camel/interpreters/interpreter_error.py +2 -2
- camel/interpreters/ipython_interpreter.py +2 -2
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/interpreters/subprocess_interpreter.py +2 -2
- camel/loaders/__init__.py +13 -4
- camel/loaders/apify_reader.py +2 -2
- camel/loaders/base_io.py +2 -2
- camel/loaders/base_loader.py +85 -0
- camel/loaders/chunkr_reader.py +11 -2
- camel/loaders/crawl4ai_reader.py +2 -2
- camel/loaders/firecrawl_reader.py +6 -6
- camel/loaders/jina_url_reader.py +2 -2
- camel/loaders/markitdown.py +2 -2
- camel/loaders/mineru_extractor.py +2 -2
- camel/loaders/mistral_reader.py +2 -2
- camel/loaders/scrapegraph_reader.py +2 -2
- camel/loaders/unstructured_io.py +2 -2
- camel/logger.py +5 -5
- camel/memories/__init__.py +2 -2
- camel/memories/agent_memories.py +86 -3
- camel/memories/base.py +36 -2
- camel/memories/blocks/__init__.py +2 -2
- camel/memories/blocks/chat_history_block.py +125 -7
- camel/memories/blocks/vectordb_block.py +10 -3
- camel/memories/context_creators/__init__.py +2 -2
- camel/memories/context_creators/score_based.py +31 -239
- camel/memories/records.py +90 -10
- camel/messages/__init__.py +2 -2
- camel/messages/base.py +178 -43
- camel/messages/conversion/__init__.py +2 -2
- camel/messages/conversion/alpaca.py +2 -2
- camel/messages/conversion/conversation_models.py +2 -2
- camel/messages/conversion/sharegpt/__init__.py +2 -2
- camel/messages/conversion/sharegpt/function_call_formatter.py +2 -2
- camel/messages/conversion/sharegpt/hermes/__init__.py +2 -2
- camel/messages/conversion/sharegpt/hermes/hermes_function_formatter.py +2 -2
- camel/messages/func_message.py +54 -17
- camel/models/__init__.py +16 -2
- camel/models/_utils.py +3 -3
- camel/models/aihubmix_model.py +83 -0
- camel/models/aiml_model.py +11 -18
- camel/models/amd_model.py +101 -0
- camel/models/anthropic_model.py +127 -20
- camel/models/aws_bedrock_model.py +12 -35
- camel/models/azure_openai_model.py +212 -89
- camel/models/base_audio_model.py +5 -3
- camel/models/base_model.py +195 -26
- camel/models/cerebras_model.py +83 -0
- camel/models/cohere_model.py +16 -21
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +11 -18
- camel/models/deepseek_model.py +18 -58
- camel/models/fish_audio_model.py +8 -2
- camel/models/gemini_model.py +389 -26
- camel/models/groq_model.py +11 -19
- camel/models/internlm_model.py +11 -18
- camel/models/litellm_model.py +56 -34
- camel/models/lmstudio_model.py +17 -20
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +18 -19
- camel/models/model_factory.py +37 -3
- camel/models/model_manager.py +26 -8
- camel/models/modelscope_model.py +13 -193
- camel/models/moonshot_model.py +195 -21
- camel/models/nebius_model.py +83 -0
- camel/models/nemotron_model.py +19 -9
- camel/models/netmind_model.py +11 -18
- camel/models/novita_model.py +11 -18
- camel/models/nvidia_model.py +11 -18
- camel/models/ollama_model.py +14 -21
- camel/models/openai_audio_models.py +2 -2
- camel/models/openai_compatible_model.py +188 -45
- camel/models/openai_model.py +216 -71
- camel/models/openrouter_model.py +11 -19
- camel/models/ppio_model.py +11 -18
- camel/models/qianfan_model.py +89 -0
- camel/models/qwen_model.py +13 -193
- camel/models/reka_model.py +21 -21
- camel/models/reward/__init__.py +2 -2
- camel/models/reward/base_reward_model.py +2 -2
- camel/models/reward/evaluator.py +2 -2
- camel/models/reward/nemotron_model.py +2 -2
- camel/models/reward/skywork_model.py +2 -2
- camel/models/samba_model.py +48 -47
- camel/models/sglang_model.py +88 -40
- camel/models/siliconflow_model.py +12 -35
- camel/models/stub_model.py +10 -7
- camel/models/togetherai_model.py +11 -18
- camel/models/vllm_model.py +10 -18
- camel/models/volcano_model.py +16 -20
- camel/models/watsonx_model.py +7 -19
- camel/models/yi_model.py +11 -18
- camel/models/zhipuai_model.py +70 -18
- camel/parsers/__init__.py +18 -0
- camel/parsers/mcp_tool_call_parser.py +176 -0
- camel/personas/__init__.py +2 -2
- camel/personas/persona.py +2 -2
- camel/personas/persona_hub.py +2 -2
- camel/prompts/__init__.py +2 -2
- camel/prompts/ai_society.py +2 -2
- camel/prompts/base.py +2 -2
- camel/prompts/code.py +2 -2
- camel/prompts/evaluation.py +2 -2
- camel/prompts/generate_text_embedding_data.py +2 -2
- camel/prompts/image_craft.py +2 -2
- camel/prompts/misalignment.py +2 -2
- camel/prompts/multi_condition_image_craft.py +2 -2
- camel/prompts/object_recognition.py +2 -2
- camel/prompts/persona_hub.py +3 -3
- camel/prompts/prompt_templates.py +2 -2
- camel/prompts/role_description_prompt_template.py +2 -2
- camel/prompts/solution_extraction.py +8 -8
- camel/prompts/task_prompt_template.py +2 -2
- camel/prompts/translation.py +2 -2
- camel/prompts/video_description_prompt.py +3 -3
- camel/responses/__init__.py +2 -2
- camel/responses/agent_responses.py +2 -2
- camel/retrievers/__init__.py +2 -2
- camel/retrievers/auto_retriever.py +3 -2
- camel/retrievers/base.py +2 -2
- camel/retrievers/bm25_retriever.py +2 -2
- camel/retrievers/cohere_rerank_retriever.py +2 -2
- camel/retrievers/hybrid_retrival.py +2 -2
- camel/retrievers/vector_retriever.py +2 -2
- camel/runtimes/Dockerfile.multi-toolkit +90 -0
- camel/runtimes/__init__.py +2 -2
- camel/runtimes/api.py +79 -23
- camel/runtimes/base.py +2 -2
- camel/runtimes/configs.py +13 -13
- camel/runtimes/daytona_runtime.py +17 -18
- camel/runtimes/docker_runtime.py +12 -12
- camel/runtimes/llm_guard_runtime.py +26 -26
- camel/runtimes/remote_http_runtime.py +11 -11
- camel/runtimes/ubuntu_docker_runtime.py +2 -2
- camel/runtimes/utils/__init__.py +2 -2
- camel/runtimes/utils/function_risk_toolkit.py +2 -2
- camel/runtimes/utils/ignore_risk_toolkit.py +2 -2
- camel/schemas/__init__.py +2 -2
- camel/schemas/base.py +2 -2
- camel/schemas/openai_converter.py +3 -3
- camel/schemas/outlines_converter.py +2 -2
- camel/services/agent_openapi_server.py +380 -0
- camel/societies/__init__.py +4 -2
- camel/societies/babyagi_playing.py +2 -2
- camel/societies/role_playing.py +201 -80
- camel/societies/workforce/__init__.py +10 -3
- camel/societies/workforce/base.py +2 -2
- camel/societies/workforce/events.py +143 -0
- camel/societies/workforce/prompts.py +258 -33
- camel/societies/workforce/role_playing_worker.py +88 -31
- camel/societies/workforce/single_agent_worker.py +638 -40
- camel/societies/workforce/structured_output_handler.py +512 -0
- camel/societies/workforce/task_channel.py +182 -38
- camel/societies/workforce/utils.py +780 -65
- camel/societies/workforce/worker.py +92 -26
- camel/societies/workforce/workflow_memory_manager.py +1746 -0
- camel/societies/workforce/workforce.py +5276 -355
- camel/societies/workforce/workforce_callback.py +103 -0
- camel/societies/workforce/workforce_logger.py +647 -0
- camel/societies/workforce/workforce_metrics.py +33 -0
- camel/storages/__init__.py +6 -2
- camel/storages/graph_storages/__init__.py +2 -2
- camel/storages/graph_storages/base.py +2 -2
- camel/storages/graph_storages/graph_element.py +2 -2
- camel/storages/graph_storages/nebula_graph.py +4 -4
- camel/storages/graph_storages/neo4j_graph.py +7 -7
- camel/storages/key_value_storages/__init__.py +2 -2
- camel/storages/key_value_storages/base.py +2 -2
- camel/storages/key_value_storages/in_memory.py +2 -2
- camel/storages/key_value_storages/json.py +17 -4
- camel/storages/key_value_storages/mem0_cloud.py +50 -49
- camel/storages/key_value_storages/redis.py +2 -2
- camel/storages/object_storages/__init__.py +2 -2
- camel/storages/object_storages/amazon_s3.py +2 -2
- camel/storages/object_storages/azure_blob.py +2 -2
- camel/storages/object_storages/base.py +2 -2
- camel/storages/object_storages/google_cloud.py +3 -3
- camel/storages/vectordb_storages/__init__.py +8 -2
- camel/storages/vectordb_storages/base.py +2 -2
- camel/storages/vectordb_storages/chroma.py +731 -0
- camel/storages/vectordb_storages/faiss.py +2 -2
- camel/storages/vectordb_storages/milvus.py +2 -2
- camel/storages/vectordb_storages/oceanbase.py +15 -15
- camel/storages/vectordb_storages/pgvector.py +349 -0
- camel/storages/vectordb_storages/qdrant.py +6 -6
- camel/storages/vectordb_storages/surreal.py +372 -0
- camel/storages/vectordb_storages/tidb.py +11 -8
- camel/storages/vectordb_storages/weaviate.py +2 -2
- camel/tasks/__init__.py +2 -2
- camel/tasks/task.py +348 -26
- camel/tasks/task_prompt.py +3 -3
- camel/terminators/__init__.py +2 -2
- camel/terminators/base.py +2 -2
- camel/terminators/response_terminator.py +2 -2
- camel/terminators/token_limit_terminator.py +2 -2
- camel/toolkits/__init__.py +54 -10
- camel/toolkits/aci_toolkit.py +66 -21
- camel/toolkits/arxiv_toolkit.py +8 -8
- camel/toolkits/ask_news_toolkit.py +2 -2
- camel/toolkits/async_browser_toolkit.py +4 -4
- camel/toolkits/audio_analysis_toolkit.py +3 -3
- camel/toolkits/base.py +65 -7
- camel/toolkits/bohrium_toolkit.py +2 -2
- camel/toolkits/browser_toolkit.py +34 -21
- camel/toolkits/browser_toolkit_commons.py +4 -4
- camel/toolkits/code_execution.py +31 -4
- camel/toolkits/context_summarizer_toolkit.py +684 -0
- camel/toolkits/craw4ai_toolkit.py +93 -0
- camel/toolkits/dappier_toolkit.py +12 -8
- camel/toolkits/data_commons_toolkit.py +2 -2
- camel/toolkits/dingtalk.py +1135 -0
- camel/toolkits/earth_science_toolkit.py +5367 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
- camel/toolkits/excel_toolkit.py +905 -71
- camel/toolkits/file_toolkit.py +1402 -0
- camel/toolkits/function_tool.py +126 -18
- camel/toolkits/github_toolkit.py +109 -22
- camel/toolkits/gmail_toolkit.py +1839 -0
- camel/toolkits/google_calendar_toolkit.py +40 -6
- camel/toolkits/google_drive_mcp_toolkit.py +54 -0
- camel/toolkits/google_maps_toolkit.py +2 -2
- camel/toolkits/google_scholar_toolkit.py +2 -2
- camel/toolkits/human_toolkit.py +36 -12
- camel/toolkits/hybrid_browser_toolkit/__init__.py +18 -0
- camel/toolkits/hybrid_browser_toolkit/config_loader.py +185 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +246 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +1973 -0
- camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +4589 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package.json +33 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1929 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +589 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +129 -0
- camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +27 -0
- camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +319 -0
- camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1037 -0
- camel/toolkits/hybrid_browser_toolkit_py/__init__.py +17 -0
- camel/toolkits/hybrid_browser_toolkit_py/actions.py +575 -0
- camel/toolkits/hybrid_browser_toolkit_py/agent.py +311 -0
- camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +787 -0
- camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +490 -0
- camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +2390 -0
- camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +233 -0
- camel/toolkits/hybrid_browser_toolkit_py/stealth_script.js +0 -0
- camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +1043 -0
- camel/toolkits/image_analysis_toolkit.py +3 -6
- camel/toolkits/image_generation_toolkit.py +390 -0
- camel/toolkits/jina_reranker_toolkit.py +5 -6
- camel/toolkits/klavis_toolkit.py +7 -3
- camel/toolkits/linkedin_toolkit.py +2 -2
- camel/toolkits/markitdown_toolkit.py +104 -0
- camel/toolkits/math_toolkit.py +66 -12
- camel/toolkits/mcp_toolkit.py +412 -36
- camel/toolkits/memory_toolkit.py +7 -3
- camel/toolkits/meshy_toolkit.py +2 -2
- camel/toolkits/message_agent_toolkit.py +608 -0
- camel/toolkits/message_integration.py +724 -0
- camel/toolkits/mineru_toolkit.py +2 -2
- camel/toolkits/minimax_mcp_toolkit.py +195 -0
- camel/toolkits/networkx_toolkit.py +2 -2
- camel/toolkits/note_taking_toolkit.py +277 -0
- camel/toolkits/notion_mcp_toolkit.py +224 -0
- camel/toolkits/notion_toolkit.py +2 -2
- camel/toolkits/open_api_specs/biztoc/__init__.py +2 -2
- camel/toolkits/open_api_specs/biztoc/ai-plugin.json +1 -1
- camel/toolkits/open_api_specs/coursera/__init__.py +2 -2
- camel/toolkits/open_api_specs/create_qr_code/__init__.py +2 -2
- camel/toolkits/open_api_specs/klarna/__init__.py +2 -2
- camel/toolkits/open_api_specs/nasa_apod/__init__.py +2 -2
- camel/toolkits/open_api_specs/outschool/__init__.py +2 -2
- camel/toolkits/open_api_specs/outschool/ai-plugin.json +1 -1
- camel/toolkits/open_api_specs/outschool/openapi.yaml +1 -1
- camel/toolkits/open_api_specs/outschool/paths/__init__.py +2 -2
- camel/toolkits/open_api_specs/outschool/paths/get_classes.py +2 -2
- camel/toolkits/open_api_specs/outschool/paths/search_teachers.py +2 -2
- camel/toolkits/open_api_specs/security_config.py +2 -2
- camel/toolkits/open_api_specs/speak/__init__.py +2 -2
- camel/toolkits/open_api_specs/web_scraper/__init__.py +2 -2
- camel/toolkits/open_api_specs/web_scraper/ai-plugin.json +1 -1
- camel/toolkits/open_api_specs/web_scraper/paths/__init__.py +2 -2
- camel/toolkits/open_api_specs/web_scraper/paths/scraper.py +2 -2
- camel/toolkits/open_api_toolkit.py +2 -2
- camel/toolkits/openbb_toolkit.py +7 -3
- camel/toolkits/origene_mcp_toolkit.py +56 -0
- camel/toolkits/page_script.js +53 -53
- camel/toolkits/playwright_mcp_toolkit.py +13 -31
- camel/toolkits/pptx_toolkit.py +36 -23
- camel/toolkits/pubmed_toolkit.py +2 -2
- camel/toolkits/pulse_mcp_search_toolkit.py +2 -2
- camel/toolkits/pyautogui_toolkit.py +2 -2
- camel/toolkits/reddit_toolkit.py +2 -2
- camel/toolkits/resend_toolkit.py +168 -0
- camel/toolkits/retrieval_toolkit.py +2 -2
- camel/toolkits/screenshot_toolkit.py +213 -0
- camel/toolkits/search_toolkit.py +539 -146
- camel/toolkits/searxng_toolkit.py +2 -2
- camel/toolkits/semantic_scholar_toolkit.py +2 -2
- camel/toolkits/slack_toolkit.py +108 -58
- camel/toolkits/sql_toolkit.py +712 -0
- camel/toolkits/stripe_toolkit.py +2 -2
- camel/toolkits/sympy_toolkit.py +3 -3
- camel/toolkits/task_planning_toolkit.py +5 -5
- camel/toolkits/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +1070 -0
- camel/toolkits/terminal_toolkit/utils.py +532 -0
- camel/toolkits/thinking_toolkit.py +3 -3
- camel/toolkits/twitter_toolkit.py +2 -2
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +109 -29
- camel/toolkits/video_download_toolkit.py +19 -16
- camel/toolkits/weather_toolkit.py +2 -2
- camel/toolkits/web_deploy_toolkit.py +1219 -0
- camel/toolkits/wechat_official_toolkit.py +483 -0
- camel/toolkits/whatsapp_toolkit.py +2 -2
- camel/toolkits/wolfram_alpha_toolkit.py +2 -2
- camel/toolkits/zapier_toolkit.py +7 -3
- camel/types/__init__.py +4 -4
- camel/types/agents/__init__.py +2 -2
- camel/types/agents/tool_calling_record.py +6 -3
- camel/types/enums.py +378 -39
- camel/types/mcp_registries.py +2 -2
- camel/types/openai_types.py +4 -4
- camel/types/unified_model_type.py +38 -6
- camel/utils/__init__.py +2 -2
- camel/utils/async_func.py +2 -2
- camel/utils/chunker/__init__.py +2 -2
- camel/utils/chunker/base.py +2 -2
- camel/utils/chunker/code_chunker.py +2 -2
- camel/utils/chunker/uio_chunker.py +2 -2
- camel/utils/commons.py +38 -7
- camel/utils/constants.py +5 -2
- camel/utils/context_utils.py +1134 -0
- camel/utils/deduplication.py +2 -2
- camel/utils/filename.py +2 -2
- camel/utils/langfuse.py +2 -2
- camel/utils/mcp.py +140 -6
- camel/utils/mcp_client.py +48 -38
- camel/utils/message_summarizer.py +148 -0
- camel/utils/response_format.py +2 -2
- camel/utils/token_counting.py +45 -22
- camel/utils/tool_result.py +44 -0
- camel/verifiers/__init__.py +2 -2
- camel/verifiers/base.py +2 -2
- camel/verifiers/math_verifier.py +2 -2
- camel/verifiers/models.py +2 -2
- camel/verifiers/physics_verifier.py +2 -2
- camel/verifiers/python_verifier.py +2 -2
- {camel_ai-0.2.65.dist-info → camel_ai-0.2.82.dist-info}/METADATA +327 -94
- camel_ai-0.2.82.dist-info/RECORD +507 -0
- {camel_ai-0.2.65.dist-info → camel_ai-0.2.82.dist-info}/WHEEL +1 -1
- {camel_ai-0.2.65.dist-info → camel_ai-0.2.82.dist-info}/licenses/LICENSE +1 -1
- camel/loaders/pandas_reader.py +0 -368
- camel/toolkits/dalle_toolkit.py +0 -175
- camel/toolkits/file_write_toolkit.py +0 -444
- camel/toolkits/openai_agent_toolkit.py +0 -135
- camel/toolkits/terminal_toolkit.py +0 -1037
- camel_ai-0.2.65.dist-info/RECORD +0 -426
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ========= Copyright 2023-
|
|
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,21 +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-
|
|
13
|
+
# ========= Copyright 2023-2025 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
|
+
import asyncio
|
|
16
17
|
import datetime
|
|
17
|
-
import
|
|
18
|
-
from
|
|
18
|
+
import time
|
|
19
|
+
from collections import deque
|
|
20
|
+
from typing import Any, Dict, List, Optional
|
|
19
21
|
|
|
20
22
|
from colorama import Fore
|
|
21
23
|
|
|
22
24
|
from camel.agents import ChatAgent
|
|
25
|
+
from camel.agents.chat_agent import AsyncStreamingChatAgentResponse
|
|
26
|
+
from camel.logger import get_logger
|
|
23
27
|
from camel.societies.workforce.prompts import PROCESS_TASK_PROMPT
|
|
24
|
-
from camel.societies.workforce.
|
|
28
|
+
from camel.societies.workforce.structured_output_handler import (
|
|
29
|
+
StructuredOutputHandler,
|
|
30
|
+
)
|
|
31
|
+
from camel.societies.workforce.utils import TaskResult
|
|
25
32
|
from camel.societies.workforce.worker import Worker
|
|
26
|
-
from camel.
|
|
27
|
-
|
|
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
|
+
}
|
|
28
185
|
|
|
29
186
|
|
|
30
187
|
class SingleAgentWorker(Worker):
|
|
@@ -33,30 +190,159 @@ class SingleAgentWorker(Worker):
|
|
|
33
190
|
Args:
|
|
34
191
|
description (str): Description of the node.
|
|
35
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`)
|
|
36
219
|
"""
|
|
37
220
|
|
|
38
221
|
def __init__(
|
|
39
222
|
self,
|
|
40
223
|
description: str,
|
|
41
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,
|
|
42
232
|
) -> None:
|
|
43
233
|
node_id = worker.agent_id
|
|
44
|
-
super().__init__(
|
|
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
|
+
)
|
|
45
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
|
+
)
|
|
46
272
|
|
|
47
273
|
def reset(self) -> Any:
|
|
48
274
|
r"""Resets the worker to its initial state."""
|
|
49
275
|
super().reset()
|
|
50
276
|
self.worker.reset()
|
|
51
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
|
+
|
|
52
336
|
async def _process_task(
|
|
53
337
|
self, task: Task, dependencies: List[Task]
|
|
54
338
|
) -> TaskState:
|
|
55
|
-
r"""Processes a task with its dependencies
|
|
339
|
+
r"""Processes a task with its dependencies using an efficient agent
|
|
340
|
+
management system.
|
|
56
341
|
|
|
57
342
|
This method asynchronously processes a given task, considering its
|
|
58
|
-
dependencies, by sending a generated prompt to a worker.
|
|
59
|
-
|
|
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.
|
|
60
346
|
|
|
61
347
|
Args:
|
|
62
348
|
task (Task): The task to process, which includes necessary details
|
|
@@ -67,22 +353,145 @@ class SingleAgentWorker(Worker):
|
|
|
67
353
|
TaskState: `TaskState.DONE` if processed successfully, otherwise
|
|
68
354
|
`TaskState.FAILED`.
|
|
69
355
|
"""
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
additional_info=task.additional_info,
|
|
75
|
-
)
|
|
356
|
+
# Get agent efficiently (from pool or by cloning)
|
|
357
|
+
worker_agent = await self._get_worker_agent()
|
|
358
|
+
response_content = ""
|
|
359
|
+
|
|
76
360
|
try:
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
79
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
|
+
|
|
80
485
|
except Exception as e:
|
|
81
|
-
|
|
82
|
-
f"
|
|
83
|
-
f"\n{e}{Fore.RESET}"
|
|
486
|
+
logger.error(
|
|
487
|
+
f"Error processing task {task.id}: {type(e).__name__}: {e}"
|
|
84
488
|
)
|
|
489
|
+
# Store error information in task result
|
|
490
|
+
task.result = f"{type(e).__name__}: {e!s}"
|
|
85
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)
|
|
86
495
|
|
|
87
496
|
# Populate additional_info with worker attempt details
|
|
88
497
|
if task.additional_info is None:
|
|
@@ -91,14 +500,24 @@ class SingleAgentWorker(Worker):
|
|
|
91
500
|
# Create worker attempt details with descriptive keys
|
|
92
501
|
worker_attempt_details = {
|
|
93
502
|
"agent_id": getattr(
|
|
503
|
+
worker_agent, "agent_id", worker_agent.role_name
|
|
504
|
+
),
|
|
505
|
+
"original_worker_id": getattr(
|
|
94
506
|
self.worker, "agent_id", self.worker.role_name
|
|
95
507
|
),
|
|
96
508
|
"timestamp": str(datetime.datetime.now()),
|
|
97
509
|
"description": f"Attempt by "
|
|
98
|
-
f"{getattr(
|
|
99
|
-
f"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
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,
|
|
102
521
|
}
|
|
103
522
|
|
|
104
523
|
# Store the worker attempt in additional_info
|
|
@@ -106,26 +525,205 @@ class SingleAgentWorker(Worker):
|
|
|
106
525
|
task.additional_info["worker_attempts"] = []
|
|
107
526
|
task.additional_info["worker_attempts"].append(worker_attempt_details)
|
|
108
527
|
|
|
109
|
-
|
|
528
|
+
# Store the actual token usage for this specific task
|
|
529
|
+
task.additional_info["token_usage"] = {"total_tokens": total_tokens}
|
|
110
530
|
|
|
111
|
-
|
|
112
|
-
|
|
531
|
+
print(f"======\n{Fore.GREEN}Response from {self}:{Fore.RESET}")
|
|
532
|
+
logger.info(f"Response from {self}:")
|
|
113
533
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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]
|
|
118
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]
|
|
119
555
|
|
|
120
|
-
if task_result.failed:
|
|
556
|
+
if task_result.failed: # type: ignore[union-attr]
|
|
121
557
|
return TaskState.FAILED
|
|
122
558
|
|
|
123
|
-
if
|
|
124
|
-
|
|
125
|
-
f"
|
|
126
|
-
f"task marked as failed
|
|
559
|
+
if is_task_result_insufficient(task):
|
|
560
|
+
logger.warning(
|
|
561
|
+
f"Task {task.id}: Content validation failed - "
|
|
562
|
+
f"task marked as failed"
|
|
127
563
|
)
|
|
128
564
|
return TaskState.FAILED
|
|
129
|
-
|
|
130
|
-
task.result = task_result.content
|
|
131
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
|
+
)
|