camel-ai 0.2.59__py3-none-any.whl → 0.2.82__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of camel-ai might be problematic. Click here for more details.
- 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 +5012 -902
- 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 +39 -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 +94 -0
- camel/benchmarks/mock_website/mock_web.py +299 -0
- camel/benchmarks/mock_website/requirements.txt +3 -0
- camel/benchmarks/mock_website/shopping_mall/app.py +465 -0
- camel/benchmarks/mock_website/task.json +104 -0
- 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 +26 -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 +8 -7
- 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 +3 -3
- camel/configs/cometapi_config.py +106 -0
- camel/configs/crynux_config.py +94 -0
- 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 +3 -3
- 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 +8 -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 +3 -3
- camel/configs/samba_config.py +8 -6
- 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_collector → data_collectors}/__init__.py +2 -2
- camel/{data_collector → data_collectors}/alpaca_collector.py +19 -10
- camel/{data_collector → data_collectors}/base.py +2 -2
- camel/{data_collector → data_collectors}/sharegpt_collector.py +3 -3
- camel/datagen/__init__.py +2 -2
- camel/datagen/cot_datagen.py +32 -37
- camel/datagen/evol_instruct/__init__.py +2 -2
- camel/datagen/evol_instruct/evol_instruct.py +2 -2
- camel/datagen/evol_instruct/scorer.py +24 -25
- camel/datagen/evol_instruct/templates.py +48 -48
- 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 +3 -3
- camel/datasets/self_instruct_generator.py +2 -2
- camel/datasets/static_dataset.py +152 -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 +10 -3
- 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 +4 -4
- camel/embeddings/together_embedding.py +2 -2
- camel/embeddings/vlm_embedding.py +11 -4
- 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 +16 -3
- camel/interpreters/docker/Dockerfile +53 -7
- camel/interpreters/docker_interpreter.py +70 -11
- camel/interpreters/e2b_interpreter.py +59 -11
- camel/interpreters/internal_python_interpreter.py +81 -4
- camel/interpreters/interpreter_error.py +2 -2
- camel/interpreters/ipython_interpreter.py +23 -5
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/interpreters/subprocess_interpreter.py +36 -4
- camel/loaders/__init__.py +17 -5
- 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 +128 -93
- 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 +148 -0
- 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 +126 -9
- 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 +98 -13
- camel/messages/__init__.py +2 -2
- camel/messages/base.py +193 -46
- 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 +263 -63
- 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 +81 -21
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +87 -0
- camel/models/deepseek_model.py +61 -59
- camel/models/fish_audio_model.py +8 -2
- camel/models/gemini_model.py +439 -30
- camel/models/groq_model.py +11 -19
- camel/models/internlm_model.py +11 -18
- camel/models/litellm_model.py +94 -34
- camel/models/lmstudio_model.py +17 -20
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +84 -19
- camel/models/model_factory.py +49 -6
- camel/models/model_manager.py +33 -11
- 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 +234 -27
- camel/models/openai_model.py +255 -39
- 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 +90 -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 +117 -49
- camel/models/sglang_model.py +162 -42
- 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 +69 -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 +23 -3
- camel/retrievers/base.py +2 -2
- camel/retrievers/bm25_retriever.py +3 -4
- camel/retrievers/cohere_rerank_retriever.py +2 -2
- camel/retrievers/hybrid_retrival.py +4 -4
- camel/retrievers/vector_retriever.py +2 -2
- camel/runtimes/Dockerfile.multi-toolkit +90 -0
- camel/{runtime → runtimes}/__init__.py +2 -2
- camel/runtimes/api.py +153 -0
- camel/{runtime → runtimes}/base.py +2 -2
- camel/{runtime → runtimes}/configs.py +13 -13
- camel/{runtime → runtimes}/daytona_runtime.py +18 -19
- camel/{runtime → runtimes}/docker_runtime.py +13 -13
- camel/{runtime → runtimes}/llm_guard_runtime.py +28 -28
- camel/{runtime → runtimes}/remote_http_runtime.py +12 -12
- camel/{runtime → runtimes}/ubuntu_docker_runtime.py +3 -3
- camel/{runtime → runtimes}/utils/__init__.py +2 -2
- camel/{runtime → runtimes}/utils/function_risk_toolkit.py +2 -2
- camel/{runtime → 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 +9 -5
- camel/societies/workforce/events.py +143 -0
- camel/societies/workforce/prompts.py +258 -33
- camel/societies/workforce/role_playing_worker.py +95 -30
- camel/societies/workforce/single_agent_worker.py +659 -30
- camel/societies/workforce/structured_output_handler.py +512 -0
- camel/societies/workforce/task_channel.py +182 -38
- camel/societies/workforce/utils.py +784 -18
- camel/societies/workforce/worker.py +96 -28
- camel/societies/workforce/workflow_memory_manager.py +1746 -0
- camel/societies/workforce/workforce.py +5730 -366
- 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 +10 -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 +12 -2
- camel/storages/vectordb_storages/base.py +2 -2
- camel/storages/vectordb_storages/chroma.py +731 -0
- camel/storages/vectordb_storages/faiss.py +712 -0
- camel/storages/vectordb_storages/milvus.py +2 -2
- camel/storages/vectordb_storages/oceanbase.py +16 -17
- 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 +714 -0
- camel/tasks/__init__.py +2 -2
- camel/tasks/task.py +366 -27
- 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 +58 -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 +174 -575
- camel/toolkits/audio_analysis_toolkit.py +3 -3
- camel/toolkits/base.py +65 -7
- camel/toolkits/bohrium_toolkit.py +318 -0
- camel/toolkits/browser_toolkit.py +306 -566
- camel/toolkits/browser_toolkit_commons.py +568 -0
- camel/toolkits/code_execution.py +67 -11
- 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 +910 -70
- camel/toolkits/file_toolkit.py +1402 -0
- camel/toolkits/function_tool.py +128 -20
- camel/toolkits/github_toolkit.py +148 -43
- 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 -3
- camel/toolkits/image_generation_toolkit.py +390 -0
- camel/toolkits/jina_reranker_toolkit.py +195 -79
- 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 +841 -600
- 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 +86 -74
- camel/toolkits/playwright_mcp_toolkit.py +27 -32
- camel/toolkits/pptx_toolkit.py +790 -0
- 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 +134 -0
- 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 +8 -3
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +112 -29
- camel/toolkits/video_download_toolkit.py +22 -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 +53 -25
- 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 +454 -35
- camel/types/mcp_registries.py +2 -2
- camel/types/openai_types.py +4 -4
- camel/types/unified_model_type.py +43 -6
- camel/utils/__init__.py +20 -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 +65 -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 +258 -0
- camel/utils/mcp.py +140 -6
- camel/utils/mcp_client.py +1056 -0
- 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.59.dist-info → camel_ai-0.2.82.dist-info}/METADATA +349 -108
- camel_ai-0.2.82.dist-info/RECORD +507 -0
- {camel_ai-0.2.59.dist-info → camel_ai-0.2.82.dist-info}/WHEEL +1 -1
- {camel_ai-0.2.59.dist-info → camel_ai-0.2.82.dist-info}/licenses/LICENSE +1 -1
- camel/loaders/pandas_reader.py +0 -368
- camel/runtime/api.py +0 -97
- camel/toolkits/dalle_toolkit.py +0 -171
- camel/toolkits/file_write_toolkit.py +0 -395
- camel/toolkits/openai_agent_toolkit.py +0 -135
- camel/toolkits/terminal_toolkit.py +0 -1037
- camel_ai-0.2.59.dist-info/RECORD +0 -410
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parent-child filtering logic for SOM-labels
|
|
3
|
+
* Filters out child elements that are contained within propagating parent elements
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ElementInfo {
|
|
7
|
+
ref: string;
|
|
8
|
+
coordinates?: {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
14
|
+
role?: string;
|
|
15
|
+
type?: string;
|
|
16
|
+
tagName?: string;
|
|
17
|
+
attributes?: Record<string, any>;
|
|
18
|
+
text?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Elements that propagate bounds to their children
|
|
22
|
+
const PROPAGATING_ELEMENTS = [
|
|
23
|
+
{ tag: 'a', role: null },
|
|
24
|
+
{ tag: 'button', role: null },
|
|
25
|
+
{ tag: 'div', role: 'button' },
|
|
26
|
+
{ tag: 'div', role: 'combobox' },
|
|
27
|
+
{ tag: 'span', role: 'button' },
|
|
28
|
+
{ tag: 'span', role: 'combobox' },
|
|
29
|
+
{ tag: 'input', role: 'combobox' },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const CONTAINMENT_THRESHOLD = 0.99; // 99% containment required
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if element is a propagating element
|
|
36
|
+
*/
|
|
37
|
+
function isPropagatingElement(element: ElementInfo): boolean {
|
|
38
|
+
const tagName = element.tagName || element.type || '';
|
|
39
|
+
const tag = tagName.toLowerCase();
|
|
40
|
+
const role = element.role || element.attributes?.role || null;
|
|
41
|
+
|
|
42
|
+
// For generic elements with cursor=pointer, we need to be more selective
|
|
43
|
+
// Only treat them as propagating if they don't have text content
|
|
44
|
+
// (text-containing generics are usually labels, not containers)
|
|
45
|
+
if ((tag === 'generic' || element.type === 'generic') &&
|
|
46
|
+
element.attributes?.['cursor'] === 'pointer') {
|
|
47
|
+
// If element has direct text content, it's likely a label, not a container
|
|
48
|
+
if (element.text && element.text.trim()) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
// If no text, it might be a container
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const pattern of PROPAGATING_ELEMENTS) {
|
|
56
|
+
if (pattern.tag === tag) {
|
|
57
|
+
if (pattern.role === null || pattern.role === role) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Check if child bounds are contained within parent bounds
|
|
67
|
+
*/
|
|
68
|
+
function isContained(
|
|
69
|
+
childBounds: { x: number; y: number; width: number; height: number },
|
|
70
|
+
parentBounds: { x: number; y: number; width: number; height: number },
|
|
71
|
+
threshold: number
|
|
72
|
+
): boolean {
|
|
73
|
+
// Calculate intersection
|
|
74
|
+
const xOverlap = Math.max(0,
|
|
75
|
+
Math.min(childBounds.x + childBounds.width, parentBounds.x + parentBounds.width) -
|
|
76
|
+
Math.max(childBounds.x, parentBounds.x)
|
|
77
|
+
);
|
|
78
|
+
const yOverlap = Math.max(0,
|
|
79
|
+
Math.min(childBounds.y + childBounds.height, parentBounds.y + parentBounds.height) -
|
|
80
|
+
Math.max(childBounds.y, parentBounds.y)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const intersectionArea = xOverlap * yOverlap;
|
|
84
|
+
const childArea = childBounds.width * childBounds.height;
|
|
85
|
+
|
|
86
|
+
if (childArea === 0) return false;
|
|
87
|
+
|
|
88
|
+
return (intersectionArea / childArea) >= threshold;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check if child element should be filtered out
|
|
93
|
+
*/
|
|
94
|
+
function shouldFilterChild(childEl: ElementInfo, parentEl: ElementInfo): boolean {
|
|
95
|
+
// Never filter if parent is not a propagating element
|
|
96
|
+
if (!isPropagatingElement(parentEl)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Never filter if elements don't have coordinates
|
|
101
|
+
if (!childEl.coordinates || !parentEl.coordinates) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Check containment
|
|
106
|
+
if (!isContained(childEl.coordinates, parentEl.coordinates, CONTAINMENT_THRESHOLD)) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const childTag = (childEl.tagName || childEl.type || '').toLowerCase();
|
|
111
|
+
const childRole = childEl.role || childEl.attributes?.role || null;
|
|
112
|
+
|
|
113
|
+
// Exception rules - never filter these:
|
|
114
|
+
|
|
115
|
+
// 1. Form elements (need individual interaction)
|
|
116
|
+
if (['input', 'select', 'textarea', 'label'].includes(childTag)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 2. Child is also a propagating element (might have stopPropagation)
|
|
121
|
+
if (isPropagatingElement(childEl)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 3. Has onclick handler
|
|
126
|
+
if (childEl.attributes?.onclick) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 4. Has meaningful aria-label
|
|
131
|
+
if (childEl.attributes?.['aria-label']?.trim()) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 5. Has interactive role
|
|
136
|
+
if (['button', 'link', 'checkbox', 'radio', 'tab', 'menuitem'].includes(childRole || '')) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Default: filter this child
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Filter clickable elements based on parent-child relationships
|
|
146
|
+
* @param elements - Map of all elements with their info
|
|
147
|
+
* @param clickableRefs - Set of refs that are clickable
|
|
148
|
+
* @returns Filtered set of element refs and debug info
|
|
149
|
+
*/
|
|
150
|
+
export function filterParentChildElements(
|
|
151
|
+
elements: Record<string, ElementInfo>,
|
|
152
|
+
clickableRefs: Set<string>
|
|
153
|
+
): {
|
|
154
|
+
filteredElements: Set<string>;
|
|
155
|
+
debugInfo: any[];
|
|
156
|
+
} {
|
|
157
|
+
const elementRefs = Array.from(clickableRefs);
|
|
158
|
+
const filteredElements = new Set<string>(elementRefs);
|
|
159
|
+
const debugInfo: any[] = [];
|
|
160
|
+
|
|
161
|
+
console.log(`[Parent-Child Filter] Analyzing ${elementRefs.length} clickable elements`);
|
|
162
|
+
|
|
163
|
+
// Check each pair of elements for parent-child filtering
|
|
164
|
+
for (let i = 0; i < elementRefs.length; i++) {
|
|
165
|
+
const parentRef = elementRefs[i];
|
|
166
|
+
const parentEl = elements[parentRef];
|
|
167
|
+
|
|
168
|
+
if (!parentEl?.coordinates) continue;
|
|
169
|
+
|
|
170
|
+
const isParentPropagating = isPropagatingElement(parentEl);
|
|
171
|
+
|
|
172
|
+
for (let j = 0; j < elementRefs.length; j++) {
|
|
173
|
+
if (i === j) continue;
|
|
174
|
+
|
|
175
|
+
const childRef = elementRefs[j];
|
|
176
|
+
const childEl = elements[childRef];
|
|
177
|
+
|
|
178
|
+
if (!childEl?.coordinates) continue;
|
|
179
|
+
|
|
180
|
+
// Debug parent-child relationships when enabled
|
|
181
|
+
const DEBUG_PARENT_CHILD = process.env.DEBUG_PARENT_CHILD === 'true';
|
|
182
|
+
if (DEBUG_PARENT_CHILD) {
|
|
183
|
+
const shouldFilter = shouldFilterChild(childEl, parentEl);
|
|
184
|
+
console.log(`\n[Debug] Checking ${parentRef} -> ${childRef}:`);
|
|
185
|
+
console.log(`Parent:`, {
|
|
186
|
+
ref: parentRef,
|
|
187
|
+
type: parentEl.type || parentEl.tagName,
|
|
188
|
+
role: parentEl.role,
|
|
189
|
+
coords: parentEl.coordinates,
|
|
190
|
+
isPropagating: isParentPropagating
|
|
191
|
+
});
|
|
192
|
+
console.log(`Child:`, {
|
|
193
|
+
ref: childRef,
|
|
194
|
+
type: childEl.type || childEl.tagName,
|
|
195
|
+
role: childEl.role,
|
|
196
|
+
coords: childEl.coordinates
|
|
197
|
+
});
|
|
198
|
+
console.log(`Should filter? ${shouldFilter}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (shouldFilterChild(childEl, parentEl)) {
|
|
202
|
+
filteredElements.delete(childRef);
|
|
203
|
+
|
|
204
|
+
debugInfo.push({
|
|
205
|
+
type: 'filtered',
|
|
206
|
+
childRef,
|
|
207
|
+
parentRef,
|
|
208
|
+
reason: 'Contained within propagating parent',
|
|
209
|
+
parentType: parentEl.type || parentEl.tagName,
|
|
210
|
+
childType: childEl.type || childEl.tagName,
|
|
211
|
+
parentRole: parentEl.role,
|
|
212
|
+
childRole: childEl.role,
|
|
213
|
+
containment: isContained(childEl.coordinates, parentEl.coordinates, CONTAINMENT_THRESHOLD)
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const filteredCount = elementRefs.length - filteredElements.size;
|
|
220
|
+
console.log(`[Parent-Child Filter] Filtered out ${filteredCount} child elements`);
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
filteredElements,
|
|
224
|
+
debugInfo
|
|
225
|
+
};
|
|
226
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse snapshot text to extract parent-child relationships
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface SnapshotNode {
|
|
6
|
+
ref: string;
|
|
7
|
+
type: string;
|
|
8
|
+
text?: string;
|
|
9
|
+
attributes: Record<string, string>;
|
|
10
|
+
children: string[]; // refs of child elements
|
|
11
|
+
parent?: string; // ref of parent element
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function parseSnapshotHierarchy(snapshotText: string): Map<string, SnapshotNode> {
|
|
15
|
+
const nodes = new Map<string, SnapshotNode>();
|
|
16
|
+
const lines = snapshotText.split('\n');
|
|
17
|
+
|
|
18
|
+
// Stack to track parent elements at each indentation level
|
|
19
|
+
const parentStack: { ref: string; indent: number }[] = [];
|
|
20
|
+
|
|
21
|
+
for (const line of lines) {
|
|
22
|
+
if (!line.trim()) continue;
|
|
23
|
+
|
|
24
|
+
const indent = line.length - line.trimStart().length;
|
|
25
|
+
|
|
26
|
+
// Extract type and optional label
|
|
27
|
+
const headerMatch = line.match(/^\s*(?:-\s*)?'?([a-z0-9_-]+)(?:\s+"((?:[^"\\]|\\.)*)")?/i);
|
|
28
|
+
if (!headerMatch) continue;
|
|
29
|
+
const [, typeRaw, label] = headerMatch;
|
|
30
|
+
const type = (typeRaw || 'unknown');
|
|
31
|
+
|
|
32
|
+
const refMatch = line.match(/\[ref=([^\]]+)\]/i);
|
|
33
|
+
if (!refMatch) continue;
|
|
34
|
+
const ref = refMatch[1];
|
|
35
|
+
|
|
36
|
+
// Parse bracketed attributes
|
|
37
|
+
const attrs: Record<string, string> = {};
|
|
38
|
+
for (const block of line.matchAll(/\[([^\]]+)\]/g)) {
|
|
39
|
+
const content = block[1];
|
|
40
|
+
if (/^ref=/i.test(content)) continue;
|
|
41
|
+
const attrMatches = content.matchAll(/([a-z0-9_-]+)(?:=(?:"([^"]*)"|'([^']*)'|([^\s\]]+)))?/gi);
|
|
42
|
+
for (const m of attrMatches) {
|
|
43
|
+
const key = m[1].toLowerCase();
|
|
44
|
+
const val = m[2] ?? m[3] ?? m[4] ?? 'true';
|
|
45
|
+
attrs[key] = val;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
while (parentStack.length > 0 && parentStack[parentStack.length - 1].indent >= indent) {
|
|
50
|
+
parentStack.pop();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const node: SnapshotNode = {
|
|
54
|
+
ref,
|
|
55
|
+
type: type.toLowerCase(),
|
|
56
|
+
text: label || '',
|
|
57
|
+
attributes: attrs,
|
|
58
|
+
children: [],
|
|
59
|
+
parent: parentStack.length > 0 ? parentStack[parentStack.length - 1].ref : undefined
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (node.parent && nodes.has(node.parent)) {
|
|
63
|
+
nodes.get(node.parent)!.children.push(ref);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
nodes.set(ref, node);
|
|
67
|
+
|
|
68
|
+
parentStack.push({ ref, indent });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return nodes;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Find clickable elements that should be filtered based on DOM hierarchy
|
|
76
|
+
*/
|
|
77
|
+
export function filterClickableByHierarchy(
|
|
78
|
+
snapshotText: string,
|
|
79
|
+
clickableElements: Set<string>
|
|
80
|
+
): Set<string> {
|
|
81
|
+
const hierarchy = parseSnapshotHierarchy(snapshotText);
|
|
82
|
+
const filtered = new Set<string>(clickableElements);
|
|
83
|
+
const debugInfo: any[] = [];
|
|
84
|
+
|
|
85
|
+
// Debug clickable elements when enabled
|
|
86
|
+
const DEBUG_SNAPSHOT_PARSER = process.env.DEBUG_SNAPSHOT_PARSER === 'true';
|
|
87
|
+
if (DEBUG_SNAPSHOT_PARSER) {
|
|
88
|
+
clickableElements.forEach(ref => {
|
|
89
|
+
const node = hierarchy.get(ref);
|
|
90
|
+
if (node) {
|
|
91
|
+
console.log(`[Debug] ${ref} type: ${node.type}, parent: ${node.parent || 'none'}`);
|
|
92
|
+
} else {
|
|
93
|
+
console.log(`[Debug] ${ref} NOT FOUND in hierarchy!`);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// First pass: identify parent-child relationships where both are clickable
|
|
99
|
+
const parentChildPairs: Array<{parent: string, child: string, parentType: string, childType: string}> = [];
|
|
100
|
+
|
|
101
|
+
for (const childRef of clickableElements) {
|
|
102
|
+
const childNode = hierarchy.get(childRef);
|
|
103
|
+
if (!childNode || !childNode.parent) continue;
|
|
104
|
+
|
|
105
|
+
const parentRef = childNode.parent;
|
|
106
|
+
if (clickableElements.has(parentRef)) {
|
|
107
|
+
const parentNode = hierarchy.get(parentRef);
|
|
108
|
+
if (parentNode) {
|
|
109
|
+
parentChildPairs.push({
|
|
110
|
+
parent: parentRef,
|
|
111
|
+
child: childRef,
|
|
112
|
+
parentType: parentNode.type.toLowerCase(),
|
|
113
|
+
childType: childNode.type.toLowerCase()
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Debug specific pairs
|
|
117
|
+
if ((parentRef === 'e296' && childRef === 'e297') ||
|
|
118
|
+
(parentRef === 'e361' && childRef === 'e363') ||
|
|
119
|
+
(parentRef === 'e371' && childRef === 'e373') ||
|
|
120
|
+
(parentRef === 'e344' && childRef === 'e346') ||
|
|
121
|
+
(parentRef === 'e348' && childRef === 'e350')) {
|
|
122
|
+
console.log(`[Debug] Found pair: ${parentRef} (${parentNode.type}) -> ${childRef} (${childNode.type})`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Decide which elements to filter based on parent-child relationships
|
|
129
|
+
for (const pair of parentChildPairs) {
|
|
130
|
+
const { parent, child, parentType, childType } = pair;
|
|
131
|
+
|
|
132
|
+
// Rules for what to filter:
|
|
133
|
+
// 1. link > img: filter img (keep link)
|
|
134
|
+
// 2. button > generic: filter generic (keep button)
|
|
135
|
+
// 3. generic > button: filter generic (keep button)
|
|
136
|
+
// 4. link > generic: filter generic (keep link)
|
|
137
|
+
// 5. generic > generic: filter child (keep parent)
|
|
138
|
+
// 6. generic > unknown: filter child (keep parent)
|
|
139
|
+
|
|
140
|
+
if ((parentType === 'link' && childType === 'img') ||
|
|
141
|
+
(parentType === 'button' && childType === 'generic') ||
|
|
142
|
+
(parentType === 'link' && childType === 'generic') ||
|
|
143
|
+
(parentType === 'generic' && childType === 'generic') ||
|
|
144
|
+
(parentType === 'generic' && childType === 'unknown')) {
|
|
145
|
+
// Filter child
|
|
146
|
+
filtered.delete(child);
|
|
147
|
+
console.log(`[Hierarchy Filter] Filtered ${child} (${childType}) - keeping parent ${parent} (${parentType})`);
|
|
148
|
+
} else if (parentType === 'generic' && childType === 'button') {
|
|
149
|
+
// Special case: filter parent generic, keep child button
|
|
150
|
+
filtered.delete(parent);
|
|
151
|
+
console.log(`[Hierarchy Filter] Filtered ${parent} (${parentType}) - keeping child ${child} (${childType})`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Original logic for nested hierarchies (keep for deep nesting)
|
|
156
|
+
for (const childRef of clickableElements) {
|
|
157
|
+
if (!filtered.has(childRef)) continue; // Already filtered
|
|
158
|
+
|
|
159
|
+
const childNode = hierarchy.get(childRef);
|
|
160
|
+
if (!childNode || !childNode.parent) continue;
|
|
161
|
+
|
|
162
|
+
// Check if any ancestor is a propagating element
|
|
163
|
+
let currentParent: string | undefined = childNode.parent;
|
|
164
|
+
while (currentParent) {
|
|
165
|
+
if (clickableElements.has(currentParent) && filtered.has(currentParent)) {
|
|
166
|
+
const parentNode = hierarchy.get(currentParent);
|
|
167
|
+
if (parentNode) {
|
|
168
|
+
// Check if parent is a propagating element
|
|
169
|
+
const parentType = parentNode.type.toLowerCase();
|
|
170
|
+
const isPropagating = ['button', 'link', 'a'].includes(parentType) ||
|
|
171
|
+
(parentType === 'generic' && parentNode.attributes.cursor === 'pointer' && !parentNode.text);
|
|
172
|
+
|
|
173
|
+
if (isPropagating) {
|
|
174
|
+
// Filter child elements that should be contained within propagating parents
|
|
175
|
+
const childType = childNode.type.toLowerCase();
|
|
176
|
+
|
|
177
|
+
// Filter these types of children:
|
|
178
|
+
// 1. Generic elements with cursor=pointer
|
|
179
|
+
// 2. Images within links/buttons
|
|
180
|
+
// 3. Text elements (span, generic without specific role)
|
|
181
|
+
const shouldFilter =
|
|
182
|
+
(childType === 'generic' && childNode.attributes.cursor === 'pointer') ||
|
|
183
|
+
childType === 'img' ||
|
|
184
|
+
childType === 'span' ||
|
|
185
|
+
(childType === 'generic' && !childNode.attributes.role);
|
|
186
|
+
|
|
187
|
+
if (shouldFilter) {
|
|
188
|
+
filtered.delete(childRef);
|
|
189
|
+
console.log(`[Hierarchy Filter] Filtered ${childRef} (${childType}) contained in ${currentParent} (${parentType})`);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Move up the hierarchy
|
|
196
|
+
const nextParent = hierarchy.get(currentParent);
|
|
197
|
+
currentParent = nextParent?.parent;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Additional pass: if a generic parent contains only one button child, filter the parent
|
|
202
|
+
for (const ref of Array.from(filtered)) {
|
|
203
|
+
const node = hierarchy.get(ref);
|
|
204
|
+
if (!node || node.type.toLowerCase() !== 'generic') continue;
|
|
205
|
+
|
|
206
|
+
// Check if this generic has exactly one clickable child that's a button
|
|
207
|
+
const clickableChildren = node.children.filter(childRef =>
|
|
208
|
+
filtered.has(childRef) && hierarchy.get(childRef)?.type.toLowerCase() === 'button'
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
if (clickableChildren.length === 1) {
|
|
212
|
+
// This generic wraps a single button - filter it out
|
|
213
|
+
filtered.delete(ref);
|
|
214
|
+
console.log(`[Hierarchy Filter] Filtered ${ref} (generic wrapper around button ${clickableChildren[0]})`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return filtered;
|
|
219
|
+
}
|