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
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool call builder for standardizing tool call structure across AutoV2.
|
|
3
|
+
|
|
4
|
+
This module provides a consistent interface for creating tool calls that align
|
|
5
|
+
with OpenAI tool call schemas. It also centralizes validation,
|
|
6
|
+
repair, and placeholder creation for tool message sequences.
|
|
7
|
+
|
|
8
|
+
GROK 4.1 / MCP NESTED ARGUMENTS FIX (Dec 2025):
|
|
9
|
+
Some LLMs (notably Grok 4.1 via OpenRouter) return nested object/array parameters
|
|
10
|
+
as JSON strings instead of parsed objects. For example:
|
|
11
|
+
{"authors": "[\"a\", \"b\"]", "filters": "{\"key\": \"val\"}"}
|
|
12
|
+
instead of:
|
|
13
|
+
{"authors": ["a", "b"], "filters": {"key": "val"}}
|
|
14
|
+
|
|
15
|
+
This module includes `_deep_parse_json_strings()` to recursively parse these
|
|
16
|
+
stringified nested structures, fixing MCP tool calling issues.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from typing import Dict, List, Optional, Any, Union, Tuple, Set
|
|
20
|
+
from dataclasses import dataclass, field, asdict
|
|
21
|
+
from uuid import uuid4
|
|
22
|
+
import json
|
|
23
|
+
import logging
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _deep_parse_json_strings(obj: Any, depth: int = 0, max_depth: int = 10) -> Any:
|
|
29
|
+
"""Recursively parse JSON strings within nested structures.
|
|
30
|
+
|
|
31
|
+
GROK 4.1 / MCP FIX (Dec 2025):
|
|
32
|
+
Some LLMs return nested objects/arrays as JSON strings instead of parsed objects.
|
|
33
|
+
This function recursively finds and parses those strings.
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
'["a", "b"]' -> ["a", "b"]
|
|
37
|
+
'{"key": "val"}' -> {"key": "val"}
|
|
38
|
+
{"items": '["x"]'} -> {"items": ["x"]}
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
obj: The object to process (any type)
|
|
42
|
+
depth: Current recursion depth (for safety)
|
|
43
|
+
max_depth: Maximum recursion depth to prevent infinite loops
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
The object with all JSON strings parsed into their Python equivalents
|
|
47
|
+
"""
|
|
48
|
+
# Safety: prevent infinite recursion
|
|
49
|
+
if depth > max_depth:
|
|
50
|
+
logger.warning(f"[DEEP_PARSE] Max depth {max_depth} reached, returning as-is")
|
|
51
|
+
return obj
|
|
52
|
+
|
|
53
|
+
if isinstance(obj, str):
|
|
54
|
+
# Check if this string looks like JSON (starts with { or [)
|
|
55
|
+
stripped = obj.strip()
|
|
56
|
+
if stripped and (stripped.startswith('{') or stripped.startswith('[')):
|
|
57
|
+
try:
|
|
58
|
+
parsed = json.loads(stripped)
|
|
59
|
+
# Recursively process the parsed result (it may contain more JSON strings)
|
|
60
|
+
result = _deep_parse_json_strings(parsed, depth + 1, max_depth)
|
|
61
|
+
logger.debug(f"[DEEP_PARSE] Parsed JSON string at depth {depth}: {stripped[:50]}...")
|
|
62
|
+
return result
|
|
63
|
+
except (json.JSONDecodeError, ValueError):
|
|
64
|
+
# Not valid JSON, return as-is
|
|
65
|
+
return obj
|
|
66
|
+
return obj
|
|
67
|
+
|
|
68
|
+
elif isinstance(obj, dict):
|
|
69
|
+
# Recursively process all values in the dict
|
|
70
|
+
return {k: _deep_parse_json_strings(v, depth + 1, max_depth) for k, v in obj.items()}
|
|
71
|
+
|
|
72
|
+
elif isinstance(obj, list):
|
|
73
|
+
# Recursively process all items in the list
|
|
74
|
+
return [_deep_parse_json_strings(item, depth + 1, max_depth) for item in obj]
|
|
75
|
+
|
|
76
|
+
else:
|
|
77
|
+
# For all other types (int, float, bool, None, etc.), return as-is
|
|
78
|
+
return obj
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _convert_to_serializable(obj: Any, depth: int = 0, max_depth: int = 20) -> Any:
|
|
82
|
+
"""Convert protobuf and other non-serializable types to JSON-serializable Python types.
|
|
83
|
+
|
|
84
|
+
GEMINI MAPCOMPOSITE FIX (Dec 2025):
|
|
85
|
+
Gemini API returns proto.marshal.collections.maps.MapComposite objects
|
|
86
|
+
which are not JSON serializable. This function recursively converts them
|
|
87
|
+
to regular Python dicts/lists.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
obj: The object to convert
|
|
91
|
+
depth: Current recursion depth
|
|
92
|
+
max_depth: Maximum recursion depth to prevent infinite loops
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
JSON-serializable Python object
|
|
96
|
+
"""
|
|
97
|
+
if depth > max_depth:
|
|
98
|
+
logger.warning(f"[SERIALIZABLE] Max depth {max_depth} reached, converting to str")
|
|
99
|
+
return str(obj)
|
|
100
|
+
|
|
101
|
+
# Handle None
|
|
102
|
+
if obj is None:
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
# Handle primitives
|
|
106
|
+
if isinstance(obj, (str, int, float, bool)):
|
|
107
|
+
return obj
|
|
108
|
+
|
|
109
|
+
# Handle regular dict
|
|
110
|
+
if isinstance(obj, dict):
|
|
111
|
+
return {str(k): _convert_to_serializable(v, depth + 1, max_depth) for k, v in obj.items()}
|
|
112
|
+
|
|
113
|
+
# Handle regular list/tuple
|
|
114
|
+
if isinstance(obj, (list, tuple)):
|
|
115
|
+
return [_convert_to_serializable(item, depth + 1, max_depth) for item in obj]
|
|
116
|
+
|
|
117
|
+
# Handle protobuf MapComposite and similar map-like objects
|
|
118
|
+
# Check for proto.marshal types by checking class name (avoid import dependency)
|
|
119
|
+
obj_class_name = obj.__class__.__name__
|
|
120
|
+
obj_module = obj.__class__.__module__ if hasattr(obj.__class__, '__module__') else ''
|
|
121
|
+
|
|
122
|
+
if 'MapComposite' in obj_class_name or 'proto.marshal' in obj_module:
|
|
123
|
+
# Convert MapComposite to dict
|
|
124
|
+
try:
|
|
125
|
+
return {str(k): _convert_to_serializable(v, depth + 1, max_depth) for k, v in obj.items()}
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.warning(f"[SERIALIZABLE] Failed to convert {obj_class_name}: {e}")
|
|
128
|
+
return str(obj)
|
|
129
|
+
|
|
130
|
+
if 'RepeatedComposite' in obj_class_name or ('proto.marshal' in obj_module and hasattr(obj, '__iter__')):
|
|
131
|
+
# Convert RepeatedComposite to list
|
|
132
|
+
try:
|
|
133
|
+
return [_convert_to_serializable(item, depth + 1, max_depth) for item in obj]
|
|
134
|
+
except Exception as e:
|
|
135
|
+
logger.warning(f"[SERIALIZABLE] Failed to convert {obj_class_name}: {e}")
|
|
136
|
+
return str(obj)
|
|
137
|
+
|
|
138
|
+
# Handle objects with .items() method (dict-like)
|
|
139
|
+
if hasattr(obj, 'items') and callable(obj.items):
|
|
140
|
+
try:
|
|
141
|
+
return {str(k): _convert_to_serializable(v, depth + 1, max_depth) for k, v in obj.items()}
|
|
142
|
+
except Exception:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
# Handle objects with __iter__ (list-like) but not strings
|
|
146
|
+
if hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes)):
|
|
147
|
+
try:
|
|
148
|
+
return [_convert_to_serializable(item, depth + 1, max_depth) for item in obj]
|
|
149
|
+
except Exception:
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
# Fallback: convert to string
|
|
153
|
+
try:
|
|
154
|
+
return str(obj)
|
|
155
|
+
except Exception:
|
|
156
|
+
return f"<non-serializable: {obj_class_name}>"
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# Native message types
|
|
160
|
+
from modules.llm.messages import (
|
|
161
|
+
AIMessage,
|
|
162
|
+
BaseMessage,
|
|
163
|
+
HumanMessage,
|
|
164
|
+
SystemMessage,
|
|
165
|
+
ToolMessage,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# Import constants from centralized location
|
|
169
|
+
from agents.task.constants import (
|
|
170
|
+
TOOL_LOOKAHEAD_WINDOW
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@dataclass
|
|
175
|
+
class StandardToolCall:
|
|
176
|
+
"""Standardized tool call structure compatible with OpenAI tool-call schemas.
|
|
177
|
+
|
|
178
|
+
This ensures consistency across all tool call creation and validation.
|
|
179
|
+
"""
|
|
180
|
+
name: str # Tool/function name
|
|
181
|
+
args: Dict[str, Any] # Arguments as dict
|
|
182
|
+
id: str = field(default_factory=lambda: str(uuid4())) # Unique ID
|
|
183
|
+
type: str = "function" # Standard type for OpenAI tool-call compatibility
|
|
184
|
+
|
|
185
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
186
|
+
"""Convert to standard dict format for AIMessage.tool_calls"""
|
|
187
|
+
return {
|
|
188
|
+
"name": self.name,
|
|
189
|
+
"args": self.args,
|
|
190
|
+
"id": self.id,
|
|
191
|
+
"type": self.type
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
def to_openai_format(self) -> Dict[str, Any]:
|
|
195
|
+
"""Convert to OpenAI tool call format for AIMessage.tool_calls"""
|
|
196
|
+
return {
|
|
197
|
+
"name": self.name,
|
|
198
|
+
"args": self.args,
|
|
199
|
+
"id": self.id,
|
|
200
|
+
"type": self.type
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class ToolCallBuilder:
|
|
205
|
+
"""Builder for creating standardized tool calls.
|
|
206
|
+
|
|
207
|
+
RESPONSIBILITY CONTRACT:
|
|
208
|
+
- ToolCallBuilder.normalize_tool_call: Handles provider-specific tool_call format differences ONLY
|
|
209
|
+
(OpenAI function nesting, IDs, arguments JSON parsing)
|
|
210
|
+
- utils_json.normalize_action_schema: Handles action payload field name transformations ONLY
|
|
211
|
+
(done.text, write_file.file_path, etc.)
|
|
212
|
+
|
|
213
|
+
These are separate concerns and should NOT have overlapping logic.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
@staticmethod
|
|
217
|
+
def create_agent_output_call(agent_output: Any, tool_id: Optional[Union[str, int]] = None) -> StandardToolCall:
|
|
218
|
+
"""Create a tool call for AgentOutput.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
agent_output: The AgentOutput object to convert
|
|
222
|
+
tool_id: Optional specific ID to use
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
StandardToolCall object
|
|
226
|
+
"""
|
|
227
|
+
if tool_id is None:
|
|
228
|
+
tool_id = str(uuid4())
|
|
229
|
+
else:
|
|
230
|
+
tool_id = str(tool_id)
|
|
231
|
+
|
|
232
|
+
# Handle model dumping if available
|
|
233
|
+
if hasattr(agent_output, 'model_dump'):
|
|
234
|
+
args = agent_output.model_dump(mode='json', exclude_unset=True)
|
|
235
|
+
elif hasattr(agent_output, 'dict'):
|
|
236
|
+
args = agent_output.dict(exclude_unset=True)
|
|
237
|
+
else:
|
|
238
|
+
args = {"data": str(agent_output)}
|
|
239
|
+
|
|
240
|
+
return StandardToolCall(
|
|
241
|
+
name="AgentOutput",
|
|
242
|
+
args=args,
|
|
243
|
+
id=tool_id,
|
|
244
|
+
type="function"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
@staticmethod
|
|
248
|
+
def create_tool_call(name: str, args: Dict[str, Any], tool_id: Optional[str] = None) -> StandardToolCall:
|
|
249
|
+
"""Create a generic tool call.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
name: Tool/function name
|
|
253
|
+
args: Arguments dictionary
|
|
254
|
+
tool_id: Optional specific ID to use
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
StandardToolCall object
|
|
258
|
+
"""
|
|
259
|
+
if tool_id is None:
|
|
260
|
+
tool_id = str(uuid4())
|
|
261
|
+
|
|
262
|
+
return StandardToolCall(
|
|
263
|
+
name=name,
|
|
264
|
+
args=args,
|
|
265
|
+
id=tool_id,
|
|
266
|
+
type="function"
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
@staticmethod
|
|
270
|
+
def build_tool_call_from_action(action: List[Dict[str, Any]], tool_call_id: str = None) -> 'StandardToolCall':
|
|
271
|
+
"""Build a StandardToolCall from an action list.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
action: List of action dictionaries
|
|
275
|
+
tool_call_id: Optional tool call ID (will generate if not provided)
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
StandardToolCall object
|
|
279
|
+
"""
|
|
280
|
+
if not action or not isinstance(action, list) or len(action) == 0:
|
|
281
|
+
# Return a default 'wait' action if no action provided
|
|
282
|
+
return StandardToolCall(
|
|
283
|
+
name="wait",
|
|
284
|
+
args={},
|
|
285
|
+
id=tool_call_id or str(uuid4()),
|
|
286
|
+
type="function"
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# Take the first action (AutoV2 typically sends one action at a time)
|
|
290
|
+
first_action = action[0]
|
|
291
|
+
|
|
292
|
+
if not isinstance(first_action, dict) or len(first_action) == 0:
|
|
293
|
+
return StandardToolCall(
|
|
294
|
+
name="wait",
|
|
295
|
+
args={},
|
|
296
|
+
id=tool_call_id or str(uuid4()),
|
|
297
|
+
type="function"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
# Extract action name and args
|
|
301
|
+
action_name = list(first_action.keys())[0]
|
|
302
|
+
action_args = first_action[action_name]
|
|
303
|
+
|
|
304
|
+
# Ensure args is a dict
|
|
305
|
+
if not isinstance(action_args, dict):
|
|
306
|
+
action_args = {"value": action_args} if action_args else {}
|
|
307
|
+
|
|
308
|
+
return StandardToolCall(
|
|
309
|
+
name=action_name,
|
|
310
|
+
args=action_args,
|
|
311
|
+
id=tool_call_id or str(uuid4()),
|
|
312
|
+
type="function"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
@staticmethod
|
|
316
|
+
def validate_tool_call(tool_call: Dict[str, Any]) -> bool:
|
|
317
|
+
"""Validate if a tool call has the required structure.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
tool_call: Tool call dict to validate
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
True if valid, False otherwise
|
|
324
|
+
"""
|
|
325
|
+
required_fields = {"name", "id"}
|
|
326
|
+
optional_fields = {"args", "type"}
|
|
327
|
+
|
|
328
|
+
# Check required fields
|
|
329
|
+
if not all(field in tool_call for field in required_fields):
|
|
330
|
+
missing = required_fields - set(tool_call.keys())
|
|
331
|
+
logger.warning(f"Tool call missing required fields: {missing}")
|
|
332
|
+
return False
|
|
333
|
+
|
|
334
|
+
# Validate types
|
|
335
|
+
if not isinstance(tool_call.get("name"), str):
|
|
336
|
+
logger.warning(f"Tool call 'name' must be string, got {type(tool_call.get('name'))}")
|
|
337
|
+
return False
|
|
338
|
+
|
|
339
|
+
if not isinstance(tool_call.get("id"), str):
|
|
340
|
+
logger.warning(f"Tool call 'id' must be string, got {type(tool_call.get('id'))}")
|
|
341
|
+
return False
|
|
342
|
+
|
|
343
|
+
# Validate args if present
|
|
344
|
+
if "args" in tool_call:
|
|
345
|
+
if not isinstance(tool_call["args"], dict):
|
|
346
|
+
# Check if it's a JSON string (OpenAI format)
|
|
347
|
+
if isinstance(tool_call["args"], str):
|
|
348
|
+
try:
|
|
349
|
+
json.loads(tool_call["args"])
|
|
350
|
+
except json.JSONDecodeError:
|
|
351
|
+
logger.warning(f"Tool call 'args' is not valid JSON: {tool_call['args']}")
|
|
352
|
+
return False
|
|
353
|
+
else:
|
|
354
|
+
logger.warning(f"Tool call 'args' must be dict or JSON string, got {type(tool_call['args'])}")
|
|
355
|
+
return False
|
|
356
|
+
|
|
357
|
+
return True
|
|
358
|
+
|
|
359
|
+
@staticmethod
|
|
360
|
+
def normalize_and_correct(tool_call: Any, provider: str = None, llm_content: str = None) -> Dict[str, Any]:
|
|
361
|
+
"""Normalize and correct tool call in a single pass.
|
|
362
|
+
|
|
363
|
+
This combines format normalization and field corrections for optimal performance.
|
|
364
|
+
|
|
365
|
+
Handles:
|
|
366
|
+
- OpenAI format (nested 'function' field)
|
|
367
|
+
- Anthropic format (direct fields)
|
|
368
|
+
- Flat format (direct fields with args)
|
|
369
|
+
- Object-based formats (using getattr)
|
|
370
|
+
- JSON string arguments
|
|
371
|
+
- Field name corrections (file_name → file_path, message → text, etc.)
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
tool_call: Tool call in any supported format (dict or object)
|
|
375
|
+
provider: Optional provider name for provider-specific handling
|
|
376
|
+
llm_content: Unused, kept for API compatibility
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
Normalized and corrected tool call dict with fields: name, args, id, type
|
|
380
|
+
"""
|
|
381
|
+
# Step 1: Normalize format (existing logic)
|
|
382
|
+
normalized = ToolCallBuilder.normalize_tool_call(tool_call)
|
|
383
|
+
|
|
384
|
+
# Step 2: Apply field corrections immediately
|
|
385
|
+
from agents.task.utils_json import apply_action_field_corrections
|
|
386
|
+
|
|
387
|
+
tool_name = normalized['name']
|
|
388
|
+
corrected_args = apply_action_field_corrections(tool_name, normalized['args'])
|
|
389
|
+
normalized['args'] = corrected_args
|
|
390
|
+
|
|
391
|
+
return normalized
|
|
392
|
+
|
|
393
|
+
@staticmethod
|
|
394
|
+
def normalize_tool_call(tool_call: Any) -> Dict[str, Any]:
|
|
395
|
+
"""Normalize a tool call to standard format - FORMAT ONLY.
|
|
396
|
+
|
|
397
|
+
SINGULAR RESPONSIBILITY: Handle provider format differences ONLY.
|
|
398
|
+
Does NOT apply field corrections - use normalize_and_correct() for that.
|
|
399
|
+
|
|
400
|
+
Handles:
|
|
401
|
+
- OpenAI format (nested 'function' field)
|
|
402
|
+
- Anthropic format (direct fields)
|
|
403
|
+
- Flat format (direct fields with args)
|
|
404
|
+
- Object-based formats (using getattr)
|
|
405
|
+
- JSON string arguments
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
tool_call: Tool call in any supported format (dict or object)
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Normalized tool call dict with guaranteed fields: name, args, id, type
|
|
412
|
+
"""
|
|
413
|
+
try:
|
|
414
|
+
# Initialize with safe defaults
|
|
415
|
+
normalized = {
|
|
416
|
+
"name": "unknown",
|
|
417
|
+
"args": {},
|
|
418
|
+
"id": str(uuid4()),
|
|
419
|
+
"type": "function"
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
# Handle object formats (convert to dict first)
|
|
423
|
+
if not isinstance(tool_call, dict):
|
|
424
|
+
# Try to extract fields from object
|
|
425
|
+
tool_dict = {}
|
|
426
|
+
|
|
427
|
+
# Check for OpenAI-style nested function
|
|
428
|
+
if hasattr(tool_call, 'function'):
|
|
429
|
+
func = tool_call.function
|
|
430
|
+
tool_dict['function'] = {
|
|
431
|
+
'name': getattr(func, 'name', 'unknown'),
|
|
432
|
+
'arguments': getattr(func, 'arguments', '{}')
|
|
433
|
+
}
|
|
434
|
+
tool_dict['id'] = getattr(tool_call, 'id', str(uuid4()))
|
|
435
|
+
else:
|
|
436
|
+
# Direct attributes
|
|
437
|
+
tool_dict['name'] = getattr(tool_call, 'name', 'unknown')
|
|
438
|
+
tool_dict['args'] = getattr(tool_call, 'args', getattr(tool_call, 'arguments', {}))
|
|
439
|
+
tool_dict['id'] = getattr(tool_call, 'id', str(uuid4()))
|
|
440
|
+
tool_dict['type'] = getattr(tool_call, 'type', 'function')
|
|
441
|
+
|
|
442
|
+
tool_call = tool_dict
|
|
443
|
+
|
|
444
|
+
# Now handle dict format
|
|
445
|
+
if "function" in tool_call and isinstance(tool_call.get("function"), dict):
|
|
446
|
+
# OpenAI format with nested 'function'
|
|
447
|
+
func = tool_call["function"]
|
|
448
|
+
normalized["name"] = func.get("name", "unknown")
|
|
449
|
+
|
|
450
|
+
# Parse arguments if they're a JSON string
|
|
451
|
+
args = func.get("arguments", {})
|
|
452
|
+
logger.info(f"[NORMALIZE_TOOL_CALL] {normalized['name']}: raw args type={type(args).__name__}, value={str(args)[:300]}")
|
|
453
|
+
|
|
454
|
+
if isinstance(args, str):
|
|
455
|
+
try:
|
|
456
|
+
parsed_args = json.loads(args) if args else {}
|
|
457
|
+
# GROK 4.1 FIX: Deep parse to handle nested JSON strings
|
|
458
|
+
parsed_args = _deep_parse_json_strings(parsed_args)
|
|
459
|
+
logger.info(f"[NORMALIZE_TOOL_CALL] {normalized['name']}: parsed args (deep)={parsed_args}")
|
|
460
|
+
normalized["args"] = parsed_args
|
|
461
|
+
except (json.JSONDecodeError, ValueError) as e:
|
|
462
|
+
logger.warning(f"Failed to parse JSON arguments: {e}. Using raw string.")
|
|
463
|
+
normalized["args"] = {"raw": args}
|
|
464
|
+
else:
|
|
465
|
+
# Already a dict (native Anthropic/OpenAI path). Convert protobuf
|
|
466
|
+
# types (Gemini MapComposite) to serializable Python. Do NOT
|
|
467
|
+
# deep-parse string VALUES here: a legit string arg that merely
|
|
468
|
+
# looks like JSON (e.g. write_file content='{"k":"v"}') would be
|
|
469
|
+
# turned into a dict and then fail str-field validation, silently
|
|
470
|
+
# dropping the action. (Deep-parse stays on the string-args path
|
|
471
|
+
# above, where the whole blob was JSON — the real Grok case.)
|
|
472
|
+
normalized["args"] = _convert_to_serializable(args or {})
|
|
473
|
+
|
|
474
|
+
normalized["id"] = tool_call.get("id", str(uuid4()))
|
|
475
|
+
else:
|
|
476
|
+
# Direct format (Anthropic, etc.)
|
|
477
|
+
normalized["name"] = tool_call.get("name", "unknown")
|
|
478
|
+
|
|
479
|
+
# Handle various argument field names
|
|
480
|
+
args = tool_call.get("args") or tool_call.get("arguments") or tool_call.get("input", {})
|
|
481
|
+
|
|
482
|
+
# Parse if string
|
|
483
|
+
if isinstance(args, str):
|
|
484
|
+
try:
|
|
485
|
+
parsed_args = json.loads(args) if args else {}
|
|
486
|
+
# GROK 4.1 FIX: Deep parse to handle nested JSON strings
|
|
487
|
+
normalized["args"] = _deep_parse_json_strings(parsed_args)
|
|
488
|
+
except (json.JSONDecodeError, ValueError) as e:
|
|
489
|
+
logger.warning(f"Failed to parse JSON arguments: {e}. Using raw string.")
|
|
490
|
+
normalized["args"] = {"raw": args}
|
|
491
|
+
else:
|
|
492
|
+
# Already a dict (native path). Convert protobuf types to
|
|
493
|
+
# serializable Python. Do NOT deep-parse string VALUES here — a
|
|
494
|
+
# legit JSON-looking string arg would be corrupted into a dict/list
|
|
495
|
+
# and fail str-field validation. (See the OpenAI branch above.)
|
|
496
|
+
normalized["args"] = _convert_to_serializable(args or {})
|
|
497
|
+
|
|
498
|
+
normalized["id"] = tool_call.get("id", str(uuid4()))
|
|
499
|
+
normalized["type"] = tool_call.get("type", "function")
|
|
500
|
+
|
|
501
|
+
# Validate the normalized result
|
|
502
|
+
if not normalized["name"] or normalized["name"] == "unknown":
|
|
503
|
+
logger.warning(f"Tool call missing name: {tool_call}")
|
|
504
|
+
# Fall back to a safe default name
|
|
505
|
+
normalized["name"] = "error_unknown_tool"
|
|
506
|
+
|
|
507
|
+
# Ensure name is never empty (Anthropic rejects empty names)
|
|
508
|
+
if not normalized["name"] or not normalized["name"].strip():
|
|
509
|
+
logger.error(f"Tool call has empty name, using fallback: {tool_call}")
|
|
510
|
+
normalized["name"] = "error_empty_name"
|
|
511
|
+
|
|
512
|
+
# Ensure args is always a dict
|
|
513
|
+
if not isinstance(normalized["args"], dict):
|
|
514
|
+
logger.warning(f"Converting non-dict args to dict: {type(normalized['args'])}")
|
|
515
|
+
normalized["args"] = {"value": normalized["args"]}
|
|
516
|
+
|
|
517
|
+
return normalized
|
|
518
|
+
|
|
519
|
+
except Exception as e:
|
|
520
|
+
logger.error(f"Failed to normalize tool call: {e}. Input: {tool_call}")
|
|
521
|
+
# Return a safe fallback
|
|
522
|
+
return {
|
|
523
|
+
"name": "error",
|
|
524
|
+
"args": {"error": str(e), "original": str(tool_call)[:200]},
|
|
525
|
+
"id": str(uuid4()),
|
|
526
|
+
"type": "function"
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
# --- Backward-compat re-exports (P9) -------------------------------------------
|
|
532
|
+
# Message-sequence repair/validation moved to tool_message_repair.py; keep these
|
|
533
|
+
# importable from here (filters.py, service.py, modules/llm/openai_client.py).
|
|
534
|
+
from agents.task.agent.message_manager.tool_message_repair import ( # noqa: E402
|
|
535
|
+
detect_and_remove_duplicate_tool_calls,
|
|
536
|
+
repair_tool_message_pairs,
|
|
537
|
+
validate_tool_message_pairs,
|
|
538
|
+
repair_and_normalize,
|
|
539
|
+
)
|