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,309 @@
|
|
|
1
|
+
"""Message-builder mixin (roadmap P9; code-motion from message_manager/service.py).
|
|
2
|
+
|
|
3
|
+
Builders for the typed messages that go into history — state, model-output,
|
|
4
|
+
tool-response, and the atomic tool-call pair. Split out so MessageManager's
|
|
5
|
+
service.py trends toward orchestration + storage primitives. MessageManager
|
|
6
|
+
composes MessageBuildersMixin; call sites unchanged via MRO.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
from agents.task.agent.views import AgentBrain, AgentOutput
|
|
14
|
+
from modules.llm.messages import AIMessage, ToolMessage
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MessageBuildersMixin:
|
|
18
|
+
"""Typed-message builders for MessageManager."""
|
|
19
|
+
|
|
20
|
+
def add_state_message(
|
|
21
|
+
self,
|
|
22
|
+
state: BrowserState,
|
|
23
|
+
result: Optional[List[ActionResult]] = None,
|
|
24
|
+
step_info: Optional[AgentStepInfo] = None,
|
|
25
|
+
use_vision=True,
|
|
26
|
+
previous_brain: Optional['AgentBrain'] = None,
|
|
27
|
+
include_browser_state: bool = True, # NEW: Toggle browser context
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Add a message with the current state (browser optional).
|
|
30
|
+
|
|
31
|
+
FIX (Jan 2026): Browser state is now conditional to prevent context
|
|
32
|
+
bleeding into non-browser tasks. Saves ~330 tokens/step.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
state: BrowserState object (may be minimal for non-browser tasks)
|
|
36
|
+
result: Action results from previous step
|
|
37
|
+
step_info: Current step information
|
|
38
|
+
use_vision: Whether to include screenshot
|
|
39
|
+
previous_brain: Previous step's brain state for memory continuity
|
|
40
|
+
include_browser_state: Whether to include browser URL/tabs/elements
|
|
41
|
+
"""
|
|
42
|
+
# Import locally to avoid circular dependency
|
|
43
|
+
from agents.task.agent.prompts import AgentMessagePrompt
|
|
44
|
+
message = AgentMessagePrompt(
|
|
45
|
+
state=state,
|
|
46
|
+
result=result,
|
|
47
|
+
include_attributes=self.include_attributes,
|
|
48
|
+
max_error_length=self.max_error_length,
|
|
49
|
+
step_info=step_info,
|
|
50
|
+
previous_brain=previous_brain,
|
|
51
|
+
include_browser_state=include_browser_state, # Pass browser flag
|
|
52
|
+
).get_user_message(use_vision=use_vision)
|
|
53
|
+
|
|
54
|
+
# CX-H1: tag the constructed state message so removal can target it by
|
|
55
|
+
# identity, not by guessing its content shape (a plain-string minimal
|
|
56
|
+
# state message and a user's multimodal image turn are otherwise
|
|
57
|
+
# indistinguishable to a shape-based scan).
|
|
58
|
+
message.metadata = {**(getattr(message, "metadata", None) or {}), "state_message": True}
|
|
59
|
+
|
|
60
|
+
self._add_message_with_tokens(message)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def add_model_output(self, model_output: AgentOutput, tool_calls: Optional[List[Dict]] = None, llm_content: Optional[str] = None) -> Optional[str]:
|
|
64
|
+
"""Add model output as AI message.
|
|
65
|
+
|
|
66
|
+
SINGULAR RESPONSIBILITY: Add AIMessage exactly once after LLM returns.
|
|
67
|
+
|
|
68
|
+
FLOW:
|
|
69
|
+
1. LLM returns → add_model_output() called ONCE
|
|
70
|
+
2. AIMessage created with tool_calls
|
|
71
|
+
3. Actions execute
|
|
72
|
+
4. Tool responses added via add_tool_response()
|
|
73
|
+
|
|
74
|
+
NO DUPLICATE CHECKS - caller ensures single call.
|
|
75
|
+
NO FALLBACKS - caller provides correct data.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
model_output: The agent's output containing actions
|
|
79
|
+
tool_calls: Native tool calls from the LLM response (for native tools)
|
|
80
|
+
llm_content: Text content from LLM (brain state)
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
tool_call_id for the ToolMessage after execution
|
|
84
|
+
"""
|
|
85
|
+
if self.use_native_tools and tool_calls:
|
|
86
|
+
# ✅ FIX: Validate content before fallback
|
|
87
|
+
content = llm_content
|
|
88
|
+
|
|
89
|
+
if not content or not content.strip():
|
|
90
|
+
self.logger.debug(
|
|
91
|
+
f"[NATIVE_TOOLS] LLM returned tool calls without content (expected in native tool mode). "
|
|
92
|
+
f"Tool calls: {[tc.get('name') for tc in tool_calls[:3]]}{'...' if len(tool_calls) > 3 else ''}"
|
|
93
|
+
)
|
|
94
|
+
content = "Executing actions"
|
|
95
|
+
else:
|
|
96
|
+
self.logger.debug(f"[NATIVE_TOOLS] AI message has content: {content[:100]}...")
|
|
97
|
+
|
|
98
|
+
msg = AIMessage(content=content, tool_calls=tool_calls)
|
|
99
|
+
self.logger.debug(f"[NATIVE_TOOLS] Adding AI message with {len(tool_calls)} tool_calls")
|
|
100
|
+
|
|
101
|
+
self._add_message_with_tokens(msg, _internal=True)
|
|
102
|
+
|
|
103
|
+
# Tool calls should already be registered by Agent
|
|
104
|
+
# Validate they exist in tracker
|
|
105
|
+
if self.tool_call_tracker:
|
|
106
|
+
for tc in tool_calls:
|
|
107
|
+
if not self.tool_call_tracker.has_call(tc.get('id')):
|
|
108
|
+
self.logger.error(
|
|
109
|
+
f"Tool call {tc.get('id')} ({tc.get('name')}) not registered in tracker. "
|
|
110
|
+
f"Agent should register tool calls before calling add_model_output."
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
return tool_calls[0].get('id') if tool_calls else None
|
|
114
|
+
|
|
115
|
+
# Note: Synthetic tool call creation for non-native tools is handled by Agent using ToolCallBuilder
|
|
116
|
+
|
|
117
|
+
# For native tools or if synthetic build failed
|
|
118
|
+
# Add minimal content to AI message to prevent empty steps
|
|
119
|
+
action_summary = "Planning actions"
|
|
120
|
+
if model_output and hasattr(model_output, 'action'):
|
|
121
|
+
try:
|
|
122
|
+
# Render a compact preview of actions without dumping full structure
|
|
123
|
+
action_summary = "Actions planned"
|
|
124
|
+
except Exception:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
msg = AIMessage(
|
|
128
|
+
content=action_summary,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
self.logger.debug("Adding AI message without tool_calls")
|
|
132
|
+
self._add_message_with_tokens(msg, _internal=True)
|
|
133
|
+
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
def _add_output_header(self, content: str) -> str:
|
|
137
|
+
"""Add metadata header to tool outputs for visibility (OPTIMIZATION: Task 2 - Nov 14, 2025)"""
|
|
138
|
+
try:
|
|
139
|
+
import json
|
|
140
|
+
parsed = json.loads(content)
|
|
141
|
+
|
|
142
|
+
if isinstance(parsed, list):
|
|
143
|
+
# Make count OBVIOUS
|
|
144
|
+
return f"[TOOL OUTPUT - List with {len(parsed)} items]\n\n{content}"
|
|
145
|
+
|
|
146
|
+
elif isinstance(parsed, dict):
|
|
147
|
+
keys = list(parsed.keys())[:5]
|
|
148
|
+
more = f" (+{len(parsed)-5} more)" if len(parsed) > 5 else ""
|
|
149
|
+
return f"[TOOL OUTPUT - Dict with keys: {', '.join(keys)}{more}]\n\n{content}"
|
|
150
|
+
|
|
151
|
+
except (json.JSONDecodeError, TypeError):
|
|
152
|
+
pass # Content is not JSON - return as-is below
|
|
153
|
+
|
|
154
|
+
# For large text, show length
|
|
155
|
+
if isinstance(content, str) and len(content) > 100:
|
|
156
|
+
return f"[TOOL OUTPUT - Text, {len(content)} chars]\n\n{content}"
|
|
157
|
+
|
|
158
|
+
return content
|
|
159
|
+
|
|
160
|
+
def add_tool_response(self, tool_call_id: str, content: str = 'Action completed') -> None:
|
|
161
|
+
"""Add tool response message after action execution.
|
|
162
|
+
|
|
163
|
+
If no tool_call_id is provided (native tool call not used), degrade to a
|
|
164
|
+
plain assistant message so providers that don't expect tool role messages
|
|
165
|
+
won't receive invalid sequences.
|
|
166
|
+
|
|
167
|
+
P0 FIX: Ensures AI message with tool_calls is present before adding tool response.
|
|
168
|
+
Buffers tool responses if AI message not yet present.
|
|
169
|
+
"""
|
|
170
|
+
if tool_call_id:
|
|
171
|
+
# CRITICAL FIX (P0): Ensure AI message with tool_calls exists before adding tool response
|
|
172
|
+
# This prevents orphan tool responses that cause message sequence errors
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# SIMPLIFIED VALIDATION: Use ToolCallTracker as single source of truth
|
|
176
|
+
if tool_call_id and self.tool_call_tracker:
|
|
177
|
+
if not self.tool_call_tracker.has_call(tool_call_id):
|
|
178
|
+
self.logger.warning(f"Tool response for {tool_call_id} has no matching call in tracker")
|
|
179
|
+
|
|
180
|
+
# Track tool response if tracker is available
|
|
181
|
+
if self.tool_call_tracker:
|
|
182
|
+
self.tool_call_tracker.complete_call(
|
|
183
|
+
call_id=tool_call_id,
|
|
184
|
+
result=content
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# MINIMAL FIX (Nov 4, 2025): Remove ALL truncation to stop file-reading loops
|
|
188
|
+
# Problem: ANY truncation causes loops - agent reads file → truncated → reads again
|
|
189
|
+
# Solution: NO TRUNCATION. Let context window handle it (we have 1M tokens available)
|
|
190
|
+
#
|
|
191
|
+
# With gpt-5 (1M context), we can fit:
|
|
192
|
+
# - 200K chars = ~50K tokens = 4.8% of context
|
|
193
|
+
# - 500K chars = ~125K tokens = 12% of context
|
|
194
|
+
# Current usage: ~6.6K tokens = 0.63% of context
|
|
195
|
+
#
|
|
196
|
+
# PLENTY OF ROOM - don't truncate!
|
|
197
|
+
|
|
198
|
+
# OPTIMIZATION: Enhance content with metadata header (Task 2 - Nov 14, 2025)
|
|
199
|
+
enhanced_content = self._add_output_header(content)
|
|
200
|
+
|
|
201
|
+
# Minimal logging for very large content (>100K chars)
|
|
202
|
+
if len(content) > 100000:
|
|
203
|
+
self.logger.info(
|
|
204
|
+
f"Large tool result: {len(content):,} chars (~{len(content)//4:,} tokens) - "
|
|
205
|
+
f"NO TRUNCATION (context has room)"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
tool_message = ToolMessage(
|
|
209
|
+
content=enhanced_content,
|
|
210
|
+
tool_call_id=tool_call_id,
|
|
211
|
+
)
|
|
212
|
+
self.logger.debug(f"Adding tool message response with tool_call_id: {tool_call_id}")
|
|
213
|
+
|
|
214
|
+
# Validate that this is a real response (not a placeholder)
|
|
215
|
+
if not content or content == "Action completed":
|
|
216
|
+
self.logger.warning(f"Tool response may be generic/empty for {tool_call_id}: {content[:100]}")
|
|
217
|
+
|
|
218
|
+
# Add the ToolMessage to history with internal flag
|
|
219
|
+
self._add_message_with_tokens(tool_message, _internal=True)
|
|
220
|
+
return
|
|
221
|
+
|
|
222
|
+
# Fallback: emit an assistant message with the tool result
|
|
223
|
+
self.logger.debug("No tool_call_id provided – emitting assistant message with tool result")
|
|
224
|
+
ai_msg = AIMessage(content=f"Tool result: {content}")
|
|
225
|
+
self._add_message_with_tokens(ai_msg, _internal=True)
|
|
226
|
+
|
|
227
|
+
# === Atomic tool call pair addition ===
|
|
228
|
+
|
|
229
|
+
def add_tool_call_pair_atomic(
|
|
230
|
+
self,
|
|
231
|
+
ai_content: str,
|
|
232
|
+
tool_calls: List[Dict[str, Any]],
|
|
233
|
+
tool_responses: List[Tuple[str, str]]
|
|
234
|
+
) -> None:
|
|
235
|
+
"""Add AIMessage with tool_calls and all ToolMessages atomically.
|
|
236
|
+
|
|
237
|
+
Ensures OpenAI's requirement: AIMessage with tool_calls must be
|
|
238
|
+
immediately followed by ToolMessages for each tool_call_id.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
ai_content: Content for AIMessage
|
|
242
|
+
tool_calls: List of tool call dicts with 'id', 'name', 'args'
|
|
243
|
+
tool_responses: List of (tool_call_id, response_content) tuples
|
|
244
|
+
|
|
245
|
+
Raises:
|
|
246
|
+
ValueError: If tool_call_ids don't match response IDs
|
|
247
|
+
"""
|
|
248
|
+
# Validate all tool_calls have responses
|
|
249
|
+
tc_ids = {tc.get('id') for tc in tool_calls if tc.get('id')}
|
|
250
|
+
resp_ids = {resp[0] for resp in tool_responses}
|
|
251
|
+
|
|
252
|
+
if tc_ids != resp_ids:
|
|
253
|
+
missing = tc_ids - resp_ids
|
|
254
|
+
extra = resp_ids - tc_ids
|
|
255
|
+
raise ValueError(
|
|
256
|
+
f"Tool call/response mismatch. Missing: {missing}, Extra: {extra}"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# SECURITY FIX: Protect entire atomic operation with lock
|
|
260
|
+
# This ensures checkpoint, add, and rollback are all atomic
|
|
261
|
+
with self._history_lock:
|
|
262
|
+
# Create checkpoint for rollback
|
|
263
|
+
checkpoint_idx = len(self.history.messages)
|
|
264
|
+
checkpoint_tokens = self.history.total_tokens
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
# Step 1: Add AIMessage with tool_calls
|
|
268
|
+
ai_msg = AIMessage(content=ai_content, tool_calls=tool_calls)
|
|
269
|
+
self._add_message_with_tokens(ai_msg)
|
|
270
|
+
|
|
271
|
+
# Step 2: Add ALL ToolMessages immediately after (in order)
|
|
272
|
+
tc_order = {tc.get('id'): idx for idx, tc in enumerate(tool_calls)}
|
|
273
|
+
sorted_responses = sorted(
|
|
274
|
+
tool_responses,
|
|
275
|
+
key=lambda x: tc_order.get(x[0], 999)
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
for tc_id, content in sorted_responses:
|
|
279
|
+
tool_msg = ToolMessage(content=content, tool_call_id=tc_id)
|
|
280
|
+
self._add_message_with_tokens(tool_msg)
|
|
281
|
+
|
|
282
|
+
self.logger.info(
|
|
283
|
+
f"✅ Atomic add: AIMessage + {len(tool_responses)} ToolMessages"
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Update tracker if available
|
|
287
|
+
if self.tool_call_tracker:
|
|
288
|
+
for tc_id, content in tool_responses:
|
|
289
|
+
self.tool_call_tracker.complete_call(tc_id, content)
|
|
290
|
+
|
|
291
|
+
except Exception as e:
|
|
292
|
+
# Rollback: remove all messages added since checkpoint
|
|
293
|
+
self.logger.error(f"Error in atomic add: {e}, rolling back")
|
|
294
|
+
|
|
295
|
+
while len(self.history.messages) > checkpoint_idx:
|
|
296
|
+
removed = self.history.messages.pop()
|
|
297
|
+
# Restore token count
|
|
298
|
+
if hasattr(removed, 'metadata') and hasattr(removed.metadata, 'input_tokens'):
|
|
299
|
+
token_delta = removed.metadata.input_tokens
|
|
300
|
+
self.history.total_tokens -= token_delta
|
|
301
|
+
|
|
302
|
+
self.history.total_tokens = checkpoint_tokens
|
|
303
|
+
self.logger.warning("Rolled back atomic addition")
|
|
304
|
+
raise
|
|
305
|
+
|
|
306
|
+
# _ensure_artifacts_in_context removed - todo system handles task tracking
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|