camel-ai 0.2.65__py3-none-any.whl → 0.2.83a6__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 +5107 -995
- 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 +29 -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/function_gemma_config.py +59 -0
- 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 +109 -230
- 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 +18 -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 +214 -115
- camel/models/base_audio_model.py +5 -3
- camel/models/base_model.py +378 -31
- camel/models/cerebras_model.py +83 -0
- camel/models/cohere_model.py +18 -49
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +11 -18
- camel/models/deepseek_model.py +20 -84
- camel/models/fish_audio_model.py +8 -2
- camel/models/function_gemma_model.py +889 -0
- camel/models/gemini_model.py +391 -52
- camel/models/groq_model.py +11 -19
- camel/models/internlm_model.py +11 -18
- camel/models/litellm_model.py +57 -49
- camel/models/lmstudio_model.py +17 -20
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +20 -47
- camel/models/model_factory.py +39 -3
- camel/models/model_manager.py +26 -8
- camel/models/modelscope_model.py +13 -193
- camel/models/moonshot_model.py +183 -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 +190 -71
- camel/models/openai_model.py +192 -86
- 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 +23 -49
- 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 +50 -75
- camel/models/sglang_model.py +90 -68
- 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 +158 -19
- camel/models/watsonx_model.py +9 -47
- 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 +145 -0
- camel/societies/workforce/prompts.py +259 -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 +5354 -372
- 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 +57 -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 +106 -6
- 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 +205 -27
- 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 +1958 -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 +1940 -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 +325 -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 +728 -0
- camel/toolkits/microsoft_outlook_mail_toolkit.py +1885 -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 +606 -156
- 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 +1281 -0
- camel/toolkits/terminal_toolkit/utils.py +659 -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 +381 -41
- camel/types/mcp_registries.py +2 -2
- camel/types/openai_types.py +4 -4
- camel/types/unified_model_type.py +46 -10
- camel/utils/__init__.py +5 -2
- camel/utils/agent_context.py +41 -0
- 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 +18 -10
- 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.83a6.dist-info}/METADATA +355 -117
- camel_ai-0.2.83a6.dist-info/RECORD +511 -0
- {camel_ai-0.2.65.dist-info → camel_ai-0.2.83a6.dist-info}/WHEEL +1 -1
- {camel_ai-0.2.65.dist-info → camel_ai-0.2.83a6.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
camel/toolkits/search_toolkit.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ========= Copyright 2023-
|
|
1
|
+
# ========= Copyright 2023-2026 @ 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,15 +10,23 @@
|
|
|
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-2026 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import os
|
|
15
|
+
import warnings
|
|
15
16
|
from typing import Any, Dict, List, Literal, Optional, TypeAlias, Union, cast
|
|
16
17
|
|
|
17
18
|
import requests
|
|
18
19
|
|
|
20
|
+
from camel.logger import get_logger
|
|
19
21
|
from camel.toolkits.base import BaseToolkit
|
|
20
22
|
from camel.toolkits.function_tool import FunctionTool
|
|
21
|
-
from camel.utils import
|
|
23
|
+
from camel.utils import (
|
|
24
|
+
MCPServer,
|
|
25
|
+
api_keys_required,
|
|
26
|
+
dependencies_required,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
logger = get_logger(__name__)
|
|
22
30
|
|
|
23
31
|
|
|
24
32
|
@MCPServer()
|
|
@@ -29,6 +37,78 @@ class SearchToolkit(BaseToolkit):
|
|
|
29
37
|
search engines like Google, DuckDuckGo, Wikipedia and Wolfram Alpha, Brave.
|
|
30
38
|
"""
|
|
31
39
|
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
timeout: Optional[float] = None,
|
|
43
|
+
exclude_domains: Optional[List[str]] = None,
|
|
44
|
+
):
|
|
45
|
+
r"""Initializes the SearchToolkit.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
timeout (float): Timeout for API requests in seconds.
|
|
49
|
+
(default: :obj:`None`)
|
|
50
|
+
exclude_domains (Optional[List[str]]): List of domains to
|
|
51
|
+
exclude from search results. Currently only supported
|
|
52
|
+
by the `search_google` function.
|
|
53
|
+
(default: :obj:`None`)
|
|
54
|
+
"""
|
|
55
|
+
super().__init__(timeout=timeout)
|
|
56
|
+
self.exclude_domains = exclude_domains
|
|
57
|
+
|
|
58
|
+
@api_keys_required(
|
|
59
|
+
[
|
|
60
|
+
(None, "SERPER_API_KEY"),
|
|
61
|
+
]
|
|
62
|
+
)
|
|
63
|
+
def search_serper(
|
|
64
|
+
self,
|
|
65
|
+
query: str,
|
|
66
|
+
page: int = 10,
|
|
67
|
+
location: str = "United States",
|
|
68
|
+
) -> Dict[str, Any]:
|
|
69
|
+
r"""Use Serper.dev API to perform Google search.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
query (str): The search query.
|
|
73
|
+
page (int): The page number of results to retrieve.
|
|
74
|
+
(default: :obj:`10`)
|
|
75
|
+
location (str): The location for the search results.
|
|
76
|
+
(default: :obj:`"United States"`)
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Dict[str, Any]: The search result dictionary containing 'organic',
|
|
80
|
+
'peopleAlsoAsk', etc.
|
|
81
|
+
"""
|
|
82
|
+
SERPER_API_KEY = os.getenv("SERPER_API_KEY")
|
|
83
|
+
|
|
84
|
+
url = "https://google.serper.dev/search"
|
|
85
|
+
|
|
86
|
+
payload = {
|
|
87
|
+
"q": query,
|
|
88
|
+
"location": location,
|
|
89
|
+
"page": page,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
headers = {
|
|
93
|
+
"X-API-KEY": SERPER_API_KEY,
|
|
94
|
+
"Content-Type": "application/json",
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
response = requests.post(
|
|
99
|
+
url, headers=headers, json=payload, timeout=self.timeout
|
|
100
|
+
)
|
|
101
|
+
if response.status_code != 200:
|
|
102
|
+
return {
|
|
103
|
+
"error": (
|
|
104
|
+
f"Serper API failed with status {response.status_code}: "
|
|
105
|
+
f"{response.text}"
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
return response.json()
|
|
109
|
+
except requests.exceptions.RequestException as e:
|
|
110
|
+
return {"error": f"Serper search failed: {e!s}"}
|
|
111
|
+
|
|
32
112
|
@dependencies_required("wikipedia")
|
|
33
113
|
def search_wiki(self, entity: str) -> str:
|
|
34
114
|
r"""Search the entity in WikiPedia and return the summary of the
|
|
@@ -86,8 +166,8 @@ class SearchToolkit(BaseToolkit):
|
|
|
86
166
|
depth (Literal["standard", "deep"]): The depth of the search.
|
|
87
167
|
"standard" for a straightforward search, "deep" for a more
|
|
88
168
|
comprehensive search.
|
|
89
|
-
output_type (Literal["searchResults", "sourcedAnswer",
|
|
90
|
-
|
|
169
|
+
output_type (Literal["searchResults", "sourcedAnswer", "structured"]):
|
|
170
|
+
The type of output:
|
|
91
171
|
- "searchResults" for raw search results,
|
|
92
172
|
- "sourcedAnswer" for an answer with supporting sources,
|
|
93
173
|
- "structured" for output based on a provided schema.
|
|
@@ -139,9 +219,12 @@ class SearchToolkit(BaseToolkit):
|
|
|
139
219
|
except Exception as e:
|
|
140
220
|
return {"error": f"An unexpected error occurred: {e!s}"}
|
|
141
221
|
|
|
142
|
-
@dependencies_required("
|
|
222
|
+
@dependencies_required("ddgs")
|
|
143
223
|
def search_duckduckgo(
|
|
144
|
-
self,
|
|
224
|
+
self,
|
|
225
|
+
query: str,
|
|
226
|
+
source: str = "text",
|
|
227
|
+
number_of_result_pages: int = 10,
|
|
145
228
|
) -> List[Dict[str, Any]]:
|
|
146
229
|
r"""Use DuckDuckGo search engine to search information for
|
|
147
230
|
the given query.
|
|
@@ -154,76 +237,79 @@ class SearchToolkit(BaseToolkit):
|
|
|
154
237
|
query (str): The query to be searched.
|
|
155
238
|
source (str): The type of information to query (e.g., "text",
|
|
156
239
|
"images", "videos"). Defaults to "text".
|
|
157
|
-
|
|
240
|
+
number_of_result_pages (int): The number of result pages to
|
|
241
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
242
|
+
for focused searches and more for comprehensive searches.
|
|
243
|
+
(default: :obj:`10`)
|
|
158
244
|
|
|
159
245
|
Returns:
|
|
160
246
|
List[Dict[str, Any]]: A list of dictionaries where each dictionary
|
|
161
247
|
represents a search result.
|
|
162
248
|
"""
|
|
163
|
-
from
|
|
164
|
-
from requests.exceptions import RequestException
|
|
249
|
+
from ddgs import DDGS
|
|
165
250
|
|
|
166
251
|
ddgs = DDGS()
|
|
167
252
|
responses: List[Dict[str, Any]] = []
|
|
168
253
|
|
|
169
254
|
if source == "text":
|
|
170
255
|
try:
|
|
171
|
-
results = ddgs.text(
|
|
172
|
-
|
|
256
|
+
results = ddgs.text(query, max_results=number_of_result_pages)
|
|
257
|
+
# Iterate over results found
|
|
258
|
+
for i, result in enumerate(results, start=1):
|
|
259
|
+
# Creating a response object with a similar structure
|
|
260
|
+
response = {
|
|
261
|
+
"result_id": i,
|
|
262
|
+
"title": result["title"],
|
|
263
|
+
"description": result["body"],
|
|
264
|
+
"url": result["href"],
|
|
265
|
+
}
|
|
266
|
+
responses.append(response)
|
|
267
|
+
except Exception as e:
|
|
173
268
|
# Handle specific exceptions or general request exceptions
|
|
174
269
|
responses.append({"error": f"duckduckgo search failed.{e}"})
|
|
175
270
|
|
|
176
|
-
# Iterate over results found
|
|
177
|
-
for i, result in enumerate(results, start=1):
|
|
178
|
-
# Creating a response object with a similar structure
|
|
179
|
-
response = {
|
|
180
|
-
"result_id": i,
|
|
181
|
-
"title": result["title"],
|
|
182
|
-
"description": result["body"],
|
|
183
|
-
"url": result["href"],
|
|
184
|
-
}
|
|
185
|
-
responses.append(response)
|
|
186
|
-
|
|
187
271
|
elif source == "images":
|
|
188
272
|
try:
|
|
189
|
-
results = ddgs.images(
|
|
190
|
-
|
|
273
|
+
results = ddgs.images(
|
|
274
|
+
query, max_results=number_of_result_pages
|
|
275
|
+
)
|
|
276
|
+
# Iterate over results found
|
|
277
|
+
for i, result in enumerate(results, start=1):
|
|
278
|
+
# Creating a response object with a similar structure
|
|
279
|
+
response = {
|
|
280
|
+
"result_id": i,
|
|
281
|
+
"title": result["title"],
|
|
282
|
+
"image": result["image"],
|
|
283
|
+
"url": result["url"],
|
|
284
|
+
"source": result["source"],
|
|
285
|
+
}
|
|
286
|
+
responses.append(response)
|
|
287
|
+
except Exception as e:
|
|
191
288
|
# Handle specific exceptions or general request exceptions
|
|
192
289
|
responses.append({"error": f"duckduckgo search failed.{e}"})
|
|
193
290
|
|
|
194
|
-
# Iterate over results found
|
|
195
|
-
for i, result in enumerate(results, start=1):
|
|
196
|
-
# Creating a response object with a similar structure
|
|
197
|
-
response = {
|
|
198
|
-
"result_id": i,
|
|
199
|
-
"title": result["title"],
|
|
200
|
-
"image": result["image"],
|
|
201
|
-
"url": result["url"],
|
|
202
|
-
"source": result["source"],
|
|
203
|
-
}
|
|
204
|
-
responses.append(response)
|
|
205
|
-
|
|
206
291
|
elif source == "videos":
|
|
207
292
|
try:
|
|
208
|
-
results = ddgs.videos(
|
|
209
|
-
|
|
293
|
+
results = ddgs.videos(
|
|
294
|
+
query, max_results=number_of_result_pages
|
|
295
|
+
)
|
|
296
|
+
# Iterate over results found
|
|
297
|
+
for i, result in enumerate(results, start=1):
|
|
298
|
+
# Creating a response object with a similar structure
|
|
299
|
+
response = {
|
|
300
|
+
"result_id": i,
|
|
301
|
+
"title": result["title"],
|
|
302
|
+
"description": result["description"],
|
|
303
|
+
"embed_url": result["embed_url"],
|
|
304
|
+
"publisher": result["publisher"],
|
|
305
|
+
"duration": result["duration"],
|
|
306
|
+
"published": result["published"],
|
|
307
|
+
}
|
|
308
|
+
responses.append(response)
|
|
309
|
+
except Exception as e:
|
|
210
310
|
# Handle specific exceptions or general request exceptions
|
|
211
311
|
responses.append({"error": f"duckduckgo search failed.{e}"})
|
|
212
312
|
|
|
213
|
-
# Iterate over results found
|
|
214
|
-
for i, result in enumerate(results, start=1):
|
|
215
|
-
# Creating a response object with a similar structure
|
|
216
|
-
response = {
|
|
217
|
-
"result_id": i,
|
|
218
|
-
"title": result["title"],
|
|
219
|
-
"description": result["description"],
|
|
220
|
-
"embed_url": result["embed_url"],
|
|
221
|
-
"publisher": result["publisher"],
|
|
222
|
-
"duration": result["duration"],
|
|
223
|
-
"published": result["published"],
|
|
224
|
-
}
|
|
225
|
-
responses.append(response)
|
|
226
|
-
|
|
227
313
|
# If no answer found, return an empty list
|
|
228
314
|
return responses
|
|
229
315
|
|
|
@@ -238,7 +324,6 @@ class SearchToolkit(BaseToolkit):
|
|
|
238
324
|
country: str = "US",
|
|
239
325
|
search_lang: str = "en",
|
|
240
326
|
ui_lang: str = "en-US",
|
|
241
|
-
count: int = 20,
|
|
242
327
|
offset: int = 0,
|
|
243
328
|
safesearch: str = "moderate",
|
|
244
329
|
freshness: Optional[str] = None,
|
|
@@ -249,6 +334,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
249
334
|
units: Optional[str] = None,
|
|
250
335
|
extra_snippets: Optional[bool] = None,
|
|
251
336
|
summary: Optional[bool] = None,
|
|
337
|
+
number_of_result_pages: int = 10,
|
|
252
338
|
) -> Dict[str, Any]:
|
|
253
339
|
r"""This function queries the Brave search engine API and returns a
|
|
254
340
|
dictionary, representing a search result.
|
|
@@ -262,17 +348,18 @@ class SearchToolkit(BaseToolkit):
|
|
|
262
348
|
The country string is limited to 2 character country codes of
|
|
263
349
|
supported countries. For a list of supported values, see
|
|
264
350
|
Country Codes. (default: :obj:`US `)
|
|
265
|
-
search_lang (str): The search language preference.
|
|
266
|
-
|
|
267
|
-
|
|
351
|
+
search_lang (str): The search language preference.
|
|
352
|
+
Use ONLY these exact values, NOT standard ISO codes:
|
|
353
|
+
'ar', 'eu', 'bn', 'bg', 'ca', 'zh-hans', 'zh-hant', 'hr',
|
|
354
|
+
'cs', 'da', 'nl', 'en', 'en-gb', 'et', 'fi', 'fr', 'gl', 'de',
|
|
355
|
+
'gu', 'he', 'hi', 'hu', 'is', 'it', 'jp', 'kn', 'ko', 'lv',
|
|
356
|
+
'lt', 'ms', 'ml', 'mr', 'nb', 'pl', 'pt-br', 'pt-pt', 'pa',
|
|
357
|
+
'ro', 'ru', 'sr', 'sk', 'sl', 'es', 'sv', 'ta', 'te', 'th',
|
|
358
|
+
'tr', 'uk', 'vi'.
|
|
268
359
|
ui_lang (str): User interface language preferred in response.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
count (int): The number of search results returned in response.
|
|
273
|
-
The maximum is 20. The actual number delivered may be less than
|
|
274
|
-
requested. Combine this parameter with offset to paginate
|
|
275
|
-
search results.
|
|
360
|
+
Format: '<language_code>-<country_code>'. Common examples:
|
|
361
|
+
'en-US', 'en-GB', 'jp-JP', 'zh-hans-CN', 'zh-hant-TW',
|
|
362
|
+
'de-DE', 'fr-FR', 'es-ES', 'pt-BR', 'ru-RU', 'ko-KR'.
|
|
276
363
|
offset (int): The zero based offset that indicates number of search
|
|
277
364
|
results per page (count) to skip before returning the result.
|
|
278
365
|
The maximum is 9. The actual number delivered may be less than
|
|
@@ -334,13 +421,15 @@ class SearchToolkit(BaseToolkit):
|
|
|
334
421
|
summary (Optional[bool]): This parameter enables summary key
|
|
335
422
|
generation in web search results. This is required for
|
|
336
423
|
summarizer to be enabled.
|
|
424
|
+
number_of_result_pages (int): The number of result pages to
|
|
425
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
426
|
+
for focused searches and more for comprehensive searches.
|
|
427
|
+
(default: :obj:`10`)
|
|
337
428
|
|
|
338
429
|
Returns:
|
|
339
430
|
Dict[str, Any]: A dictionary representing a search result.
|
|
340
431
|
"""
|
|
341
432
|
|
|
342
|
-
import requests
|
|
343
|
-
|
|
344
433
|
BRAVE_API_KEY = os.getenv("BRAVE_API_KEY")
|
|
345
434
|
|
|
346
435
|
url = "https://api.search.brave.com/res/v1/web/search"
|
|
@@ -360,7 +449,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
360
449
|
"country": country,
|
|
361
450
|
"search_lang": search_lang,
|
|
362
451
|
"ui_lang": ui_lang,
|
|
363
|
-
"count":
|
|
452
|
+
"count": number_of_result_pages,
|
|
364
453
|
"offset": offset,
|
|
365
454
|
"safesearch": safesearch,
|
|
366
455
|
"freshness": freshness,
|
|
@@ -372,10 +461,38 @@ class SearchToolkit(BaseToolkit):
|
|
|
372
461
|
"extra_snippets": extra_snippets,
|
|
373
462
|
"summary": summary,
|
|
374
463
|
}
|
|
464
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
375
465
|
|
|
376
|
-
response = requests.get(
|
|
377
|
-
|
|
378
|
-
|
|
466
|
+
response = requests.get(
|
|
467
|
+
url, headers=headers, params=params, timeout=self.timeout
|
|
468
|
+
)
|
|
469
|
+
try:
|
|
470
|
+
response.raise_for_status()
|
|
471
|
+
except requests.HTTPError as e:
|
|
472
|
+
raise RuntimeError(
|
|
473
|
+
f"Brave API HTTP error: {e}, body={response.text!r}"
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
json_data = response.json()
|
|
477
|
+
# Check if response has search results
|
|
478
|
+
content_keys = [
|
|
479
|
+
'web',
|
|
480
|
+
'news',
|
|
481
|
+
'videos',
|
|
482
|
+
'images',
|
|
483
|
+
'locations',
|
|
484
|
+
'discussions',
|
|
485
|
+
'faq',
|
|
486
|
+
'infobox',
|
|
487
|
+
]
|
|
488
|
+
has_results = any(key in json_data for key in content_keys)
|
|
489
|
+
|
|
490
|
+
if not has_results:
|
|
491
|
+
# Return empty results structure if no content found
|
|
492
|
+
json_data['web'] = {'results': []}
|
|
493
|
+
json_data['message'] = 'No search results found for the query'
|
|
494
|
+
|
|
495
|
+
return json_data
|
|
379
496
|
|
|
380
497
|
@api_keys_required(
|
|
381
498
|
[
|
|
@@ -384,25 +501,53 @@ class SearchToolkit(BaseToolkit):
|
|
|
384
501
|
]
|
|
385
502
|
)
|
|
386
503
|
def search_google(
|
|
387
|
-
self,
|
|
504
|
+
self,
|
|
505
|
+
query: str,
|
|
506
|
+
search_type: str = "web",
|
|
507
|
+
number_of_result_pages: int = 10,
|
|
508
|
+
start_page: int = 1,
|
|
388
509
|
) -> List[Dict[str, Any]]:
|
|
389
510
|
r"""Use Google search engine to search information for the given query.
|
|
390
511
|
|
|
391
512
|
Args:
|
|
392
513
|
query (str): The query to be searched.
|
|
393
|
-
|
|
514
|
+
search_type (str): The type of search to perform. Must be either
|
|
515
|
+
"web" for web pages or "image" for image search. Any other
|
|
516
|
+
value will raise a ValueError. (default: "web")
|
|
517
|
+
number_of_result_pages (int): The number of result pages to
|
|
518
|
+
retrieve. Must be a positive integer between 1 and 10.
|
|
519
|
+
Google Custom Search API limits results to 10 per request.
|
|
520
|
+
If a value greater than 10 is provided, it will be capped
|
|
521
|
+
at 10 with a warning. Adjust this based on your task - use
|
|
522
|
+
fewer results for focused searches and more for comprehensive
|
|
523
|
+
searches. (default: :obj:`10`)
|
|
524
|
+
start_page (int): The result page to start from. Must be a
|
|
525
|
+
positive integer (>= 1). Use this for pagination - e.g.,
|
|
526
|
+
start_page=1 for results 1-10, start_page=11 for results
|
|
527
|
+
11-20, etc. This allows agents to check initial results
|
|
528
|
+
and continue searching if needed. (default: :obj:`1`)
|
|
394
529
|
|
|
395
530
|
Returns:
|
|
396
531
|
List[Dict[str, Any]]: A list of dictionaries where each dictionary
|
|
397
|
-
represents a
|
|
398
|
-
|
|
532
|
+
represents a search result.
|
|
533
|
+
|
|
534
|
+
For web search, each dictionary contains:
|
|
399
535
|
- 'result_id': A number in order.
|
|
400
536
|
- 'title': The title of the website.
|
|
401
537
|
- 'description': A brief description of the website.
|
|
402
538
|
- 'long_description': More detail of the website.
|
|
403
539
|
- 'url': The URL of the website.
|
|
404
540
|
|
|
405
|
-
|
|
541
|
+
For image search, each dictionary contains:
|
|
542
|
+
- 'result_id': A number in order.
|
|
543
|
+
- 'title': The title of the image.
|
|
544
|
+
- 'image_url': The URL of the image.
|
|
545
|
+
- 'display_link': The website hosting the image.
|
|
546
|
+
- 'context_url': The URL of the page containing the image.
|
|
547
|
+
- 'width': Image width in pixels (if available).
|
|
548
|
+
- 'height': Image height in pixels (if available).
|
|
549
|
+
|
|
550
|
+
Example web result:
|
|
406
551
|
{
|
|
407
552
|
'result_id': 1,
|
|
408
553
|
'title': 'OpenAI',
|
|
@@ -414,89 +559,192 @@ class SearchToolkit(BaseToolkit):
|
|
|
414
559
|
benefit humanity as a whole',
|
|
415
560
|
'url': 'https://www.openai.com'
|
|
416
561
|
}
|
|
417
|
-
|
|
562
|
+
|
|
563
|
+
Example image result:
|
|
564
|
+
{
|
|
565
|
+
'result_id': 1,
|
|
566
|
+
'title': 'Beautiful Sunset',
|
|
567
|
+
'image_url': 'https://example.com/image.jpg',
|
|
568
|
+
'display_link': 'example.com',
|
|
569
|
+
'context_url': 'https://example.com/page.html',
|
|
570
|
+
'width': 800,
|
|
571
|
+
'height': 600
|
|
572
|
+
}
|
|
418
573
|
"""
|
|
419
|
-
import
|
|
574
|
+
from urllib.parse import quote
|
|
575
|
+
|
|
576
|
+
# Validate input parameters
|
|
577
|
+
if not isinstance(start_page, int) or start_page < 1:
|
|
578
|
+
raise ValueError("start_page must be a positive integer")
|
|
579
|
+
|
|
580
|
+
if (
|
|
581
|
+
not isinstance(number_of_result_pages, int)
|
|
582
|
+
or number_of_result_pages < 1
|
|
583
|
+
):
|
|
584
|
+
raise ValueError(
|
|
585
|
+
"number_of_result_pages must be a positive integer"
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
# Google Custom Search API has a limit of 10 results per request
|
|
589
|
+
if number_of_result_pages > 10:
|
|
590
|
+
logger.warning(
|
|
591
|
+
f"Google API limits results to 10 per request. "
|
|
592
|
+
f"Requested {number_of_result_pages}, using 10 instead."
|
|
593
|
+
)
|
|
594
|
+
number_of_result_pages = 10
|
|
595
|
+
|
|
596
|
+
if search_type not in ["web", "image"]:
|
|
597
|
+
raise ValueError("search_type must be either 'web' or 'image'")
|
|
420
598
|
|
|
421
599
|
# https://developers.google.com/custom-search/v1/overview
|
|
422
600
|
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
|
423
601
|
# https://cse.google.com/cse/all
|
|
424
602
|
SEARCH_ENGINE_ID = os.getenv("SEARCH_ENGINE_ID")
|
|
425
603
|
|
|
426
|
-
# Using the
|
|
427
|
-
start_page_idx =
|
|
604
|
+
# Using the specified start page
|
|
605
|
+
start_page_idx = start_page
|
|
428
606
|
# Different language may get different result
|
|
429
607
|
search_language = "en"
|
|
430
|
-
|
|
431
|
-
|
|
608
|
+
|
|
609
|
+
modified_query = query
|
|
610
|
+
if self.exclude_domains:
|
|
611
|
+
# Use Google's -site: operator to exclude domains
|
|
612
|
+
exclusion_terms = " ".join(
|
|
613
|
+
[f"-site:{domain}" for domain in self.exclude_domains]
|
|
614
|
+
)
|
|
615
|
+
modified_query = f"{query} {exclusion_terms}"
|
|
616
|
+
logger.debug(f"Excluded domains, modified query: {modified_query}")
|
|
617
|
+
|
|
618
|
+
encoded_query = quote(modified_query)
|
|
619
|
+
|
|
432
620
|
# Constructing the URL
|
|
433
621
|
# Doc: https://developers.google.com/custom-search/v1/using_rest
|
|
434
|
-
|
|
622
|
+
base_url = (
|
|
435
623
|
f"https://www.googleapis.com/customsearch/v1?"
|
|
436
|
-
f"key={GOOGLE_API_KEY}&cx={SEARCH_ENGINE_ID}&q={
|
|
437
|
-
f"{start_page_idx}&lr={search_language}&num={
|
|
624
|
+
f"key={GOOGLE_API_KEY}&cx={SEARCH_ENGINE_ID}&q={encoded_query}&start="
|
|
625
|
+
f"{start_page_idx}&lr={search_language}&num={number_of_result_pages}"
|
|
438
626
|
)
|
|
439
627
|
|
|
628
|
+
# Add searchType parameter for image search
|
|
629
|
+
if search_type == "image":
|
|
630
|
+
url = base_url + "&searchType=image"
|
|
631
|
+
else:
|
|
632
|
+
url = base_url
|
|
633
|
+
|
|
440
634
|
responses = []
|
|
441
635
|
# Fetch the results given the URL
|
|
442
636
|
try:
|
|
443
637
|
# Make the get
|
|
444
|
-
result = requests.get(url)
|
|
638
|
+
result = requests.get(url, timeout=self.timeout)
|
|
445
639
|
data = result.json()
|
|
446
640
|
|
|
447
641
|
# Get the result items
|
|
448
642
|
if "items" in data:
|
|
449
643
|
search_items = data.get("items")
|
|
450
644
|
|
|
451
|
-
# Iterate over
|
|
645
|
+
# Iterate over results found
|
|
452
646
|
for i, search_item in enumerate(search_items, start=1):
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
647
|
+
if search_type == "image":
|
|
648
|
+
# Process image search results
|
|
649
|
+
title = search_item.get("title")
|
|
650
|
+
image_url = search_item.get("link")
|
|
651
|
+
display_link = search_item.get("displayLink")
|
|
652
|
+
|
|
653
|
+
# Get context URL (page containing the image)
|
|
654
|
+
image_info = search_item.get("image", {})
|
|
655
|
+
context_url = image_info.get("contextLink", "")
|
|
656
|
+
|
|
657
|
+
# Get image dimensions if available
|
|
658
|
+
width = image_info.get("width")
|
|
659
|
+
height = image_info.get("height")
|
|
660
|
+
|
|
661
|
+
response = {
|
|
662
|
+
"result_id": i,
|
|
663
|
+
"title": title,
|
|
664
|
+
"image_url": image_url,
|
|
665
|
+
"display_link": display_link,
|
|
666
|
+
"context_url": context_url,
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if width:
|
|
670
|
+
response["width"] = int(width)
|
|
671
|
+
if height:
|
|
672
|
+
response["height"] = int(height)
|
|
673
|
+
|
|
674
|
+
responses.append(response)
|
|
465
675
|
else:
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
"
|
|
480
|
-
|
|
481
|
-
|
|
676
|
+
if "pagemap" not in search_item:
|
|
677
|
+
continue
|
|
678
|
+
if "metatags" not in search_item["pagemap"]:
|
|
679
|
+
continue
|
|
680
|
+
if (
|
|
681
|
+
"og:description"
|
|
682
|
+
in search_item["pagemap"]["metatags"][0]
|
|
683
|
+
):
|
|
684
|
+
long_description = search_item["pagemap"][
|
|
685
|
+
"metatags"
|
|
686
|
+
][0]["og:description"]
|
|
687
|
+
else:
|
|
688
|
+
long_description = "N/A"
|
|
689
|
+
title = search_item.get("title")
|
|
690
|
+
snippet = search_item.get("snippet")
|
|
691
|
+
|
|
692
|
+
link = search_item.get("link")
|
|
693
|
+
response = {
|
|
694
|
+
"result_id": i,
|
|
695
|
+
"title": title,
|
|
696
|
+
"description": snippet,
|
|
697
|
+
"long_description": long_description,
|
|
698
|
+
"url": link,
|
|
699
|
+
}
|
|
700
|
+
responses.append(response)
|
|
482
701
|
else:
|
|
483
|
-
|
|
702
|
+
if "error" in data:
|
|
703
|
+
error_info = data.get("error", {})
|
|
704
|
+
logger.error(
|
|
705
|
+
f"Google search failed - API response: {error_info}"
|
|
706
|
+
)
|
|
707
|
+
responses.append(
|
|
708
|
+
{
|
|
709
|
+
"error": f"Google search failed - "
|
|
710
|
+
f"API response: {error_info}"
|
|
711
|
+
}
|
|
712
|
+
)
|
|
713
|
+
elif "searchInformation" in data:
|
|
714
|
+
search_info = data.get("searchInformation", {})
|
|
715
|
+
total_results = search_info.get("totalResults", "0")
|
|
716
|
+
if total_results == "0":
|
|
717
|
+
logger.info(f"No results found for query: {query}")
|
|
718
|
+
# Return empty list to indicate no results (not an error)
|
|
719
|
+
responses = []
|
|
720
|
+
else:
|
|
721
|
+
logger.warning(
|
|
722
|
+
f"Google search returned no items but claims {total_results} results"
|
|
723
|
+
)
|
|
724
|
+
responses = []
|
|
725
|
+
else:
|
|
726
|
+
logger.error(
|
|
727
|
+
f"Unexpected Google API response format: {data}"
|
|
728
|
+
)
|
|
729
|
+
responses.append(
|
|
730
|
+
{"error": "Unexpected response format from Google API"}
|
|
731
|
+
)
|
|
484
732
|
|
|
485
|
-
except
|
|
486
|
-
|
|
487
|
-
responses.append({"error": "google search failed."})
|
|
488
|
-
# If no answer found, return an empty list
|
|
733
|
+
except Exception as e:
|
|
734
|
+
responses.append({"error": f"google search failed: {e!s}"})
|
|
489
735
|
return responses
|
|
490
736
|
|
|
491
|
-
def
|
|
492
|
-
self, query: str,
|
|
737
|
+
def search_tavily(
|
|
738
|
+
self, query: str, number_of_result_pages: int = 10, **kwargs
|
|
493
739
|
) -> List[Dict[str, Any]]:
|
|
494
740
|
r"""Use Tavily Search API to search information for the given query.
|
|
495
741
|
|
|
496
742
|
Args:
|
|
497
743
|
query (str): The query to be searched.
|
|
498
|
-
|
|
499
|
-
|
|
744
|
+
number_of_result_pages (int): The number of result pages to
|
|
745
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
746
|
+
for focused searches and more for comprehensive searches.
|
|
747
|
+
(default: :obj:`10`)
|
|
500
748
|
**kwargs: Additional optional parameters supported by Tavily's API:
|
|
501
749
|
- search_depth (str): "basic" or "advanced" search depth.
|
|
502
750
|
- topic (str): The search category, e.g., "general" or "news."
|
|
@@ -532,7 +780,9 @@ class SearchToolkit(BaseToolkit):
|
|
|
532
780
|
client = TavilyClient(Tavily_API_KEY)
|
|
533
781
|
|
|
534
782
|
try:
|
|
535
|
-
results = client.search(
|
|
783
|
+
results = client.search(
|
|
784
|
+
query, max_results=number_of_result_pages, **kwargs
|
|
785
|
+
)
|
|
536
786
|
return results
|
|
537
787
|
except Exception as e:
|
|
538
788
|
return [{"error": f"An unexpected error occurred: {e!s}"}]
|
|
@@ -543,8 +793,8 @@ class SearchToolkit(BaseToolkit):
|
|
|
543
793
|
query: str,
|
|
544
794
|
freshness: str = "noLimit",
|
|
545
795
|
summary: bool = False,
|
|
546
|
-
count: int = 10,
|
|
547
796
|
page: int = 1,
|
|
797
|
+
number_of_result_pages: int = 10,
|
|
548
798
|
) -> Dict[str, Any]:
|
|
549
799
|
r"""Query the Bocha AI search API and return search results.
|
|
550
800
|
|
|
@@ -559,8 +809,11 @@ class SearchToolkit(BaseToolkit):
|
|
|
559
809
|
- 'oneYear': past year.
|
|
560
810
|
summary (bool): Whether to include text summaries in results.
|
|
561
811
|
Default is False.
|
|
562
|
-
count (int): Number of results to return (1-50). Default is 10.
|
|
563
812
|
page (int): Page number of results. Default is 1.
|
|
813
|
+
number_of_result_pages (int): The number of result pages to
|
|
814
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
815
|
+
for focused searches and more for comprehensive searches.
|
|
816
|
+
(default: :obj:`10`)
|
|
564
817
|
|
|
565
818
|
Returns:
|
|
566
819
|
Dict[str, Any]: A dictionary containing search results, including
|
|
@@ -582,13 +835,15 @@ class SearchToolkit(BaseToolkit):
|
|
|
582
835
|
"query": query,
|
|
583
836
|
"freshness": freshness,
|
|
584
837
|
"summary": summary,
|
|
585
|
-
"count":
|
|
838
|
+
"count": number_of_result_pages,
|
|
586
839
|
"page": page,
|
|
587
840
|
},
|
|
588
841
|
ensure_ascii=False,
|
|
589
842
|
)
|
|
590
843
|
try:
|
|
591
|
-
response = requests.post(
|
|
844
|
+
response = requests.post(
|
|
845
|
+
url, headers=headers, data=payload, timeout=self.timeout
|
|
846
|
+
)
|
|
592
847
|
if response.status_code != 200:
|
|
593
848
|
return {
|
|
594
849
|
"error": (
|
|
@@ -600,15 +855,19 @@ class SearchToolkit(BaseToolkit):
|
|
|
600
855
|
except requests.exceptions.RequestException as e:
|
|
601
856
|
return {"error": f"Bocha AI search failed: {e!s}"}
|
|
602
857
|
|
|
603
|
-
def search_baidu(
|
|
858
|
+
def search_baidu(
|
|
859
|
+
self, query: str, number_of_result_pages: int = 10
|
|
860
|
+
) -> Dict[str, Any]:
|
|
604
861
|
r"""Search Baidu using web scraping to retrieve relevant search
|
|
605
862
|
results. This method queries Baidu's search engine and extracts search
|
|
606
863
|
results including titles, descriptions, and URLs.
|
|
607
864
|
|
|
608
865
|
Args:
|
|
609
866
|
query (str): Search query string to submit to Baidu.
|
|
610
|
-
|
|
611
|
-
|
|
867
|
+
number_of_result_pages (int): The number of result pages to
|
|
868
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
869
|
+
for focused searches and more for comprehensive searches.
|
|
870
|
+
(default: :obj:`10`)
|
|
612
871
|
|
|
613
872
|
Returns:
|
|
614
873
|
Dict[str, Any]: A dictionary containing search results or error
|
|
@@ -626,9 +885,11 @@ class SearchToolkit(BaseToolkit):
|
|
|
626
885
|
),
|
|
627
886
|
"Referer": "https://www.baidu.com",
|
|
628
887
|
}
|
|
629
|
-
params = {"wd": query, "rn": str(
|
|
888
|
+
params = {"wd": query, "rn": str(number_of_result_pages)}
|
|
630
889
|
|
|
631
|
-
response = requests.get(
|
|
890
|
+
response = requests.get(
|
|
891
|
+
url, headers=headers, params=params, timeout=self.timeout
|
|
892
|
+
)
|
|
632
893
|
response.encoding = "utf-8"
|
|
633
894
|
|
|
634
895
|
soup = BeautifulSoup(response.text, "html.parser")
|
|
@@ -655,7 +916,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
655
916
|
"url": link,
|
|
656
917
|
}
|
|
657
918
|
)
|
|
658
|
-
if len(results) >=
|
|
919
|
+
if len(results) >= number_of_result_pages:
|
|
659
920
|
break
|
|
660
921
|
|
|
661
922
|
if not results:
|
|
@@ -669,7 +930,9 @@ class SearchToolkit(BaseToolkit):
|
|
|
669
930
|
except Exception as e:
|
|
670
931
|
return {"error": f"Baidu scraping error: {e!s}"}
|
|
671
932
|
|
|
672
|
-
def search_bing(
|
|
933
|
+
def search_bing(
|
|
934
|
+
self, query: str, number_of_result_pages: int = 10
|
|
935
|
+
) -> Dict[str, Any]:
|
|
673
936
|
r"""Use Bing search engine to search information for the given query.
|
|
674
937
|
|
|
675
938
|
This function queries the Chinese version of Bing search engine (cn.
|
|
@@ -681,8 +944,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
681
944
|
Args:
|
|
682
945
|
query (str): The search query string to submit to Bing. Works best
|
|
683
946
|
with Chinese queries or when Chinese results are preferred.
|
|
684
|
-
|
|
685
|
-
|
|
947
|
+
number_of_result_pages (int): The number of result pages to
|
|
948
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
949
|
+
for focused searches and more for comprehensive searches.
|
|
950
|
+
(default: :obj:`10`)
|
|
686
951
|
|
|
687
952
|
Returns:
|
|
688
953
|
Dict ([str, Any]): A dictionary containing either:
|
|
@@ -708,8 +973,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
708
973
|
"Chrome/120.0.0.0 Safari/537.36"
|
|
709
974
|
),
|
|
710
975
|
}
|
|
711
|
-
|
|
712
|
-
response = requests.get(url, headers=headers, timeout=10)
|
|
976
|
+
response = requests.get(url, headers=headers, timeout=self.timeout)
|
|
713
977
|
|
|
714
978
|
# Check if the request was successful
|
|
715
979
|
if response.status_code != 200:
|
|
@@ -732,7 +996,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
732
996
|
result_items = b_results_tag.find_all("li")
|
|
733
997
|
|
|
734
998
|
results: List[Dict[str, Any]] = []
|
|
735
|
-
for i in range(min(len(result_items),
|
|
999
|
+
for i in range(min(len(result_items), number_of_result_pages)):
|
|
736
1000
|
row = result_items[i]
|
|
737
1001
|
if not isinstance(row, Tag):
|
|
738
1002
|
continue
|
|
@@ -797,11 +1061,11 @@ class SearchToolkit(BaseToolkit):
|
|
|
797
1061
|
"financial report",
|
|
798
1062
|
]
|
|
799
1063
|
] = None,
|
|
800
|
-
num_results: int = 10,
|
|
801
1064
|
include_text: Optional[List[str]] = None,
|
|
802
1065
|
exclude_text: Optional[List[str]] = None,
|
|
803
1066
|
use_autoprompt: bool = True,
|
|
804
1067
|
text: bool = False,
|
|
1068
|
+
number_of_result_pages: int = 10,
|
|
805
1069
|
) -> Dict[str, Any]:
|
|
806
1070
|
r"""Use Exa search API to perform intelligent web search with optional
|
|
807
1071
|
content extraction.
|
|
@@ -813,8 +1077,6 @@ class SearchToolkit(BaseToolkit):
|
|
|
813
1077
|
and neural search. (default: :obj:`"auto"`)
|
|
814
1078
|
category (Optional[Literal]): Category to focus the search on, such
|
|
815
1079
|
as "research paper" or "news". (default: :obj:`None`)
|
|
816
|
-
num_results (int): Number of results to return (max 100).
|
|
817
|
-
(default: :obj:`10`)
|
|
818
1080
|
include_text (Optional[List[str]]): Strings that must be present in
|
|
819
1081
|
webpage text. Limited to 1 string of up to 5 words.
|
|
820
1082
|
(default: :obj:`None`)
|
|
@@ -825,6 +1087,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
825
1087
|
enhance the query. (default: :obj:`True`)
|
|
826
1088
|
text (bool): Whether to include webpage contents in results.
|
|
827
1089
|
(default: :obj:`False`)
|
|
1090
|
+
number_of_result_pages (int): The number of result pages to
|
|
1091
|
+
retrieve. Must be between 1 and 100. Adjust this based on
|
|
1092
|
+
your task - use fewer results for focused searches and more
|
|
1093
|
+
for comprehensive searches. (default: :obj:`10`)
|
|
828
1094
|
|
|
829
1095
|
Returns:
|
|
830
1096
|
Dict[str, Any]: A dict containing search results and metadata:
|
|
@@ -843,7 +1109,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
843
1109
|
try:
|
|
844
1110
|
exa = Exa(EXA_API_KEY)
|
|
845
1111
|
|
|
846
|
-
if
|
|
1112
|
+
if (
|
|
1113
|
+
number_of_result_pages is not None
|
|
1114
|
+
and not 0 < number_of_result_pages <= 100
|
|
1115
|
+
):
|
|
847
1116
|
raise ValueError("num_results must be between 1 and 100")
|
|
848
1117
|
|
|
849
1118
|
if include_text is not None:
|
|
@@ -870,7 +1139,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
870
1139
|
query=query,
|
|
871
1140
|
type=search_type,
|
|
872
1141
|
category=category,
|
|
873
|
-
num_results=
|
|
1142
|
+
num_results=number_of_result_pages,
|
|
874
1143
|
include_text=include_text,
|
|
875
1144
|
exclude_text=exclude_text,
|
|
876
1145
|
use_autoprompt=use_autoprompt,
|
|
@@ -884,7 +1153,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
884
1153
|
query=query,
|
|
885
1154
|
type=search_type,
|
|
886
1155
|
category=category,
|
|
887
|
-
num_results=
|
|
1156
|
+
num_results=number_of_result_pages,
|
|
888
1157
|
include_text=include_text,
|
|
889
1158
|
exclude_text=exclude_text,
|
|
890
1159
|
use_autoprompt=use_autoprompt,
|
|
@@ -914,10 +1183,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
914
1183
|
"news_center",
|
|
915
1184
|
]
|
|
916
1185
|
] = None,
|
|
917
|
-
page: int = 1,
|
|
918
1186
|
return_main_text: bool = False,
|
|
919
1187
|
return_markdown_text: bool = True,
|
|
920
1188
|
enable_rerank: bool = True,
|
|
1189
|
+
number_of_result_pages: int = 10,
|
|
921
1190
|
) -> Dict[str, Any]:
|
|
922
1191
|
r"""Query the Alibaba Tongxiao search API and return search results.
|
|
923
1192
|
|
|
@@ -931,17 +1200,14 @@ class SearchToolkit(BaseToolkit):
|
|
|
931
1200
|
|
|
932
1201
|
Args:
|
|
933
1202
|
query (str): The search query string (length >= 1 and <= 100).
|
|
934
|
-
time_range (Literal["OneDay", "OneWeek", "OneMonth", "OneYear",
|
|
935
|
-
|
|
1203
|
+
time_range (Literal["OneDay", "OneWeek", "OneMonth", "OneYear", "NoLimit"]):
|
|
1204
|
+
Time frame filter for search results.
|
|
936
1205
|
(default: :obj:`"NoLimit"`)
|
|
937
|
-
industry (Optional[Literal["finance", "law", "medical",
|
|
938
|
-
"internet", "tax", "news_province", "news_center"]]):
|
|
1206
|
+
industry (Optional[Literal["finance", "law", "medical", "internet", "tax", "news_province", "news_center"]]):
|
|
939
1207
|
Industry-specific search filter. When specified, only returns
|
|
940
1208
|
results from sites in the specified industries. Multiple
|
|
941
1209
|
industries can be comma-separated.
|
|
942
1210
|
(default: :obj:`None`)
|
|
943
|
-
page (int): Page number for results pagination.
|
|
944
|
-
(default: :obj:`1`)
|
|
945
1211
|
return_main_text (bool): Whether to include the main text of the
|
|
946
1212
|
webpage in results. (default: :obj:`True`)
|
|
947
1213
|
return_markdown_text (bool): Whether to include markdown formatted
|
|
@@ -949,6 +1215,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
949
1215
|
enable_rerank (bool): Whether to enable result reranking. If
|
|
950
1216
|
response time is critical, setting this to False can reduce
|
|
951
1217
|
response time by approximately 140ms. (default: :obj:`True`)
|
|
1218
|
+
number_of_result_pages (int): The number of result pages to
|
|
1219
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
1220
|
+
for focused searches and more for comprehensive searches.
|
|
1221
|
+
(default: :obj:`10`)
|
|
952
1222
|
|
|
953
1223
|
Returns:
|
|
954
1224
|
Dict[str, Any]: A dictionary containing either search results with
|
|
@@ -956,6 +1226,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
956
1226
|
message. Each result contains title, snippet, url and other
|
|
957
1227
|
metadata.
|
|
958
1228
|
"""
|
|
1229
|
+
|
|
959
1230
|
TONGXIAO_API_KEY = os.getenv("TONGXIAO_API_KEY")
|
|
960
1231
|
|
|
961
1232
|
# Validate query length
|
|
@@ -974,7 +1245,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
974
1245
|
params: Dict[str, Union[str, int]] = {
|
|
975
1246
|
"query": query,
|
|
976
1247
|
"timeRange": time_range,
|
|
977
|
-
"page":
|
|
1248
|
+
"page": number_of_result_pages,
|
|
978
1249
|
"returnMainText": str(return_main_text).lower(),
|
|
979
1250
|
"returnMarkdownText": str(return_markdown_text).lower(),
|
|
980
1251
|
"enableRerank": str(enable_rerank).lower(),
|
|
@@ -987,7 +1258,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
987
1258
|
try:
|
|
988
1259
|
# Send GET request with proper typing for params
|
|
989
1260
|
response = requests.get(
|
|
990
|
-
base_url, headers=headers, params=params, timeout=
|
|
1261
|
+
base_url, headers=headers, params=params, timeout=self.timeout
|
|
991
1262
|
)
|
|
992
1263
|
|
|
993
1264
|
# Check response status
|
|
@@ -1062,6 +1333,172 @@ class SearchToolkit(BaseToolkit):
|
|
|
1062
1333
|
f"search: {e!s}"
|
|
1063
1334
|
}
|
|
1064
1335
|
|
|
1336
|
+
@api_keys_required([(None, 'METASO_API_KEY')])
|
|
1337
|
+
def search_metaso(
|
|
1338
|
+
self,
|
|
1339
|
+
query: str,
|
|
1340
|
+
page: int = 1,
|
|
1341
|
+
include_summary: bool = False,
|
|
1342
|
+
include_raw_content: bool = False,
|
|
1343
|
+
concise_snippet: bool = False,
|
|
1344
|
+
scope: Literal[
|
|
1345
|
+
"webpage", "document", "scholar", "image", "video", "podcast"
|
|
1346
|
+
] = "webpage",
|
|
1347
|
+
) -> Dict[str, Any]:
|
|
1348
|
+
r"""Perform a web search using the metaso.cn API.
|
|
1349
|
+
|
|
1350
|
+
Args:
|
|
1351
|
+
query (str): The search query string.
|
|
1352
|
+
page (int): Page number. (default: :obj:`1`)
|
|
1353
|
+
include_summary (bool): Whether to include summary in the result.
|
|
1354
|
+
(default: :obj:`False`)
|
|
1355
|
+
include_raw_content (bool): Whether to include raw content in the
|
|
1356
|
+
result. (default: :obj:`False`)
|
|
1357
|
+
concise_snippet (bool): Whether to return concise snippet.
|
|
1358
|
+
(default: :obj:`False`)
|
|
1359
|
+
scope (Literal["webpage", "document", "scholar", "image", "video",
|
|
1360
|
+
"podcast"]): Search scope. (default: :obj:`"webpage"`)
|
|
1361
|
+
|
|
1362
|
+
Returns:
|
|
1363
|
+
Dict[str, Any]: Search results or error information.
|
|
1364
|
+
"""
|
|
1365
|
+
import http.client
|
|
1366
|
+
import json
|
|
1367
|
+
|
|
1368
|
+
# It is recommended to put the token in environment variable for
|
|
1369
|
+
# security
|
|
1370
|
+
|
|
1371
|
+
METASO_API_KEY = os.getenv("METASO_API_KEY")
|
|
1372
|
+
|
|
1373
|
+
conn = http.client.HTTPSConnection("metaso.cn")
|
|
1374
|
+
payload = json.dumps(
|
|
1375
|
+
{
|
|
1376
|
+
"q": query,
|
|
1377
|
+
"scope": scope,
|
|
1378
|
+
"includeSummary": include_summary,
|
|
1379
|
+
"page": str(page),
|
|
1380
|
+
"includeRawContent": include_raw_content,
|
|
1381
|
+
"conciseSnippet": concise_snippet,
|
|
1382
|
+
}
|
|
1383
|
+
)
|
|
1384
|
+
headers = {
|
|
1385
|
+
'Authorization': f'Bearer {METASO_API_KEY}',
|
|
1386
|
+
'Accept': 'application/json',
|
|
1387
|
+
'Content-Type': 'application/json',
|
|
1388
|
+
}
|
|
1389
|
+
try:
|
|
1390
|
+
conn.request("POST", "/api/v1/search", payload, headers)
|
|
1391
|
+
res = conn.getresponse()
|
|
1392
|
+
data = res.read()
|
|
1393
|
+
result = data.decode("utf-8")
|
|
1394
|
+
try:
|
|
1395
|
+
return json.loads(result)
|
|
1396
|
+
except Exception:
|
|
1397
|
+
return {
|
|
1398
|
+
"error": f"Metaso returned content could not be parsed: {result}"
|
|
1399
|
+
}
|
|
1400
|
+
except Exception as e:
|
|
1401
|
+
return {"error": f"Metaso search failed: {e}"}
|
|
1402
|
+
|
|
1403
|
+
@dependencies_required("google-search-results")
|
|
1404
|
+
@api_keys_required([(None, 'SERPAPI_KEY')])
|
|
1405
|
+
def search_serpapi(
|
|
1406
|
+
self,
|
|
1407
|
+
query: str,
|
|
1408
|
+
engine: str = "google",
|
|
1409
|
+
location: str = "Austin,Texas",
|
|
1410
|
+
google_domain: str = "google.com",
|
|
1411
|
+
gl: str = "us",
|
|
1412
|
+
search_lang: str = "en",
|
|
1413
|
+
device: str = "desktop",
|
|
1414
|
+
number_of_result_pages: int = 1,
|
|
1415
|
+
safe: str = "off",
|
|
1416
|
+
filter: int = 0,
|
|
1417
|
+
custom_params: Optional[Dict[str, Any]] = None,
|
|
1418
|
+
) -> Dict[str, Any]:
|
|
1419
|
+
r"""Use SerpApi search engine to search information for the given query.
|
|
1420
|
+
|
|
1421
|
+
SerpApi provides real-time search engine results from multiple search engines
|
|
1422
|
+
including Google, Bing, Yahoo, DuckDuckGo, Baidu, Yandex, and more.
|
|
1423
|
+
|
|
1424
|
+
Args:
|
|
1425
|
+
query (str): The search query string.
|
|
1426
|
+
engine (str): Search engine to use. Supported engines include:
|
|
1427
|
+
'google', 'bing', 'yahoo', 'duckduckgo', 'baidu', 'yandex',
|
|
1428
|
+
'youtube', 'ebay', 'amazon', etc. (default: :obj:`"google"`)
|
|
1429
|
+
location (str): Location for localized search results. Can be a city,
|
|
1430
|
+
state, country, or coordinates. (default: :obj:`"Austin,Texas"`)
|
|
1431
|
+
google_domain (str): Google domain to use (e.g., 'google.com', 'google.co.uk').
|
|
1432
|
+
Only applicable for Google engine. (default: :obj:`"google.com"`)
|
|
1433
|
+
gl (str): Country code for localized results (e.g., 'us', 'uk', 'ca').
|
|
1434
|
+
Only applicable for Google engine. (default: :obj:`"us"`)
|
|
1435
|
+
search_lang (str): Language code for results (e.g., 'en', 'es', 'fr').
|
|
1436
|
+
Only applicable for Google engine. (default: :obj:`"en"`)
|
|
1437
|
+
device (str): Device type: 'desktop', 'tablet', or 'mobile'.
|
|
1438
|
+
(default: :obj:`"desktop"`)
|
|
1439
|
+
number_of_result_pages (int): Number of organic results to return.
|
|
1440
|
+
Adjust based on task needs. (default: :obj:`1`)
|
|
1441
|
+
safe (str): Safe search level: 'off', 'medium', 'high', 'active'.
|
|
1442
|
+
(default: :obj:`"off"`)
|
|
1443
|
+
filter (int): Filter results: 0 (no filter), 1 (filter similar results).
|
|
1444
|
+
(default: :obj:`0`)
|
|
1445
|
+
custom_params (Optional[Dict[str, Any]]): Additional custom parameters
|
|
1446
|
+
to pass to SerpApi. (default: :obj:`None`)
|
|
1447
|
+
|
|
1448
|
+
Returns:
|
|
1449
|
+
Dict[str, Any]: A dictionary containing search results:
|
|
1450
|
+
- 'results': List of organic search results, each containing:
|
|
1451
|
+
- 'title': The title of the search result
|
|
1452
|
+
- 'link': The URL of the search result
|
|
1453
|
+
- 'snippet': The description snippet
|
|
1454
|
+
- 'keywords': Highlighted keywords in the snippet
|
|
1455
|
+
- 'source': The source of the result
|
|
1456
|
+
- 'error: Error if any
|
|
1457
|
+
"""
|
|
1458
|
+
from serpapi import SerpApiClient
|
|
1459
|
+
|
|
1460
|
+
SerpApiClient.SERP_API_KEY = os.getenv("SERPAPI_KEY")
|
|
1461
|
+
params = {
|
|
1462
|
+
"engine": engine,
|
|
1463
|
+
"q": query,
|
|
1464
|
+
"location": location,
|
|
1465
|
+
"google_domain": google_domain,
|
|
1466
|
+
"gl": gl,
|
|
1467
|
+
"hl": search_lang,
|
|
1468
|
+
"device": device,
|
|
1469
|
+
"num": number_of_result_pages,
|
|
1470
|
+
"safe": safe,
|
|
1471
|
+
"filter": filter,
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
if custom_params is not None:
|
|
1475
|
+
params.update(custom_params)
|
|
1476
|
+
try:
|
|
1477
|
+
search = SerpApiClient(params)
|
|
1478
|
+
results = search.get_dict()
|
|
1479
|
+
|
|
1480
|
+
if (
|
|
1481
|
+
"organic_results" not in results
|
|
1482
|
+
or not results["organic_results"]
|
|
1483
|
+
):
|
|
1484
|
+
return {"error": "No organic results found"}
|
|
1485
|
+
|
|
1486
|
+
formatted_results = []
|
|
1487
|
+
for result in results['organic_results']:
|
|
1488
|
+
formatted_result = {
|
|
1489
|
+
"title": result.get("title", ""),
|
|
1490
|
+
"link": result.get("link", ""),
|
|
1491
|
+
"snippet": result.get("snippet", ""),
|
|
1492
|
+
"keywords": result.get("snippet_highlighted_words", []),
|
|
1493
|
+
"source": result.get("source", ""),
|
|
1494
|
+
}
|
|
1495
|
+
formatted_results.append(formatted_result)
|
|
1496
|
+
|
|
1497
|
+
return {"results": formatted_results}
|
|
1498
|
+
|
|
1499
|
+
except Exception as e:
|
|
1500
|
+
return {"error": f"SerpApi search failed: {e!s}"}
|
|
1501
|
+
|
|
1065
1502
|
def get_tools(self) -> List[FunctionTool]:
|
|
1066
1503
|
r"""Returns a list of FunctionTool objects representing the
|
|
1067
1504
|
functions in the toolkit.
|
|
@@ -1071,15 +1508,28 @@ class SearchToolkit(BaseToolkit):
|
|
|
1071
1508
|
representing the functions in the toolkit.
|
|
1072
1509
|
"""
|
|
1073
1510
|
return [
|
|
1511
|
+
FunctionTool(self.search_serper),
|
|
1074
1512
|
FunctionTool(self.search_wiki),
|
|
1075
1513
|
FunctionTool(self.search_linkup),
|
|
1076
1514
|
FunctionTool(self.search_google),
|
|
1077
1515
|
FunctionTool(self.search_duckduckgo),
|
|
1078
|
-
FunctionTool(self.
|
|
1516
|
+
FunctionTool(self.search_tavily),
|
|
1079
1517
|
FunctionTool(self.search_brave),
|
|
1080
1518
|
FunctionTool(self.search_bocha),
|
|
1081
1519
|
FunctionTool(self.search_baidu),
|
|
1082
1520
|
FunctionTool(self.search_bing),
|
|
1083
1521
|
FunctionTool(self.search_exa),
|
|
1084
1522
|
FunctionTool(self.search_alibaba_tongxiao),
|
|
1523
|
+
FunctionTool(self.search_metaso),
|
|
1524
|
+
FunctionTool(self.search_serpapi),
|
|
1085
1525
|
]
|
|
1526
|
+
|
|
1527
|
+
# Deprecated method alias for backward compatibility
|
|
1528
|
+
def tavily_search(self, *args, **kwargs):
|
|
1529
|
+
r"""Deprecated: Use search_tavily instead for consistency with other search methods."""
|
|
1530
|
+
warnings.warn(
|
|
1531
|
+
"tavily_search is deprecated. Use search_tavily instead for consistency.",
|
|
1532
|
+
DeprecationWarning,
|
|
1533
|
+
stacklevel=2,
|
|
1534
|
+
)
|
|
1535
|
+
return self.search_tavily(*args, **kwargs)
|