polyrob 0.5.0__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.
- agents/README.md +453 -0
- agents/__init__.py +164 -0
- agents/base_agent.py +743 -0
- agents/personality/character.py +119 -0
- agents/personality/character_manager.py +309 -0
- agents/personality/characters/rob.character.json +56 -0
- agents/personality/characters/trump.character.json +63 -0
- agents/personality/persona_render.py +78 -0
- agents/personality/persona_resolver.py +115 -0
- agents/prompt/__init__.py +58 -0
- agents/prompt/base_prompt.py +92 -0
- agents/prompt/system.py +417 -0
- agents/task/README_PATH_MANAGEMENT.md +141 -0
- agents/task/__init__.py +162 -0
- agents/task/agent/__init__.py +70 -0
- agents/task/agent/agent_state.py +408 -0
- agents/task/agent/async_delegation.py +274 -0
- agents/task/agent/autonomy_state.py +275 -0
- agents/task/agent/conversation.py +75 -0
- agents/task/agent/core/__init__.py +6 -0
- agents/task/agent/core/aux_metering.py +61 -0
- agents/task/agent/core/background_review.py +157 -0
- agents/task/agent/core/construction.py +1179 -0
- agents/task/agent/core/conversational_exit.py +49 -0
- agents/task/agent/core/correspondent_gate.py +227 -0
- agents/task/agent/core/curator.py +246 -0
- agents/task/agent/core/episodic_digest.py +103 -0
- agents/task/agent/core/error_recovery.py +480 -0
- agents/task/agent/core/history_io.py +257 -0
- agents/task/agent/core/llm_provisioning.py +287 -0
- agents/task/agent/core/llm_runner.py +547 -0
- agents/task/agent/core/logging_io.py +276 -0
- agents/task/agent/core/loop_detection.py +262 -0
- agents/task/agent/core/memory_prefetch.py +325 -0
- agents/task/agent/core/memory_writer.py +667 -0
- agents/task/agent/core/model_introspection.py +82 -0
- agents/task/agent/core/model_swap.py +177 -0
- agents/task/agent/core/next_action_internal.py +1331 -0
- agents/task/agent/core/output_validation.py +303 -0
- agents/task/agent/core/project_context.py +272 -0
- agents/task/agent/core/resources.py +93 -0
- agents/task/agent/core/result_processing.py +389 -0
- agents/task/agent/core/run_loop.py +661 -0
- agents/task/agent/core/safety_lifecycle.py +228 -0
- agents/task/agent/core/secret_guard.py +293 -0
- agents/task/agent/core/self_wake.py +280 -0
- agents/task/agent/core/session_metadata.py +104 -0
- agents/task/agent/core/step.py +781 -0
- agents/task/agent/core/step_execution.py +398 -0
- agents/task/agent/core/step_telemetry.py +222 -0
- agents/task/agent/core/test_aux_metering.py +50 -0
- agents/task/agent/core/test_billing_failover.py +68 -0
- agents/task/agent/core/test_fatal_error_classifier.py +38 -0
- agents/task/agent/core/test_judge_validation.py +275 -0
- agents/task/agent/core/test_model_swap.py +190 -0
- agents/task/agent/core/test_reflection_offload.py +54 -0
- agents/task/agent/core/turn_input.py +8 -0
- agents/task/agent/core/untrusted_wrap.py +103 -0
- agents/task/agent/core/user_ingress.py +228 -0
- agents/task/agent/hitl_manager.py +396 -0
- agents/task/agent/log_sanitize.py +36 -0
- agents/task/agent/message_manager/config.py +97 -0
- agents/task/agent/message_manager/service.py +758 -0
- agents/task/agent/message_manager/tests.py +305 -0
- agents/task/agent/message_manager/tool_call_builder.py +539 -0
- agents/task/agent/message_manager/tool_message_repair.py +364 -0
- agents/task/agent/message_manager/views.py +143 -0
- agents/task/agent/messages/__init__.py +8 -0
- agents/task/agent/messages/builders.py +309 -0
- agents/task/agent/messages/compactor.py +611 -0
- agents/task/agent/messages/context_references.py +271 -0
- agents/task/agent/messages/filters.py +333 -0
- agents/task/agent/messages/guidance.py +328 -0
- agents/task/agent/messages/persistence.py +448 -0
- agents/task/agent/messages/retrieval.py +506 -0
- agents/task/agent/messages/sqlite_persistence.py +85 -0
- agents/task/agent/messages/test_compaction_upgrade.py +349 -0
- agents/task/agent/messages/test_persistence_subdir_fix.py +28 -0
- agents/task/agent/messages/test_sqlite_persistence.py +54 -0
- agents/task/agent/messages/token_counter.py +532 -0
- agents/task/agent/orchestrator.py +776 -0
- agents/task/agent/profile_manager.py +105 -0
- agents/task/agent/profile_registry.py +173 -0
- agents/task/agent/prompts.py +1090 -0
- agents/task/agent/scenario_registry.py +226 -0
- agents/task/agent/service.py +509 -0
- agents/task/agent/session.py +984 -0
- agents/task/agent/skill_discovery.py +110 -0
- agents/task/agent/skill_frontmatter.py +94 -0
- agents/task/agent/skill_manager.py +1201 -0
- agents/task/agent/skill_store.py +627 -0
- agents/task/agent/skill_validation.py +56 -0
- agents/task/agent/skill_writer.py +492 -0
- agents/task/agent/sub_agent_manager.py +1137 -0
- agents/task/agent/test_session_disk_recovery.py +34 -0
- agents/task/agent/tests.py +513 -0
- agents/task/agent/tool_call_tracker.py +511 -0
- agents/task/agent/views.py +469 -0
- agents/task/config.py +432 -0
- agents/task/constants.py +1384 -0
- agents/task/flag_defaults.py +63 -0
- agents/task/goals/__init__.py +1 -0
- agents/task/goals/autonomy_marker.py +28 -0
- agents/task/goals/board.py +690 -0
- agents/task/goals/completion_judge.py +247 -0
- agents/task/goals/context.py +62 -0
- agents/task/goals/dispatcher.py +848 -0
- agents/task/goals/escalation.py +102 -0
- agents/task/goals/planner.py +114 -0
- agents/task/logging_config.py +155 -0
- agents/task/path.py +991 -0
- agents/task/robust_parse_config.py +400 -0
- agents/task/runtime/__init__.py +0 -0
- agents/task/runtime/run_as_session.py +130 -0
- agents/task/runtime_safety.py +308 -0
- agents/task/session/__init__.py +5 -0
- agents/task/session/browser_pool.py +130 -0
- agents/task/session/cleanup.py +612 -0
- agents/task/session/execution.py +397 -0
- agents/task/session/feed.py +200 -0
- agents/task/session/hitl_ingress.py +201 -0
- agents/task/session/hooks.py +83 -0
- agents/task/session/multi_agent.py +243 -0
- agents/task/session/workspace.py +91 -0
- agents/task/session_registry.py +91 -0
- agents/task/session_route.py +35 -0
- agents/task/sqlite_session_registry.py +261 -0
- agents/task/surface_config.py +185 -0
- agents/task/telemetry/__init__.py +58 -0
- agents/task/telemetry/event_log.py +180 -0
- agents/task/telemetry/formatters.py +642 -0
- agents/task/telemetry/manager.py +571 -0
- agents/task/telemetry/memory_events.py +66 -0
- agents/task/telemetry/self_events.py +53 -0
- agents/task/telemetry/sequence.py +160 -0
- agents/task/telemetry/service.py +1265 -0
- agents/task/telemetry/views.py +882 -0
- agents/task/templates.py +98 -0
- agents/task/test_aux_chain.py +151 -0
- agents/task/test_aux_router.py +41 -0
- agents/task/tests/test_parse_robustness.py +170 -0
- agents/task/tool_defaults.py +110 -0
- agents/task/utils.py +762 -0
- agents/task/utils_json.py +768 -0
- agents/task/utils_webview.py +86 -0
- agents/task/workspace_context.py +229 -0
- agents/task_agent_lite.py +2398 -0
- api/README.md +683 -0
- api/TASK_API_DOCS.md +151 -0
- api/__init__.py +0 -0
- api/a2a/__init__.py +37 -0
- api/a2a/agent_card.py +337 -0
- api/a2a/client.py +657 -0
- api/a2a/endpoints.py +375 -0
- api/a2a/models.py +268 -0
- api/a2a/streaming.py +419 -0
- api/a2a/task_handler.py +929 -0
- api/admin_endpoints.py +1584 -0
- api/app.py +923 -0
- api/auth_constants.py +28 -0
- api/auth_endpoints.py +402 -0
- api/auth_state.py +36 -0
- api/chat_via_task.py +42 -0
- api/conversation_manager.py +231 -0
- api/dependencies.py +186 -0
- api/eip8004_endpoints.py +452 -0
- api/hyperliquid_models.py +174 -0
- api/hyperliquid_routes.py +450 -0
- api/interfaces.py +207 -0
- api/jwt_middleware.py +83 -0
- api/kb/__init__.py +1 -0
- api/kb/endpoints.py +314 -0
- api/mcp_models.py +279 -0
- api/mcp_routes.py +438 -0
- api/middleware.py +526 -0
- api/models.py +176 -0
- api/openai_compat/__init__.py +0 -0
- api/openai_compat/model_map.py +25 -0
- api/openai_compat/models.py +59 -0
- api/openai_compat/router.py +140 -0
- api/payment_endpoints.py +444 -0
- api/payment_verification.py +138 -0
- api/polymarket_models.py +155 -0
- api/polymarket_routes.py +501 -0
- api/pricing_endpoints.py +89 -0
- api/session_routing.py +54 -0
- api/skill_endpoints.py +453 -0
- api/task_http_api.py +1856 -0
- api/webhooks.py +52 -0
- api/x402_endpoints.py +280 -0
- avatar/README.md +44 -0
- avatar/__init__.py +1 -0
- avatar/config/rob.json +7 -0
- avatar/mindprint.js +395 -0
- avatar/renders/rob.meta.json +20 -0
- avatar/renders/rob.png +0 -0
- avatar/studio.html +373 -0
- avatar/webview/avatar-live.js +44 -0
- cli/README.md +89 -0
- cli/__init__.py +0 -0
- cli/cli_surface.py +67 -0
- cli/commands/__init__.py +0 -0
- cli/commands/_bootstrap.py +49 -0
- cli/commands/_errors.py +53 -0
- cli/commands/chat.py +973 -0
- cli/commands/config.py +100 -0
- cli/commands/dashboard.py +103 -0
- cli/commands/doctor.py +222 -0
- cli/commands/email.py +174 -0
- cli/commands/gateway.py +346 -0
- cli/commands/goals.py +509 -0
- cli/commands/init.py +276 -0
- cli/commands/journey.py +30 -0
- cli/commands/kb.py +280 -0
- cli/commands/model.py +107 -0
- cli/commands/owner.py +431 -0
- cli/commands/pfp.py +232 -0
- cli/commands/run.py +414 -0
- cli/commands/serve.py +41 -0
- cli/commands/session.py +684 -0
- cli/commands/skill_install.py +786 -0
- cli/commands/skills.py +128 -0
- cli/commands/subagents.py +100 -0
- cli/commands/surface.py +81 -0
- cli/commands/telegram.py +185 -0
- cli/commands/todos.py +209 -0
- cli/commands/tools.py +102 -0
- cli/commands/update.py +316 -0
- cli/commands/whatsapp.py +175 -0
- cli/config_store.py +276 -0
- cli/gitignore.py +43 -0
- cli/inventory.py +46 -0
- cli/keys.py +101 -0
- cli/persona.py +17 -0
- cli/polyrob.py +137 -0
- cli/ui/__init__.py +64 -0
- cli/ui/activity.py +141 -0
- cli/ui/app.py +538 -0
- cli/ui/banner.py +233 -0
- cli/ui/blocks.py +534 -0
- cli/ui/bootstrap_notice.py +47 -0
- cli/ui/commands/__init__.py +41 -0
- cli/ui/commands/h_cron.py +64 -0
- cli/ui/commands/h_journey.py +164 -0
- cli/ui/commands/h_kb.py +121 -0
- cli/ui/commands/h_learn.py +100 -0
- cli/ui/commands/h_mcp.py +215 -0
- cli/ui/commands/h_self.py +113 -0
- cli/ui/commands/h_skills.py +314 -0
- cli/ui/commands/handlers.py +1672 -0
- cli/ui/commands/registry.py +426 -0
- cli/ui/dialog.py +425 -0
- cli/ui/event_registry.py +110 -0
- cli/ui/event_specs.py +45 -0
- cli/ui/events.py +433 -0
- cli/ui/identity.py +15 -0
- cli/ui/lifecycle.py +159 -0
- cli/ui/live_hooks.py +43 -0
- cli/ui/model_selector.py +532 -0
- cli/ui/persistent_loop.py +181 -0
- cli/ui/pick.py +113 -0
- cli/ui/plain_renderer.py +351 -0
- cli/ui/renderer.py +384 -0
- cli/ui/rich_renderer.py +533 -0
- cli/ui/secrets.py +115 -0
- cli/ui/state.py +376 -0
- cli/ui/statusbar.py +231 -0
- cli/ui/streaming.py +254 -0
- cli/ui/terminal_render.py +105 -0
- cli/ui/theme.py +132 -0
- cli/update/__init__.py +6 -0
- cli/update/context.py +121 -0
- cli/update/detect.py +176 -0
- cli/update/engine.py +95 -0
- cli/update/migrate_guarded.py +55 -0
- cli/update/process_guard.py +215 -0
- cli/update/runners.py +78 -0
- cli/update/snapshot.py +270 -0
- cli/update/versions.py +205 -0
- core/README.md +377 -0
- core/__init__.py +174 -0
- core/assets.py +87 -0
- core/async_bridge.py +76 -0
- core/autonomy_runtime.py +259 -0
- core/base_component.py +302 -0
- core/bootstrap.py +681 -0
- core/bot.py +310 -0
- core/config.py +833 -0
- core/constants.py +126 -0
- core/container.py +462 -0
- core/db_manifest.py +101 -0
- core/embedding.py +57 -0
- core/env.py +39 -0
- core/exceptions.py +287 -0
- core/flags.py +144 -0
- core/flags_catalog.py +345 -0
- core/home_migration.py +62 -0
- core/identity.py +118 -0
- core/initialization.py +1004 -0
- core/instance.py +537 -0
- core/interactive_gate.py +96 -0
- core/logging.py +436 -0
- core/owner_doc_writer.py +176 -0
- core/pairing.py +193 -0
- core/path_safety.py +20 -0
- core/paths.py +27 -0
- core/payment_config.py +21 -0
- core/permissions.py +322 -0
- core/runtime_config.py +96 -0
- core/runtime_paths.py +135 -0
- core/seams.py +35 -0
- core/secret_scan.py +25 -0
- core/secret_scrub.py +71 -0
- core/secrets.py +35 -0
- core/security_logging_filter.py +148 -0
- core/self_context_writer.py +333 -0
- core/self_evolution.py +294 -0
- core/session_context.py +47 -0
- core/sqlite_util.py +59 -0
- core/surfaces/__init__.py +16 -0
- core/surfaces/access.py +118 -0
- core/surfaces/binding.py +88 -0
- core/surfaces/bootstrap.py +78 -0
- core/surfaces/circuit.py +168 -0
- core/surfaces/continuity.py +77 -0
- core/surfaces/correspondents.py +228 -0
- core/surfaces/dispatcher.py +216 -0
- core/surfaces/envelopes.py +75 -0
- core/surfaces/gc.py +30 -0
- core/surfaces/idempotency.py +57 -0
- core/surfaces/inbound_webhook.py +124 -0
- core/surfaces/media.py +32 -0
- core/surfaces/message_router.py +91 -0
- core/surfaces/outbound_allowlist.py +80 -0
- core/surfaces/outbound_dispatcher.py +110 -0
- core/surfaces/outbound_mirror.py +37 -0
- core/surfaces/outbound_queue.py +107 -0
- core/surfaces/outbound_target.py +12 -0
- core/surfaces/owner_admin.py +29 -0
- core/surfaces/proactive.py +78 -0
- core/surfaces/progress.py +108 -0
- core/surfaces/rate_bucket.py +21 -0
- core/surfaces/registry.py +51 -0
- core/surfaces/rendering.py +53 -0
- core/surfaces/send_policy.py +14 -0
- core/surfaces/serialize.py +24 -0
- core/surfaces/session_chat_registry.py +112 -0
- core/surfaces/session_policy.py +60 -0
- core/surfaces/surface.py +288 -0
- core/surfaces/transcription.py +88 -0
- core/surfaces/voice_echo.py +26 -0
- core/surfaces/voice_guard.py +23 -0
- core/tickers.py +174 -0
- core/tool_catalog.py +192 -0
- core/version.py +75 -0
- core/wallet/__init__.py +5 -0
- core/wallet/agent_wallet.py +59 -0
- core/wallet/audit_sink.py +61 -0
- core/wallet/config.py +70 -0
- core/wallet/factory.py +87 -0
- core/wallet/policy.py +104 -0
- core/wallet/signer.py +51 -0
- cron/README.md +65 -0
- cron/__init__.py +0 -0
- cron/delivery.py +277 -0
- cron/digest.py +124 -0
- cron/jobs.py +207 -0
- cron/runner.py +297 -0
- cron/schedule.py +194 -0
- cron/scheduler.py +201 -0
- cron/service.py +57 -0
- cron/wake_gate.py +223 -0
- data/__init__.py +1 -0
- data/prompts/autov2_prompts.json +87 -0
- data/prompts/skills/browser-automation/SKILL.md +43 -0
- data/prompts/skills/coding-workflow/SKILL.md +36 -0
- data/prompts/skills/crypto-trading-safety/SKILL.md +53 -0
- data/prompts/skills/document-writing/SKILL.md +33 -0
- data/prompts/skills/email-comms/SKILL.md +33 -0
- data/prompts/skills/file-data-ops/SKILL.md +35 -0
- data/prompts/skills/hyperliquid-account-review/SKILL.md +48 -0
- data/prompts/skills/hyperliquid-market-data/SKILL.md +52 -0
- data/prompts/skills/hyperliquid-trading/SKILL.md +59 -0
- data/prompts/skills/lead-research/SKILL.md +86 -0
- data/prompts/skills/market-research-brief/SKILL.md +104 -0
- data/prompts/skills/person-analyzer/SKILL.md +124 -0
- data/prompts/skills/polymarket-market-research/SKILL.md +54 -0
- data/prompts/skills/polymarket-portfolio-review/SKILL.md +50 -0
- data/prompts/skills/polymarket-trading/SKILL.md +55 -0
- data/prompts/skills/presentation-creator/SKILL.md +36 -0
- data/prompts/skills/project-analyzer/SKILL.md +169 -0
- data/prompts/skills/rules.json +268 -0
- data/prompts/skills/secret-handling/SKILL.md +20 -0
- data/prompts/skills/skill-authoring/SKILL.md +31 -0
- data/prompts/skills/skill-security-review/SKILL.md +27 -0
- data/prompts/skills/social-discovery/SKILL.md +57 -0
- data/prompts/skills/task-planning/SKILL.md +33 -0
- data/prompts/skills/web-research/SKILL.md +39 -0
- data/prompts/skills/web-scraping/SKILL.md +73 -0
- data/prompts/skills/x-engagement/SKILL.md +69 -0
- data/prompts/system_prompts.json +4 -0
- data/subscription_channels.json +5 -0
- modules/README.md +503 -0
- modules/__init__.py +124 -0
- modules/auth/__init__.py +13 -0
- modules/auth/api_key_manager.py +157 -0
- modules/auth/identity_mapper.py +380 -0
- modules/auth/siwe_auth.py +273 -0
- modules/auth/tier_manager.py +173 -0
- modules/base_module.py +190 -0
- modules/credits/__init__.py +29 -0
- modules/credits/balance_manager.py +237 -0
- modules/credits/cost_utils.py +129 -0
- modules/credits/pricing.py +139 -0
- modules/credits/unified_ledger.py +148 -0
- modules/credits/usage_meter.py +310 -0
- modules/credits/usage_tracker.py +674 -0
- modules/database/__init__.py +33 -0
- modules/database/audit_log.py +322 -0
- modules/database/auth_tables.py +276 -0
- modules/database/connection.py +644 -0
- modules/database/connection_pool.py +305 -0
- modules/database/conversation_contexts.py +446 -0
- modules/database/database_manager.py +237 -0
- modules/database/hyperliquid.py +375 -0
- modules/database/polymarket.py +574 -0
- modules/database/user_mcp_servers.py +728 -0
- modules/database/user_profiles.py +562 -0
- modules/database/utils.py +107 -0
- modules/database/x402_tables.py +92 -0
- modules/eip8004/README.md +1069 -0
- modules/eip8004/__init__.py +65 -0
- modules/eip8004/contracts.py +498 -0
- modules/eip8004/models.py +271 -0
- modules/eip8004/registration.py +148 -0
- modules/eip8004/reputation.py +367 -0
- modules/eip8004/validation.py +277 -0
- modules/llm/__init__.py +97 -0
- modules/llm/adapters.py +963 -0
- modules/llm/anthropic_client.py +831 -0
- modules/llm/available_models.py +106 -0
- modules/llm/brain_scrubber.py +137 -0
- modules/llm/cache_hints.py +162 -0
- modules/llm/deepseek_client.py +562 -0
- modules/llm/gemini_client.py +1367 -0
- modules/llm/llm_client.py +1139 -0
- modules/llm/llm_client_registry.py +188 -0
- modules/llm/llm_factory.py +237 -0
- modules/llm/llm_manager.py +1036 -0
- modules/llm/messages.py +374 -0
- modules/llm/model_registry.py +1935 -0
- modules/llm/nvidia_client.py +125 -0
- modules/llm/openai_client.py +800 -0
- modules/llm/openrouter_client.py +969 -0
- modules/llm/profiles.py +178 -0
- modules/llm/test_anthropic_cache_capture.py +35 -0
- modules/llm/test_cached_pricing_derivation.py +24 -0
- modules/llm/think_scrubber.py +444 -0
- modules/llm/token_counter.py +268 -0
- modules/memory/__init__.py +35 -0
- modules/memory/backend_factory.py +83 -0
- modules/memory/cache_manager.py +186 -0
- modules/memory/episodic.py +108 -0
- modules/memory/local_vector_memory_provider.py +552 -0
- modules/memory/memory_manager.py +225 -0
- modules/memory/models.py +312 -0
- modules/memory/provider.py +210 -0
- modules/memory/registry.py +205 -0
- modules/memory/sqlite_memory_provider.py +767 -0
- modules/memory/task/__init__.py +52 -0
- modules/memory/task/compaction_manager.py +157 -0
- modules/memory/task/context_retriever.py +809 -0
- modules/memory/task/hierarchical_memory.py +1002 -0
- modules/memory/task/lexical_retriever.py +71 -0
- modules/memory/task/null_context_manager.py +213 -0
- modules/memory/task/phase_manager.py +625 -0
- modules/memory/task/reflection_service.py +157 -0
- modules/memory/task/semantic_retriever.py +218 -0
- modules/memory/task/task_context_manager.py +1165 -0
- modules/memory/task/test_forgetting_engages.py +24 -0
- modules/memory/task/test_reflection_llm.py +39 -0
- modules/memory/task/test_threat_scan.py +53 -0
- modules/memory/task/threat_scan.py +90 -0
- modules/memory/test_sqlite_memory_provider.py +106 -0
- modules/memory/user_profile_manager.py +527 -0
- modules/payments/__init__.py +11 -0
- modules/payments/deposit_monitor.py +478 -0
- modules/payments/price_oracle.py +70 -0
- modules/payments/treasury_sweeper.py +401 -0
- modules/payments/wallet_generator.py +145 -0
- modules/pfp/__init__.py +1 -0
- modules/pfp/config.py +92 -0
- modules/pfp/mesh.py +565 -0
- modules/pfp/push.py +69 -0
- modules/pfp/renderer.py +85 -0
- modules/pfp/store.py +82 -0
- modules/skills/__init__.py +1 -0
- modules/skills/skill_usage.py +248 -0
- modules/transcription/__init__.py +24 -0
- modules/transcription/base.py +20 -0
- modules/transcription/faster_whisper_transcriber.py +55 -0
- modules/x402/README.md +249 -0
- modules/x402/__init__.py +22 -0
- modules/x402/invoicing.py +416 -0
- modules/x402/middleware.py +364 -0
- modules/x402/settlement_watcher.py +145 -0
- modules/x402/x402_integration.py +344 -0
- polyrob-0.5.0.dist-info/METADATA +482 -0
- polyrob-0.5.0.dist-info/RECORD +745 -0
- polyrob-0.5.0.dist-info/WHEEL +5 -0
- polyrob-0.5.0.dist-info/entry_points.txt +2 -0
- polyrob-0.5.0.dist-info/licenses/LICENSE +21 -0
- polyrob-0.5.0.dist-info/top_level.txt +12 -0
- surfaces/README.md +70 -0
- surfaces/__init__.py +0 -0
- surfaces/email/__init__.py +0 -0
- surfaces/email/dedup.py +44 -0
- surfaces/email/harness.py +187 -0
- surfaces/email/inbound.py +159 -0
- surfaces/email/seed.py +60 -0
- surfaces/email/surface.py +105 -0
- surfaces/telegram/__init__.py +0 -0
- surfaces/telegram/dedup.py +83 -0
- surfaces/telegram/harness.py +886 -0
- surfaces/telegram/inbound.py +145 -0
- surfaces/telegram/interactive_tools.py +49 -0
- surfaces/telegram/markdown.py +347 -0
- surfaces/telegram/rate_limit.py +167 -0
- surfaces/telegram/surface.py +187 -0
- surfaces/telegram/voice.py +52 -0
- surfaces/whatsapp/__init__.py +0 -0
- surfaces/whatsapp/client.py +51 -0
- surfaces/whatsapp/harness.py +62 -0
- surfaces/whatsapp/inbound.py +132 -0
- surfaces/whatsapp/surface.py +64 -0
- surfaces/whatsapp/window.py +34 -0
- tools/README.md +578 -0
- tools/__init__.py +424 -0
- tools/alchemy/__init__.py +5 -0
- tools/alchemy/alchemy_tool.py +389 -0
- tools/anysite/__init__.py +17 -0
- tools/anysite/client.py +88 -0
- tools/anysite/tool.py +89 -0
- tools/base_tool.py +468 -0
- tools/browser/__init__.py +22 -0
- tools/browser/actions.py +118 -0
- tools/browser/browser.py +1457 -0
- tools/browser/browser_manager.py +690 -0
- tools/browser/context.py +1748 -0
- tools/browser/playwright_utils.py +137 -0
- tools/browser/views.py +56 -0
- tools/code_exec/SANDBOX_SECURITY.md +144 -0
- tools/code_exec/__init__.py +178 -0
- tools/code_exec/backend.py +73 -0
- tools/code_exec/backends/__init__.py +1 -0
- tools/code_exec/backends/docker.py +779 -0
- tools/code_exec/backends/local_subprocess.py +154 -0
- tools/code_exec/env_policy.py +45 -0
- tools/code_exec/result.py +42 -0
- tools/code_exec/sandbox_guard.py +59 -0
- tools/code_exec/tool.py +227 -0
- tools/coding/__init__.py +50 -0
- tools/coding/edit.py +107 -0
- tools/coding/search.py +113 -0
- tools/coding/tool.py +353 -0
- tools/collabland/__init__.py +5 -0
- tools/collabland/collabland_tool.py +471 -0
- tools/controller/__init__.py +0 -0
- tools/controller/_helpers.py +165 -0
- tools/controller/action_registration.py +1765 -0
- tools/controller/approval.py +244 -0
- tools/controller/approval_interactive.py +90 -0
- tools/controller/delegation.py +195 -0
- tools/controller/execution.py +797 -0
- tools/controller/execution_context.py +141 -0
- tools/controller/hooks.py +135 -0
- tools/controller/introspection.py +344 -0
- tools/controller/mcp_registrar.py +190 -0
- tools/controller/message_send.py +31 -0
- tools/controller/registry/__init__.py +4 -0
- tools/controller/registry/schema_generators.py +395 -0
- tools/controller/registry/schema_sanitizer.py +406 -0
- tools/controller/registry/service.py +1266 -0
- tools/controller/registry/views.py +151 -0
- tools/controller/service.py +409 -0
- tools/controller/tool_management.py +334 -0
- tools/controller/types.py +28 -0
- tools/controller/views.py +450 -0
- tools/cronjob_tools.py +166 -0
- tools/crypto_trade_gate.py +59 -0
- tools/descriptors.py +452 -0
- tools/dom/__init__.py +0 -0
- tools/dom/history_tree_processor/service.py +244 -0
- tools/dom/history_tree_processor/view.py +99 -0
- tools/dom/service.py +471 -0
- tools/dom/views.py +346 -0
- tools/email_tool.py +403 -0
- tools/exceptions.py +169 -0
- tools/filesystem.py +1038 -0
- tools/filesystem_docproc.py +331 -0
- tools/filesystem_pdf.py +755 -0
- tools/git/__init__.py +42 -0
- tools/git/tool.py +258 -0
- tools/github/__init__.py +33 -0
- tools/github/client.py +94 -0
- tools/github/tool.py +237 -0
- tools/goal_tools.py +309 -0
- tools/hyperliquid/__init__.py +56 -0
- tools/hyperliquid/models.py +233 -0
- tools/hyperliquid/service.py +1680 -0
- tools/knowledge_ingest.py +950 -0
- tools/mcp/README.md +535 -0
- tools/mcp/__init__.py +52 -0
- tools/mcp/catalog.py +115 -0
- tools/mcp/config.py +337 -0
- tools/mcp/mcp_tool.py +1415 -0
- tools/mcp/param_coercion.py +289 -0
- tools/mcp/protocol.py +1520 -0
- tools/mcp/rate_limit.py +50 -0
- tools/mcp/security.py +424 -0
- tools/mcp/self_install.py +111 -0
- tools/mcp/server_manager.py +829 -0
- tools/mcp/subscriptions.py +72 -0
- tools/mcp/user_mcp_service.py +899 -0
- tools/mcp/validation_tracker.py +89 -0
- tools/mcp/views.py +346 -0
- tools/oauth/__init__.py +17 -0
- tools/oauth/manager.py +75 -0
- tools/oauth/provider.py +69 -0
- tools/oauth/providers/__init__.py +1 -0
- tools/oauth/providers/generic_oauth2.py +96 -0
- tools/perplexity_tool.py +280 -0
- tools/polymarket/__init__.py +41 -0
- tools/polymarket/clob_adapter.py +76 -0
- tools/polymarket/models.py +182 -0
- tools/polymarket/service.py +2082 -0
- tools/self_env/__init__.py +61 -0
- tools/self_env/tool.py +274 -0
- tools/shell/__init__.py +80 -0
- tools/shell/backend_pool.py +118 -0
- tools/shell/discipline.py +62 -0
- tools/shell/executor.py +157 -0
- tools/shell/loopback_allow.py +87 -0
- tools/shell/process_registry.py +113 -0
- tools/shell/process_tool.py +131 -0
- tools/shell/state.py +129 -0
- tools/shell/tool.py +151 -0
- tools/task_tool.py +637 -0
- tools/twitter_tool.py +2086 -0
- tools/user_directory.py +179 -0
- tools/web_fetch/__init__.py +3 -0
- tools/web_fetch/fetcher.py +144 -0
- tools/web_fetch/render.py +44 -0
- tools/web_fetch/tool.py +60 -0
- tools/x402/__init__.py +60 -0
- tools/x402/client.py +47 -0
- tools/x402/invoice_tool.py +143 -0
- tools/x402/real_client.py +250 -0
- tools/x402/service.py +131 -0
- utils/README.md +498 -0
- utils/__init__.py +46 -0
- utils/auth_utils.py +114 -0
- utils/bounded_collections.py +162 -0
- utils/circuit_breaker.py +389 -0
- utils/gif_utils.py +435 -0
- utils/markdown_utils.py +291 -0
- utils/message_utils.py +147 -0
- utils/metrics.py +36 -0
- utils/path_validator.py +227 -0
- utils/rate_limit_manager.py +399 -0
- utils/result_size.py +296 -0
- utils/time_utils.py +206 -0
- utils/user_utils.py +188 -0
- webview/README.md +111 -0
- webview/RENAME_AND_ALIGN_HANDOFF.md +200 -0
- webview/__init__.py +8 -0
- webview/activity.py +636 -0
- webview/owner_auth.py +108 -0
- webview/pages.py +448 -0
- webview/repair_sessions.py +399 -0
- webview/server.py +4323 -0
- webview/server_launcher.py +112 -0
- webview/static/css/activity.css +89 -0
- webview/static/css/chat.css +1772 -0
- webview/static/css/components.css +1190 -0
- webview/static/css/config-panel.css +651 -0
- webview/static/css/pages/admin.css +766 -0
- webview/static/css/pages/profile.css +231 -0
- webview/static/css/pages/settings.css +297 -0
- webview/static/css/pages/signin.css +316 -0
- webview/static/css/style.css +4250 -0
- webview/static/css/variables.css +147 -0
- webview/static/css/workspace-fullwidth-fix.css +109 -0
- webview/static/img/favicon.ico +0 -0
- webview/static/js/activity.js +394 -0
- webview/static/js/admin/activity.js +186 -0
- webview/static/js/admin/dashboard.js +163 -0
- webview/static/js/admin/user_detail.js +400 -0
- webview/static/js/admin/users.js +174 -0
- webview/static/js/admin/utils.js +214 -0
- webview/static/js/chat.js +3178 -0
- webview/static/js/config-panel.js +522 -0
- webview/static/js/constants.js +20 -0
- webview/static/js/error-handler.js +226 -0
- webview/static/js/ethers.min.js +1 -0
- webview/static/js/event-filter.js +137 -0
- webview/static/js/event-store.js +351 -0
- webview/static/js/file-attachments.js +374 -0
- webview/static/js/file-loader.js +163 -0
- webview/static/js/index.js +103 -0
- webview/static/js/performance-utils.js +196 -0
- webview/static/js/profile.js +396 -0
- webview/static/js/screenshot.js +386 -0
- webview/static/js/session.js +1527 -0
- webview/static/js/settings.js +1288 -0
- webview/static/js/sidebar-data.js +766 -0
- webview/static/js/sidebar-toggle.js +296 -0
- webview/static/js/socket.io.min.js +7 -0
- webview/static/js/stats.js +355 -0
- webview/static/js/ui-utils.js +420 -0
- webview/static/js/workspace.js +966 -0
- webview/stats_service.py +613 -0
- webview/templates/__init__.py +1 -0
- webview/templates/__pycache__/__init__.cpython-311.pyc +0 -0
- webview/templates/activity.html +36 -0
- webview/templates/admin/activity.html +122 -0
- webview/templates/admin/dashboard.html +112 -0
- webview/templates/admin/user_detail.html +228 -0
- webview/templates/admin/users.html +105 -0
- webview/templates/autonomy.html +60 -0
- webview/templates/error.html +133 -0
- webview/templates/finance.html +90 -0
- webview/templates/identity.html +73 -0
- webview/templates/index.html +42 -0
- webview/templates/layout.html +125 -0
- webview/templates/memory.html +59 -0
- webview/templates/owner_login.html +15 -0
- webview/templates/profile.html +121 -0
- webview/templates/session.html +312 -0
- webview/templates/settings.html +534 -0
- webview/templates/sidebar.html +112 -0
- webview/templates/signin.html +213 -0
- webview/templates/status.html +14 -0
- webview/templates/system.html +45 -0
- webview/webgate.py +196 -0
tools/descriptors.py
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
"""Single source of truth for tool metadata and configuration.
|
|
2
|
+
|
|
3
|
+
This module consolidates all tool-related constants that were previously
|
|
4
|
+
duplicated between tools/__init__.py and core/initialization.py.
|
|
5
|
+
|
|
6
|
+
IMPORTANT: This is the ONLY place tool metadata should be defined.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Dict, List, Type, Any, Optional, TYPE_CHECKING
|
|
11
|
+
from enum import Enum
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from tools.base_tool import BaseTool
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ToolCategory(Enum):
|
|
18
|
+
"""Tool categories for organization."""
|
|
19
|
+
CORE = "core" # Essential tools (filesystem, task)
|
|
20
|
+
BROWSER = "browser" # Browser automation
|
|
21
|
+
COMMUNICATION = "comm" # Email, social media
|
|
22
|
+
SEARCH = "search" # Search and research
|
|
23
|
+
VERIFICATION = "verify" # Token gating, identity
|
|
24
|
+
INTEGRATION = "integration" # MCP, external APIs
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class ToolDescriptor:
|
|
29
|
+
"""Complete descriptor for a tool.
|
|
30
|
+
|
|
31
|
+
This replaces the previous scattered definitions:
|
|
32
|
+
- TOOL_COMPONENTS (name, class)
|
|
33
|
+
- TOOL_DEPENDENCIES (required, optional)
|
|
34
|
+
- TOOL_METADATA (description, requires_config, etc.)
|
|
35
|
+
- TOOL_INIT_ORDER (via init_priority)
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
name: str
|
|
39
|
+
description: str
|
|
40
|
+
category: ToolCategory
|
|
41
|
+
|
|
42
|
+
# Dependencies - services this tool needs
|
|
43
|
+
required_services: List[str] = field(default_factory=list)
|
|
44
|
+
optional_services: List[str] = field(default_factory=list)
|
|
45
|
+
|
|
46
|
+
# Configuration requirements
|
|
47
|
+
required_config: List[str] = field(default_factory=list)
|
|
48
|
+
|
|
49
|
+
# Initialization
|
|
50
|
+
init_priority: int = 50 # Lower = earlier (0-100)
|
|
51
|
+
is_optional: bool = True # Can system start without it?
|
|
52
|
+
|
|
53
|
+
# Rate limiting
|
|
54
|
+
rate_limited: bool = False
|
|
55
|
+
rate_limit_settings: Dict[str, Any] = field(default_factory=dict)
|
|
56
|
+
|
|
57
|
+
# Class reference (set during registration)
|
|
58
|
+
tool_class: Optional[Type["BaseTool"]] = None
|
|
59
|
+
|
|
60
|
+
def __post_init__(self):
|
|
61
|
+
# Ensure rate_limit_manager is always required if rate_limited
|
|
62
|
+
if self.rate_limited and 'rate_limit_manager' not in self.required_services:
|
|
63
|
+
self.required_services = ['rate_limit_manager'] + self.required_services
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# =============================================================================
|
|
67
|
+
# TOOL REGISTRY - Single Source of Truth
|
|
68
|
+
# =============================================================================
|
|
69
|
+
|
|
70
|
+
TOOL_DESCRIPTORS: Dict[str, ToolDescriptor] = {
|
|
71
|
+
# ---------------------------------------------------------------------
|
|
72
|
+
# CORE TOOLS (init_priority 0-19)
|
|
73
|
+
# ---------------------------------------------------------------------
|
|
74
|
+
'filesystem': ToolDescriptor(
|
|
75
|
+
name='filesystem',
|
|
76
|
+
description='File system operations and document processing',
|
|
77
|
+
category=ToolCategory.CORE,
|
|
78
|
+
required_services=['rate_limit_manager'],
|
|
79
|
+
optional_services=['llm_client', 'cache_manager'],
|
|
80
|
+
required_config=[],
|
|
81
|
+
init_priority=10,
|
|
82
|
+
is_optional=False, # Required tool
|
|
83
|
+
),
|
|
84
|
+
|
|
85
|
+
'task': ToolDescriptor(
|
|
86
|
+
name='task',
|
|
87
|
+
description='Task and todo list management',
|
|
88
|
+
category=ToolCategory.CORE,
|
|
89
|
+
required_services=['rate_limit_manager'],
|
|
90
|
+
optional_services=[],
|
|
91
|
+
required_config=[],
|
|
92
|
+
init_priority=15,
|
|
93
|
+
is_optional=True,
|
|
94
|
+
),
|
|
95
|
+
|
|
96
|
+
# ---------------------------------------------------------------------
|
|
97
|
+
# BROWSER TOOLS (init_priority 5 - needs to be early for pooling)
|
|
98
|
+
# ---------------------------------------------------------------------
|
|
99
|
+
'browser_manager': ToolDescriptor(
|
|
100
|
+
name='browser_manager',
|
|
101
|
+
description='Browser lifecycle and context pooling manager',
|
|
102
|
+
category=ToolCategory.BROWSER,
|
|
103
|
+
required_services=[],
|
|
104
|
+
optional_services=[],
|
|
105
|
+
required_config=[],
|
|
106
|
+
init_priority=5, # Very early - browser pool
|
|
107
|
+
is_optional=True,
|
|
108
|
+
),
|
|
109
|
+
|
|
110
|
+
# ---------------------------------------------------------------------
|
|
111
|
+
# SEARCH TOOLS (init_priority 20-29)
|
|
112
|
+
# ---------------------------------------------------------------------
|
|
113
|
+
'perplexity': ToolDescriptor(
|
|
114
|
+
name='perplexity',
|
|
115
|
+
description='AI-powered search via Perplexity API',
|
|
116
|
+
category=ToolCategory.SEARCH,
|
|
117
|
+
required_services=['rate_limit_manager'],
|
|
118
|
+
optional_services=['cache_manager'],
|
|
119
|
+
required_config=['perplexity_api_key'],
|
|
120
|
+
init_priority=20,
|
|
121
|
+
is_optional=True,
|
|
122
|
+
),
|
|
123
|
+
|
|
124
|
+
'web_fetch': ToolDescriptor(
|
|
125
|
+
name='web_fetch',
|
|
126
|
+
description='Stateless web page reader (URL -> markdown). No browser/Chromium.',
|
|
127
|
+
category=ToolCategory.SEARCH,
|
|
128
|
+
required_services=[],
|
|
129
|
+
optional_services=['cache_manager'],
|
|
130
|
+
required_config=[],
|
|
131
|
+
init_priority=21,
|
|
132
|
+
is_optional=True,
|
|
133
|
+
),
|
|
134
|
+
|
|
135
|
+
# ---------------------------------------------------------------------
|
|
136
|
+
# COMMUNICATION TOOLS (init_priority 30-39)
|
|
137
|
+
# ---------------------------------------------------------------------
|
|
138
|
+
'twitter': ToolDescriptor(
|
|
139
|
+
name='twitter',
|
|
140
|
+
description='Twitter/X account actions: post/media/poll/thread, reply/quote/delete, like/retweet, follow/mute/block, DM, mentions (gated by TWITTER_ENABLED). For Twitter/X DATA RETRIEVAL prefer the anysite tool to conserve quota.',
|
|
141
|
+
category=ToolCategory.COMMUNICATION,
|
|
142
|
+
required_services=['rate_limit_manager', 'database_manager'],
|
|
143
|
+
optional_services=['cache_manager'],
|
|
144
|
+
required_config=[], # Uses OAuth tokens from DB
|
|
145
|
+
init_priority=30,
|
|
146
|
+
is_optional=True,
|
|
147
|
+
rate_limited=True,
|
|
148
|
+
rate_limit_settings={
|
|
149
|
+
'default_wait': 900, # 15 minutes
|
|
150
|
+
'requests_per_minute': 300,
|
|
151
|
+
'burst_limit': 50
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
|
|
155
|
+
'email': ToolDescriptor(
|
|
156
|
+
name='email',
|
|
157
|
+
description='Email sending via Gmail',
|
|
158
|
+
category=ToolCategory.COMMUNICATION,
|
|
159
|
+
required_services=['rate_limit_manager'],
|
|
160
|
+
optional_services=[],
|
|
161
|
+
required_config=['gmail_email', 'gmail_app_password'],
|
|
162
|
+
init_priority=35,
|
|
163
|
+
is_optional=True,
|
|
164
|
+
),
|
|
165
|
+
|
|
166
|
+
# ---------------------------------------------------------------------
|
|
167
|
+
# VERIFICATION TOOLS (init_priority 40-49)
|
|
168
|
+
# ---------------------------------------------------------------------
|
|
169
|
+
'collabland': ToolDescriptor(
|
|
170
|
+
name='collabland',
|
|
171
|
+
description='CollabLand token gating verification',
|
|
172
|
+
category=ToolCategory.VERIFICATION,
|
|
173
|
+
required_services=['rate_limit_manager', 'database_manager'],
|
|
174
|
+
optional_services=['cache_manager'],
|
|
175
|
+
required_config=['collabland_api_key'],
|
|
176
|
+
init_priority=40,
|
|
177
|
+
is_optional=True,
|
|
178
|
+
),
|
|
179
|
+
|
|
180
|
+
'alchemy': ToolDescriptor(
|
|
181
|
+
name='alchemy',
|
|
182
|
+
description='Alchemy NFT API for token verification',
|
|
183
|
+
category=ToolCategory.VERIFICATION,
|
|
184
|
+
required_services=['rate_limit_manager'],
|
|
185
|
+
optional_services=['cache_manager'],
|
|
186
|
+
required_config=['alchemy_api_key'],
|
|
187
|
+
init_priority=45,
|
|
188
|
+
is_optional=True,
|
|
189
|
+
),
|
|
190
|
+
|
|
191
|
+
# ---------------------------------------------------------------------
|
|
192
|
+
# INTEGRATION TOOLS (init_priority 50-59)
|
|
193
|
+
# ---------------------------------------------------------------------
|
|
194
|
+
'mcp': ToolDescriptor(
|
|
195
|
+
name='mcp',
|
|
196
|
+
description='Model Context Protocol server integration',
|
|
197
|
+
category=ToolCategory.INTEGRATION,
|
|
198
|
+
required_services=['rate_limit_manager'],
|
|
199
|
+
optional_services=['cache_manager'],
|
|
200
|
+
required_config=[], # MCP config is separate
|
|
201
|
+
init_priority=50,
|
|
202
|
+
is_optional=True,
|
|
203
|
+
),
|
|
204
|
+
|
|
205
|
+
'anysite': ToolDescriptor(
|
|
206
|
+
name='anysite',
|
|
207
|
+
description="Query AnySite's 200+ sources / 1,200+ endpoints (LinkedIn, X, Reddit, YouTube, GitHub, SEC, web scraper) via the anysite CLI",
|
|
208
|
+
category=ToolCategory.INTEGRATION,
|
|
209
|
+
is_optional=True,
|
|
210
|
+
init_priority=52,
|
|
211
|
+
),
|
|
212
|
+
|
|
213
|
+
'polymarket_data': ToolDescriptor(
|
|
214
|
+
name='polymarket_data',
|
|
215
|
+
description='Polymarket prediction markets - read-only market data & research (no wallet)',
|
|
216
|
+
category=ToolCategory.INTEGRATION,
|
|
217
|
+
required_services=['rate_limit_manager'],
|
|
218
|
+
optional_services=['cache_manager'],
|
|
219
|
+
required_config=[],
|
|
220
|
+
init_priority=53, # before the trade tool
|
|
221
|
+
is_optional=True,
|
|
222
|
+
rate_limited=True,
|
|
223
|
+
rate_limit_settings={'requests_per_minute': 60, 'burst_limit': 10, 'default_wait': 60},
|
|
224
|
+
),
|
|
225
|
+
|
|
226
|
+
'polymarket': ToolDescriptor(
|
|
227
|
+
name='polymarket',
|
|
228
|
+
description='Polymarket prediction markets - trading and market data',
|
|
229
|
+
category=ToolCategory.INTEGRATION,
|
|
230
|
+
required_services=['rate_limit_manager'],
|
|
231
|
+
optional_services=['cache_manager', 'database_manager'],
|
|
232
|
+
required_config=[], # Credentials stored in DB, not config
|
|
233
|
+
init_priority=55, # After MCP
|
|
234
|
+
is_optional=True,
|
|
235
|
+
rate_limited=True,
|
|
236
|
+
rate_limit_settings={
|
|
237
|
+
'requests_per_minute': 60,
|
|
238
|
+
'burst_limit': 10,
|
|
239
|
+
'default_wait': 60
|
|
240
|
+
}
|
|
241
|
+
),
|
|
242
|
+
|
|
243
|
+
'hyperliquid_data': ToolDescriptor(
|
|
244
|
+
name='hyperliquid_data',
|
|
245
|
+
description='Hyperliquid perps/spot - read-only market data & account state (no signing)',
|
|
246
|
+
category=ToolCategory.INTEGRATION,
|
|
247
|
+
required_services=['rate_limit_manager'],
|
|
248
|
+
optional_services=['cache_manager'],
|
|
249
|
+
required_config=[],
|
|
250
|
+
init_priority=54, # before the trade tool
|
|
251
|
+
is_optional=True,
|
|
252
|
+
rate_limited=True,
|
|
253
|
+
rate_limit_settings={'requests_per_minute': 120, 'burst_limit': 20, 'default_wait': 30},
|
|
254
|
+
),
|
|
255
|
+
|
|
256
|
+
'hyperliquid': ToolDescriptor(
|
|
257
|
+
name='hyperliquid',
|
|
258
|
+
description='Hyperliquid perpetuals and spot trading - market data and execution',
|
|
259
|
+
category=ToolCategory.INTEGRATION,
|
|
260
|
+
required_services=['rate_limit_manager'],
|
|
261
|
+
optional_services=['cache_manager', 'database_manager'],
|
|
262
|
+
required_config=[], # Credentials stored in DB, not config
|
|
263
|
+
init_priority=56, # After polymarket
|
|
264
|
+
is_optional=True,
|
|
265
|
+
rate_limited=True,
|
|
266
|
+
rate_limit_settings={
|
|
267
|
+
'requests_per_minute': 120,
|
|
268
|
+
'burst_limit': 20,
|
|
269
|
+
'default_wait': 30
|
|
270
|
+
}
|
|
271
|
+
),
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# =============================================================================
|
|
276
|
+
# DERIVED CONSTANTS (for backward compatibility)
|
|
277
|
+
# =============================================================================
|
|
278
|
+
|
|
279
|
+
def get_tool_init_order() -> List[str]:
|
|
280
|
+
"""Get tools in initialization order (sorted by init_priority)."""
|
|
281
|
+
return sorted(
|
|
282
|
+
TOOL_DESCRIPTORS.keys(),
|
|
283
|
+
key=lambda name: TOOL_DESCRIPTORS[name].init_priority
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def get_tool_dependencies(tool_name: str) -> Dict[str, List[str]]:
|
|
288
|
+
"""Get dependencies for a tool (backward compatible format)."""
|
|
289
|
+
if tool_name not in TOOL_DESCRIPTORS:
|
|
290
|
+
return {'required': [], 'optional': []}
|
|
291
|
+
desc = TOOL_DESCRIPTORS[tool_name]
|
|
292
|
+
return {
|
|
293
|
+
'required': desc.required_services,
|
|
294
|
+
'optional': desc.optional_services
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def get_tool_metadata(tool_name: str) -> Dict[str, Any]:
|
|
299
|
+
"""Get metadata for a tool (backward compatible format)."""
|
|
300
|
+
if tool_name not in TOOL_DESCRIPTORS:
|
|
301
|
+
return {
|
|
302
|
+
'name': tool_name.title(),
|
|
303
|
+
'description': 'No description available',
|
|
304
|
+
'requires_config': [],
|
|
305
|
+
'required': False
|
|
306
|
+
}
|
|
307
|
+
desc = TOOL_DESCRIPTORS[tool_name]
|
|
308
|
+
return {
|
|
309
|
+
'name': desc.name,
|
|
310
|
+
'description': desc.description,
|
|
311
|
+
'requires_config': desc.required_config,
|
|
312
|
+
'required': not desc.is_optional,
|
|
313
|
+
'dependencies': desc.required_services,
|
|
314
|
+
'optional_dependencies': desc.optional_services,
|
|
315
|
+
'rate_limited': desc.rate_limited,
|
|
316
|
+
'rate_limit_settings': desc.rate_limit_settings,
|
|
317
|
+
'is_core': desc.category == ToolCategory.CORE
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def get_optional_tools() -> set:
|
|
322
|
+
"""Get set of optional tool names."""
|
|
323
|
+
return {
|
|
324
|
+
name for name, desc in TOOL_DESCRIPTORS.items()
|
|
325
|
+
if desc.is_optional
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def get_available_tools() -> Dict[str, str]:
|
|
330
|
+
"""Get dict of tool name -> description."""
|
|
331
|
+
return {
|
|
332
|
+
name: desc.description
|
|
333
|
+
for name, desc in TOOL_DESCRIPTORS.items()
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def get_default_tools() -> List[str]:
|
|
338
|
+
"""Get list of tools that should be enabled by default in UI.
|
|
339
|
+
|
|
340
|
+
These are the baseline tools that provide essential functionality.
|
|
341
|
+
Returns both the canonical name and any aliases (e.g., 'browser' for 'browser_manager').
|
|
342
|
+
"""
|
|
343
|
+
# Core tools always enabled
|
|
344
|
+
defaults = ['filesystem', 'browser']
|
|
345
|
+
return defaults
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def get_agent_usable_tools() -> Dict[str, ToolDescriptor]:
|
|
349
|
+
"""Get tools that should appear in the agent configuration panel.
|
|
350
|
+
|
|
351
|
+
Excludes:
|
|
352
|
+
- Internal verification tools (collabland, alchemy)
|
|
353
|
+
- Tools shown as MCP servers (polymarket)
|
|
354
|
+
- Deprecated tools (twitter - use mcp:anysite)
|
|
355
|
+
- Internal tools not meant for user selection (task)
|
|
356
|
+
"""
|
|
357
|
+
# Categories that should appear in config panel
|
|
358
|
+
usable_categories = {ToolCategory.CORE, ToolCategory.BROWSER, ToolCategory.SEARCH, ToolCategory.COMMUNICATION, ToolCategory.INTEGRATION}
|
|
359
|
+
|
|
360
|
+
# Specific exclusions
|
|
361
|
+
# NOTE: polymarket/hyperliquid are live in-process tools (see TOOL_DESCRIPTORS above),
|
|
362
|
+
# NOT MCP — the old "polymarket is MCP-only" note was stale. They are selectable but
|
|
363
|
+
# high-risk and stay out of the DEFAULT tool lists (opt-in only).
|
|
364
|
+
# twitter is loadable (G1 full write surface, gated by TWITTER_ENABLED) — it is
|
|
365
|
+
# selectable in the panel but stays out of the DEFAULT tool lists (opt-in only).
|
|
366
|
+
excluded_tools = {'collabland', 'alchemy', 'task'}
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
name: desc
|
|
370
|
+
for name, desc in TOOL_DESCRIPTORS.items()
|
|
371
|
+
if desc.category in usable_categories and name not in excluded_tools
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def get_tool_display_name(tool_name: str) -> str:
|
|
376
|
+
"""Get display name for a tool, handling aliases.
|
|
377
|
+
|
|
378
|
+
Maps internal names to user-facing names:
|
|
379
|
+
- browser_manager -> browser
|
|
380
|
+
"""
|
|
381
|
+
aliases = {
|
|
382
|
+
'browser_manager': 'browser'
|
|
383
|
+
}
|
|
384
|
+
return aliases.get(tool_name, tool_name)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
# Backward compatible exports
|
|
388
|
+
TOOL_INIT_ORDER = get_tool_init_order()
|
|
389
|
+
OPTIONAL_TOOLS = get_optional_tools()
|
|
390
|
+
AVAILABLE_TOOLS = get_available_tools()
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
# Build TOOL_COMPONENTS and TOOL_DEPENDENCIES dynamically
|
|
394
|
+
# (These will be populated when tools/__init__.py imports this and registers classes)
|
|
395
|
+
TOOL_COMPONENTS: List[tuple] = []
|
|
396
|
+
TOOL_DEPENDENCIES: Dict[str, Dict[str, List[str]]] = {
|
|
397
|
+
name: get_tool_dependencies(name)
|
|
398
|
+
for name in TOOL_DESCRIPTORS
|
|
399
|
+
}
|
|
400
|
+
TOOL_METADATA: Dict[str, Dict[str, Any]] = {
|
|
401
|
+
name: get_tool_metadata(name)
|
|
402
|
+
for name in TOOL_DESCRIPTORS
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def register_tool_class(tool_name: str, tool_class: Type["BaseTool"]) -> None:
|
|
407
|
+
"""Register a tool class with its descriptor.
|
|
408
|
+
|
|
409
|
+
Called from tools/__init__.py to associate classes with descriptors.
|
|
410
|
+
"""
|
|
411
|
+
if tool_name in TOOL_DESCRIPTORS:
|
|
412
|
+
TOOL_DESCRIPTORS[tool_name].tool_class = tool_class
|
|
413
|
+
# Update TOOL_COMPONENTS for backward compatibility
|
|
414
|
+
if not any(name == tool_name for name, _ in TOOL_COMPONENTS):
|
|
415
|
+
TOOL_COMPONENTS.append((tool_name, tool_class))
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def get_tool_class(tool_name: str) -> Optional[Type["BaseTool"]]:
|
|
419
|
+
"""Get the tool class for a given tool name."""
|
|
420
|
+
if tool_name in TOOL_DESCRIPTORS:
|
|
421
|
+
return TOOL_DESCRIPTORS[tool_name].tool_class
|
|
422
|
+
return None
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def register_optional_tool(
|
|
426
|
+
name: str,
|
|
427
|
+
tool_cls: Type["BaseTool"],
|
|
428
|
+
descriptor: "ToolDescriptor",
|
|
429
|
+
enabled_fn,
|
|
430
|
+
*,
|
|
431
|
+
force: bool = False,
|
|
432
|
+
) -> bool:
|
|
433
|
+
"""Register an opt-in tool (code_exec/cronjob/goal) behind a feature gate.
|
|
434
|
+
|
|
435
|
+
Inserts *descriptor* into ``TOOL_DESCRIPTORS`` idempotently (existing entry is
|
|
436
|
+
never overwritten), then calls ``register_tool_class``. Returns ``True`` iff
|
|
437
|
+
the tool was registered.
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
name: Tool key (e.g. ``"cronjob"``).
|
|
441
|
+
tool_cls: The ``BaseTool`` subclass to register.
|
|
442
|
+
descriptor: ``ToolDescriptor`` instance for this tool.
|
|
443
|
+
enabled_fn: Zero-argument callable; if it returns falsy *and* ``force`` is
|
|
444
|
+
``False``, registration is skipped.
|
|
445
|
+
force: If ``True``, bypass ``enabled_fn`` and register unconditionally.
|
|
446
|
+
"""
|
|
447
|
+
if not (force or enabled_fn()):
|
|
448
|
+
return False
|
|
449
|
+
if name not in TOOL_DESCRIPTORS:
|
|
450
|
+
TOOL_DESCRIPTORS[name] = descriptor
|
|
451
|
+
register_tool_class(name, tool_cls)
|
|
452
|
+
return True
|
tools/dom/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from tools.dom.history_tree_processor.view import DOMHistoryElement, HashedDomElement
|
|
6
|
+
from tools.dom.views import DOMElementNode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class HistoryTreeProcessor:
|
|
10
|
+
""" "
|
|
11
|
+
Operations on the DOM elements
|
|
12
|
+
|
|
13
|
+
@dev be careful - text nodes can change even if elements stay the same
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def convert_dom_element_to_history_element(dom_element: DOMElementNode) -> DOMHistoryElement:
|
|
18
|
+
try:
|
|
19
|
+
parent_branch_path = HistoryTreeProcessor._get_parent_branch_path(dom_element)
|
|
20
|
+
# Safely try to get the CSS selector with error handling
|
|
21
|
+
try:
|
|
22
|
+
css_selector = dom_element.get_advanced_css_selector()
|
|
23
|
+
except Exception as e:
|
|
24
|
+
# If CSS selector generation fails, create a simple fallback
|
|
25
|
+
css_selector = f"{dom_element.tag_name}_{hash(dom_element.xpath)}"
|
|
26
|
+
|
|
27
|
+
return DOMHistoryElement(
|
|
28
|
+
dom_element.tag_name,
|
|
29
|
+
dom_element.xpath,
|
|
30
|
+
dom_element.highlight_index,
|
|
31
|
+
parent_branch_path,
|
|
32
|
+
dom_element.attributes,
|
|
33
|
+
dom_element.shadow_root,
|
|
34
|
+
css_selector=css_selector,
|
|
35
|
+
page_coordinates=dom_element.page_coordinates,
|
|
36
|
+
viewport_coordinates=dom_element.viewport_coordinates,
|
|
37
|
+
viewport_info=dom_element.viewport_info,
|
|
38
|
+
)
|
|
39
|
+
except Exception as e:
|
|
40
|
+
# Create a minimal history element as fallback if anything fails
|
|
41
|
+
default_branch_path = ["html", "body"] if dom_element.tag_name.lower() != "html" else ["html"]
|
|
42
|
+
return DOMHistoryElement(
|
|
43
|
+
tag_name=dom_element.tag_name or "div",
|
|
44
|
+
xpath=dom_element.xpath or "",
|
|
45
|
+
highlight_index=dom_element.highlight_index,
|
|
46
|
+
entire_parent_branch_path=default_branch_path,
|
|
47
|
+
attributes=dom_element.attributes or {},
|
|
48
|
+
shadow_root=False,
|
|
49
|
+
css_selector=f"fallback-{hash(str(dom_element))}",
|
|
50
|
+
page_coordinates=None,
|
|
51
|
+
viewport_coordinates=None,
|
|
52
|
+
viewport_info=None
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def find_history_element_in_tree(dom_history_element: DOMHistoryElement, tree: DOMElementNode) -> Optional[DOMElementNode]:
|
|
57
|
+
hashed_dom_history_element = HistoryTreeProcessor._hash_dom_history_element(dom_history_element)
|
|
58
|
+
|
|
59
|
+
def process_node(node: DOMElementNode):
|
|
60
|
+
if node.highlight_index is not None:
|
|
61
|
+
hashed_node = HistoryTreeProcessor._hash_dom_element(node)
|
|
62
|
+
if hashed_node == hashed_dom_history_element:
|
|
63
|
+
return node
|
|
64
|
+
for child in node.children:
|
|
65
|
+
if isinstance(child, DOMElementNode):
|
|
66
|
+
result = process_node(child)
|
|
67
|
+
if result is not None:
|
|
68
|
+
return result
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
return process_node(tree)
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def compare_history_element_and_dom_element(dom_history_element: DOMHistoryElement, dom_element: DOMElementNode) -> bool:
|
|
75
|
+
hashed_dom_history_element = HistoryTreeProcessor._hash_dom_history_element(dom_history_element)
|
|
76
|
+
hashed_dom_element = HistoryTreeProcessor._hash_dom_element(dom_element)
|
|
77
|
+
|
|
78
|
+
return hashed_dom_history_element == hashed_dom_element
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def _hash_dom_history_element(dom_history_element: DOMHistoryElement) -> HashedDomElement:
|
|
82
|
+
branch_path_hash = HistoryTreeProcessor._parent_branch_path_hash(dom_history_element.entire_parent_branch_path)
|
|
83
|
+
attributes_hash = HistoryTreeProcessor._attributes_hash(dom_history_element.attributes)
|
|
84
|
+
xpath_hash = HistoryTreeProcessor._xpath_hash(dom_history_element.xpath)
|
|
85
|
+
|
|
86
|
+
return HashedDomElement(branch_path_hash, attributes_hash, xpath_hash)
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def _hash_dom_element(dom_element: DOMElementNode) -> HashedDomElement:
|
|
90
|
+
"""Hash a DOM element with comprehensive error handling"""
|
|
91
|
+
try:
|
|
92
|
+
# Get parent branch path with error handling
|
|
93
|
+
try:
|
|
94
|
+
parent_branch_path = HistoryTreeProcessor._get_parent_branch_path(dom_element)
|
|
95
|
+
except Exception as e:
|
|
96
|
+
import logging
|
|
97
|
+
logging.warning(f"Error getting parent branch path: {str(e)}")
|
|
98
|
+
# Use a fallback path based on tag name
|
|
99
|
+
parent_branch_path = ["html", dom_element.tag_name] if hasattr(dom_element, "tag_name") else ["html", "unknown"]
|
|
100
|
+
|
|
101
|
+
# Get branch path hash with error handling
|
|
102
|
+
try:
|
|
103
|
+
branch_path_hash = HistoryTreeProcessor._parent_branch_path_hash(parent_branch_path)
|
|
104
|
+
except Exception as e:
|
|
105
|
+
import logging
|
|
106
|
+
logging.warning(f"Error hashing branch path: {str(e)}")
|
|
107
|
+
# Use a fallback hash from the path or a constant
|
|
108
|
+
import hashlib
|
|
109
|
+
path_str = "/".join(parent_branch_path)
|
|
110
|
+
branch_path_hash = hashlib.sha256(path_str.encode()).hexdigest()
|
|
111
|
+
|
|
112
|
+
# Get attributes hash with error handling
|
|
113
|
+
try:
|
|
114
|
+
attributes = dom_element.attributes if hasattr(dom_element, "attributes") else {}
|
|
115
|
+
attributes_hash = HistoryTreeProcessor._attributes_hash(attributes)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
import logging
|
|
118
|
+
logging.warning(f"Error hashing attributes: {str(e)}")
|
|
119
|
+
# Use a fallback hash from stringified attributes or a constant
|
|
120
|
+
import hashlib
|
|
121
|
+
attr_str = str(getattr(dom_element, "attributes", {}))
|
|
122
|
+
attributes_hash = hashlib.sha256(attr_str.encode()).hexdigest()
|
|
123
|
+
|
|
124
|
+
# Get xpath hash with error handling
|
|
125
|
+
try:
|
|
126
|
+
xpath = dom_element.xpath if hasattr(dom_element, "xpath") else ""
|
|
127
|
+
xpath_hash = HistoryTreeProcessor._xpath_hash(xpath)
|
|
128
|
+
except Exception as e:
|
|
129
|
+
import logging
|
|
130
|
+
logging.warning(f"Error hashing xpath: {str(e)}")
|
|
131
|
+
# Use a fallback hash from the xpath or a constant
|
|
132
|
+
import hashlib
|
|
133
|
+
xpath_str = str(getattr(dom_element, "xpath", ""))
|
|
134
|
+
xpath_hash = hashlib.sha256(xpath_str.encode()).hexdigest()
|
|
135
|
+
|
|
136
|
+
# Create a HashedDomElement with the computed hashes
|
|
137
|
+
return HashedDomElement(branch_path_hash, attributes_hash, xpath_hash)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
# Log the error and create a minimal valid hash as a fallback
|
|
140
|
+
import logging
|
|
141
|
+
logging.error(f"Critical error in _hash_dom_element: {str(e)}")
|
|
142
|
+
|
|
143
|
+
# Create minimal valid hash values based on element ID to ensure uniqueness
|
|
144
|
+
import hashlib
|
|
145
|
+
element_id = str(id(dom_element))
|
|
146
|
+
fallback_hash = hashlib.sha256(element_id.encode()).hexdigest()
|
|
147
|
+
|
|
148
|
+
# Split the hash into three parts for the three hash fields
|
|
149
|
+
third = len(fallback_hash) // 3
|
|
150
|
+
return HashedDomElement(
|
|
151
|
+
fallback_hash[:third],
|
|
152
|
+
fallback_hash[third:2*third],
|
|
153
|
+
fallback_hash[2*third:]
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
@staticmethod
|
|
157
|
+
def _get_parent_branch_path(dom_element: DOMElementNode) -> list[str]:
|
|
158
|
+
try:
|
|
159
|
+
parents: list[DOMElementNode] = []
|
|
160
|
+
current_element: DOMElementNode = dom_element
|
|
161
|
+
|
|
162
|
+
# Safety check - limit iterations to prevent infinite loops
|
|
163
|
+
iteration_limit = 100
|
|
164
|
+
iteration_count = 0
|
|
165
|
+
|
|
166
|
+
while current_element.parent is not None and iteration_count < iteration_limit:
|
|
167
|
+
parents.append(current_element)
|
|
168
|
+
current_element = current_element.parent
|
|
169
|
+
iteration_count += 1
|
|
170
|
+
|
|
171
|
+
if iteration_count >= iteration_limit:
|
|
172
|
+
# If we hit the limit, it could be a circular reference
|
|
173
|
+
# Return just the direct path we have so far
|
|
174
|
+
return [parent.tag_name for parent in parents[-10:]] if parents else []
|
|
175
|
+
|
|
176
|
+
parents.reverse()
|
|
177
|
+
return [parent.tag_name for parent in parents]
|
|
178
|
+
except Exception as e:
|
|
179
|
+
# If anything goes wrong, return a minimal valid path
|
|
180
|
+
return ["html", "body"] if dom_element.tag_name.lower() != "html" else ["html"]
|
|
181
|
+
|
|
182
|
+
@staticmethod
|
|
183
|
+
def _parent_branch_path_hash(parent_branch_path: list[str]) -> str:
|
|
184
|
+
try:
|
|
185
|
+
# If list is empty, use a default path
|
|
186
|
+
if not parent_branch_path:
|
|
187
|
+
return hashlib.sha256("default/path".encode()).hexdigest()
|
|
188
|
+
|
|
189
|
+
# Join with extra safety for invalid data
|
|
190
|
+
safe_path = []
|
|
191
|
+
for item in parent_branch_path:
|
|
192
|
+
if item is not None and isinstance(item, str):
|
|
193
|
+
safe_path.append(item)
|
|
194
|
+
else:
|
|
195
|
+
safe_path.append("unknown")
|
|
196
|
+
|
|
197
|
+
parent_branch_path_string = '/'.join(safe_path)
|
|
198
|
+
return hashlib.sha256(parent_branch_path_string.encode()).hexdigest()
|
|
199
|
+
except Exception as e:
|
|
200
|
+
# Fallback hash if anything fails
|
|
201
|
+
return hashlib.sha256("error".encode()).hexdigest()
|
|
202
|
+
|
|
203
|
+
@staticmethod
|
|
204
|
+
def _attributes_hash(attributes: dict[str, str]) -> str:
|
|
205
|
+
try:
|
|
206
|
+
if not attributes:
|
|
207
|
+
return hashlib.sha256("empty_attributes".encode()).hexdigest()
|
|
208
|
+
|
|
209
|
+
# Handle attributes safely
|
|
210
|
+
safe_attrs = []
|
|
211
|
+
for key, value in attributes.items():
|
|
212
|
+
if key is not None and value is not None:
|
|
213
|
+
# Convert any non-string values to strings safely
|
|
214
|
+
if not isinstance(key, str):
|
|
215
|
+
key = str(key)
|
|
216
|
+
if not isinstance(value, str):
|
|
217
|
+
value = str(value)
|
|
218
|
+
safe_attrs.append(f'{key}={value}')
|
|
219
|
+
|
|
220
|
+
attributes_string = ''.join(safe_attrs)
|
|
221
|
+
return hashlib.sha256(attributes_string.encode()).hexdigest()
|
|
222
|
+
except Exception as e:
|
|
223
|
+
# Fallback hash if anything fails
|
|
224
|
+
return hashlib.sha256("error_attributes".encode()).hexdigest()
|
|
225
|
+
|
|
226
|
+
@staticmethod
|
|
227
|
+
def _xpath_hash(xpath: str) -> str:
|
|
228
|
+
try:
|
|
229
|
+
if not xpath:
|
|
230
|
+
return hashlib.sha256("empty_xpath".encode()).hexdigest()
|
|
231
|
+
|
|
232
|
+
if not isinstance(xpath, str):
|
|
233
|
+
xpath = str(xpath)
|
|
234
|
+
|
|
235
|
+
return hashlib.sha256(xpath.encode()).hexdigest()
|
|
236
|
+
except Exception as e:
|
|
237
|
+
# Fallback hash if anything fails
|
|
238
|
+
return hashlib.sha256("error_xpath".encode()).hexdigest()
|
|
239
|
+
|
|
240
|
+
@staticmethod
|
|
241
|
+
def _text_hash(dom_element: DOMElementNode) -> str:
|
|
242
|
+
""" """
|
|
243
|
+
text_string = dom_element.get_all_text_till_next_clickable_element()
|
|
244
|
+
return hashlib.sha256(text_string.encode()).hexdigest()
|