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
api/a2a/streaming.py
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""A2A Streaming - Server-Sent Events for real-time updates.
|
|
2
|
+
|
|
3
|
+
Implements SSE streaming for A2A protocol, enabling real-time
|
|
4
|
+
task status updates and artifact delivery.
|
|
5
|
+
|
|
6
|
+
Supports:
|
|
7
|
+
- message/stream: Initial streaming request
|
|
8
|
+
- tasks/resubscribe: Reconnection after connection loss
|
|
9
|
+
|
|
10
|
+
Reference: https://a2a-protocol.org/latest/topics/streaming-and-async/
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
from typing import AsyncGenerator, Optional
|
|
17
|
+
from fastapi import APIRouter, Request, HTTPException
|
|
18
|
+
from fastapi.responses import StreamingResponse
|
|
19
|
+
|
|
20
|
+
from api.a2a.models import (
|
|
21
|
+
A2ATask, A2ATaskState, A2ATaskStatus, A2AMessage,
|
|
22
|
+
TaskStatusUpdateEvent, TaskArtifactUpdateEvent,
|
|
23
|
+
JSONRPCResponse, SendMessageRequest
|
|
24
|
+
)
|
|
25
|
+
from api.a2a.task_handler import A2ATaskHandler
|
|
26
|
+
from api.dependencies import get_user_permissive
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
router = APIRouter(prefix="/a2a", tags=["a2a-streaming"])
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async def task_event_stream(
|
|
33
|
+
task_id: str,
|
|
34
|
+
handler: A2ATaskHandler,
|
|
35
|
+
history_length: Optional[int] = None
|
|
36
|
+
) -> AsyncGenerator[str, None]:
|
|
37
|
+
"""Generate SSE events for task status changes.
|
|
38
|
+
|
|
39
|
+
Streams TaskStatusUpdateEvent and TaskArtifactUpdateEvent
|
|
40
|
+
until task reaches terminal state.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
task_id: Task/session ID to monitor
|
|
44
|
+
handler: A2A task handler
|
|
45
|
+
history_length: Optional number of events to replay
|
|
46
|
+
|
|
47
|
+
Yields:
|
|
48
|
+
SSE formatted event strings
|
|
49
|
+
"""
|
|
50
|
+
from agents.task.path import pm
|
|
51
|
+
|
|
52
|
+
# Send initial status
|
|
53
|
+
try:
|
|
54
|
+
task = await handler.get_task(task_id, history_length)
|
|
55
|
+
event = TaskStatusUpdateEvent(
|
|
56
|
+
task=task,
|
|
57
|
+
final=A2ATaskState.is_terminal(task.status.state)
|
|
58
|
+
)
|
|
59
|
+
yield _format_sse_event(event)
|
|
60
|
+
|
|
61
|
+
# If already terminal, we're done
|
|
62
|
+
if event.final:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
except Exception as e:
|
|
66
|
+
yield _format_sse_error(str(e))
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
# Get session info for feed directory
|
|
70
|
+
agent = handler._get_task_agent()
|
|
71
|
+
if not agent:
|
|
72
|
+
yield _format_sse_error("TaskAgent not available")
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
session_info = await agent.get_session_by_id(task_id)
|
|
76
|
+
if not session_info:
|
|
77
|
+
yield _format_sse_error(f"Task {task_id} not found")
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
user_id = session_info.get("user_id")
|
|
81
|
+
feed_dir = pm().get_subdir(task_id, "feed", user_id=user_id)
|
|
82
|
+
|
|
83
|
+
# Track seen files to avoid duplicates
|
|
84
|
+
seen_files = set()
|
|
85
|
+
terminal_states = {"completed", "failed", "cancelled", "error"}
|
|
86
|
+
last_status = None
|
|
87
|
+
|
|
88
|
+
# Poll for updates
|
|
89
|
+
while True:
|
|
90
|
+
try:
|
|
91
|
+
# Check for new feed files
|
|
92
|
+
if feed_dir and feed_dir.exists():
|
|
93
|
+
for event_file in sorted(feed_dir.glob("*.json")):
|
|
94
|
+
if event_file.name in seen_files:
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
seen_files.add(event_file.name)
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
with open(event_file) as f:
|
|
101
|
+
event_data = json.load(f)
|
|
102
|
+
|
|
103
|
+
# Convert to appropriate event type
|
|
104
|
+
event_type = event_data.get("type", "")
|
|
105
|
+
data = event_data.get("data", {})
|
|
106
|
+
|
|
107
|
+
# Status events
|
|
108
|
+
if event_type == "status":
|
|
109
|
+
new_status = data.get("status", "")
|
|
110
|
+
if new_status != last_status:
|
|
111
|
+
last_status = new_status
|
|
112
|
+
|
|
113
|
+
# Refresh full task status
|
|
114
|
+
task = await handler.get_task(task_id, history_length=0)
|
|
115
|
+
event = TaskStatusUpdateEvent(
|
|
116
|
+
task=task,
|
|
117
|
+
final=A2ATaskState.is_terminal(task.status.state)
|
|
118
|
+
)
|
|
119
|
+
yield _format_sse_event(event)
|
|
120
|
+
|
|
121
|
+
if event.final:
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
# Step/action events as status updates
|
|
125
|
+
elif event_type in ["step", "step_result", "action", "action_result"]:
|
|
126
|
+
# Create intermediate status message
|
|
127
|
+
message_text = _extract_event_text(event_type, data)
|
|
128
|
+
if message_text:
|
|
129
|
+
task = await handler.get_task(task_id, history_length=0)
|
|
130
|
+
task.status.message = A2AMessage(
|
|
131
|
+
role="agent",
|
|
132
|
+
parts=[{"kind": "text", "text": message_text}]
|
|
133
|
+
)
|
|
134
|
+
event = TaskStatusUpdateEvent(task=task, final=False)
|
|
135
|
+
yield _format_sse_event(event)
|
|
136
|
+
|
|
137
|
+
# Artifact events
|
|
138
|
+
elif event_type in ["file_created", "artifact"]:
|
|
139
|
+
artifact_event = _build_artifact_event(task_id, data)
|
|
140
|
+
if artifact_event:
|
|
141
|
+
yield _format_sse_event(artifact_event, event_type="artifact")
|
|
142
|
+
|
|
143
|
+
except Exception as e:
|
|
144
|
+
logger.warning(f"Error parsing feed file {event_file}: {e}")
|
|
145
|
+
|
|
146
|
+
# Check current session status
|
|
147
|
+
session_info = await agent.get_session_by_id(task_id)
|
|
148
|
+
if session_info:
|
|
149
|
+
current_status = session_info.get("status", "").lower()
|
|
150
|
+
if current_status in terminal_states:
|
|
151
|
+
# Send final event
|
|
152
|
+
task = await handler.get_task(task_id)
|
|
153
|
+
yield _format_sse_event(
|
|
154
|
+
TaskStatusUpdateEvent(task=task, final=True)
|
|
155
|
+
)
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
# Poll interval
|
|
159
|
+
await asyncio.sleep(1)
|
|
160
|
+
|
|
161
|
+
except asyncio.CancelledError:
|
|
162
|
+
logger.info(f"SSE stream cancelled for task {task_id}")
|
|
163
|
+
break
|
|
164
|
+
except Exception as e:
|
|
165
|
+
logger.error(f"Error in SSE stream: {e}")
|
|
166
|
+
yield _format_sse_error(str(e))
|
|
167
|
+
break
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _format_sse_event(
|
|
171
|
+
event_data,
|
|
172
|
+
event_type: str = "message"
|
|
173
|
+
) -> str:
|
|
174
|
+
"""Format data as SSE event string.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
event_data: Event data (Pydantic model or dict)
|
|
178
|
+
event_type: SSE event type
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
SSE formatted string
|
|
182
|
+
"""
|
|
183
|
+
if hasattr(event_data, 'dict'):
|
|
184
|
+
data = event_data.dict()
|
|
185
|
+
else:
|
|
186
|
+
data = event_data
|
|
187
|
+
|
|
188
|
+
# Wrap in JSON-RPC response format
|
|
189
|
+
response = JSONRPCResponse(result=data)
|
|
190
|
+
|
|
191
|
+
return f"event: {event_type}\ndata: {json.dumps(response.dict())}\n\n"
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _format_sse_error(message: str) -> str:
|
|
195
|
+
"""Format error as SSE event string."""
|
|
196
|
+
response = JSONRPCResponse(
|
|
197
|
+
error={"code": -32603, "message": message}
|
|
198
|
+
)
|
|
199
|
+
return f"event: error\ndata: {json.dumps(response.dict())}\n\n"
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _extract_event_text(event_type: str, data: dict) -> Optional[str]:
|
|
203
|
+
"""Extract human-readable text from event data.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
event_type: Type of event
|
|
207
|
+
data: Event data
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
Extracted text or None
|
|
211
|
+
"""
|
|
212
|
+
if event_type == "step":
|
|
213
|
+
return data.get("step_name") or data.get("description")
|
|
214
|
+
elif event_type == "step_result":
|
|
215
|
+
return data.get("result") or data.get("output")
|
|
216
|
+
elif event_type == "action":
|
|
217
|
+
action = data.get("action_type", "")
|
|
218
|
+
return f"Executing: {action}"
|
|
219
|
+
elif event_type == "action_result":
|
|
220
|
+
return data.get("result") or data.get("output")
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _build_artifact_event(
|
|
225
|
+
task_id: str,
|
|
226
|
+
data: dict
|
|
227
|
+
) -> Optional[TaskArtifactUpdateEvent]:
|
|
228
|
+
"""Build artifact update event from feed data.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
task_id: Task ID
|
|
232
|
+
data: Event data with file info
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
TaskArtifactUpdateEvent or None
|
|
236
|
+
"""
|
|
237
|
+
from api.a2a.models import A2AArtifact
|
|
238
|
+
import uuid
|
|
239
|
+
|
|
240
|
+
file_path = data.get("path") or data.get("file_path")
|
|
241
|
+
if not file_path:
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
file_name = data.get("filename") or data.get("name") or file_path.split("/")[-1]
|
|
245
|
+
mime_type = data.get("mime_type", "application/octet-stream")
|
|
246
|
+
|
|
247
|
+
artifact = A2AArtifact(
|
|
248
|
+
artifactId=str(uuid.uuid4()),
|
|
249
|
+
name=file_name,
|
|
250
|
+
parts=[{
|
|
251
|
+
"kind": "file",
|
|
252
|
+
"file": {
|
|
253
|
+
"uri": f"/api/task/sessions/{task_id}/workspace/{file_path}",
|
|
254
|
+
"name": file_name,
|
|
255
|
+
"mimeType": mime_type
|
|
256
|
+
}
|
|
257
|
+
}],
|
|
258
|
+
metadata=data
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
return TaskArtifactUpdateEvent(taskId=task_id, artifact=artifact)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@router.post("/message/stream")
|
|
265
|
+
async def stream_message(
|
|
266
|
+
request_body: SendMessageRequest,
|
|
267
|
+
request: Request
|
|
268
|
+
):
|
|
269
|
+
"""Stream task events for a new or continued task with payment verification.
|
|
270
|
+
|
|
271
|
+
Creates a new task and immediately begins streaming updates.
|
|
272
|
+
Equivalent to message/send but returns SSE stream instead of single response.
|
|
273
|
+
"""
|
|
274
|
+
from core.container import DependencyContainer
|
|
275
|
+
from api.payment_verification import verify_payment_for_request, payment_required_response
|
|
276
|
+
|
|
277
|
+
# Get authenticated user (use user_id set by middleware, not raw payer_address)
|
|
278
|
+
user_id = getattr(request.state, 'user_id', None)
|
|
279
|
+
if not user_id or user_id == 'api_user':
|
|
280
|
+
# Fallback for x402 if middleware didn't set user_id
|
|
281
|
+
if getattr(request.state, 'payment_method', None) == 'x402':
|
|
282
|
+
from core.identity import generate_user_id_from_wallet
|
|
283
|
+
payer_address = getattr(request.state, 'payer_address', None)
|
|
284
|
+
if payer_address:
|
|
285
|
+
user_id = generate_user_id_from_wallet(payer_address)
|
|
286
|
+
if not user_id or user_id == 'api_user':
|
|
287
|
+
raise HTTPException(status_code=401, detail="Authentication required")
|
|
288
|
+
|
|
289
|
+
container = DependencyContainer.get_instance()
|
|
290
|
+
handler = A2ATaskHandler(container)
|
|
291
|
+
|
|
292
|
+
# Check if continuing existing task
|
|
293
|
+
task_id = request_body.message.taskId
|
|
294
|
+
if task_id:
|
|
295
|
+
# Continue existing task - already paid
|
|
296
|
+
await handler.send_message(task_id, request_body.message, user_id)
|
|
297
|
+
else:
|
|
298
|
+
# NEW TASK: Verify payment before creation
|
|
299
|
+
try:
|
|
300
|
+
payment_method, details = await verify_payment_for_request(
|
|
301
|
+
request=request,
|
|
302
|
+
cost_credits=1 # Session creation = 1 credit
|
|
303
|
+
)
|
|
304
|
+
logger.info(f"A2A stream payment verified via {payment_method}")
|
|
305
|
+
except HTTPException as e:
|
|
306
|
+
if e.status_code == 402:
|
|
307
|
+
raise HTTPException(
|
|
308
|
+
status_code=402,
|
|
309
|
+
detail=payment_required_response(request, cost_credits=1)
|
|
310
|
+
)
|
|
311
|
+
raise
|
|
312
|
+
|
|
313
|
+
# Create new task
|
|
314
|
+
task = await handler.create_task(
|
|
315
|
+
request_body,
|
|
316
|
+
user_id,
|
|
317
|
+
request_body.message.contextId
|
|
318
|
+
)
|
|
319
|
+
task_id = task.id
|
|
320
|
+
|
|
321
|
+
# Return streaming response
|
|
322
|
+
return StreamingResponse(
|
|
323
|
+
task_event_stream(task_id, handler),
|
|
324
|
+
media_type="text/event-stream",
|
|
325
|
+
headers={
|
|
326
|
+
"Cache-Control": "no-cache",
|
|
327
|
+
"Connection": "keep-alive",
|
|
328
|
+
"X-Accel-Buffering": "no"
|
|
329
|
+
}
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@router.get("/tasks/{task_id}/stream")
|
|
334
|
+
async def stream_task_events(
|
|
335
|
+
task_id: str,
|
|
336
|
+
historyLength: Optional[int] = None,
|
|
337
|
+
request: Request = None
|
|
338
|
+
):
|
|
339
|
+
"""Stream events for an existing task.
|
|
340
|
+
|
|
341
|
+
Establishes SSE connection for real-time task updates.
|
|
342
|
+
Useful for monitoring long-running tasks.
|
|
343
|
+
"""
|
|
344
|
+
from core.container import DependencyContainer
|
|
345
|
+
|
|
346
|
+
container = DependencyContainer.get_instance()
|
|
347
|
+
handler = A2ATaskHandler(container)
|
|
348
|
+
|
|
349
|
+
# Authenticate and enforce ownership before streaming another tenant's events.
|
|
350
|
+
user_id = await get_user_permissive(request)
|
|
351
|
+
try:
|
|
352
|
+
await handler.get_task(task_id, user_id=user_id)
|
|
353
|
+
except ValueError:
|
|
354
|
+
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
|
|
355
|
+
|
|
356
|
+
return StreamingResponse(
|
|
357
|
+
task_event_stream(task_id, handler, historyLength),
|
|
358
|
+
media_type="text/event-stream",
|
|
359
|
+
headers={
|
|
360
|
+
"Cache-Control": "no-cache",
|
|
361
|
+
"Connection": "keep-alive",
|
|
362
|
+
"X-Accel-Buffering": "no"
|
|
363
|
+
}
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
@router.post("/tasks/resubscribe")
|
|
368
|
+
async def resubscribe_to_task(
|
|
369
|
+
task_id: str,
|
|
370
|
+
historyLength: Optional[int] = None,
|
|
371
|
+
request: Request = None
|
|
372
|
+
):
|
|
373
|
+
"""Resubscribe to task events after connection loss.
|
|
374
|
+
|
|
375
|
+
Re-establishes SSE stream for existing task.
|
|
376
|
+
May replay missed events based on historyLength.
|
|
377
|
+
|
|
378
|
+
This is the A2A protocol's recommended method for
|
|
379
|
+
handling network interruptions.
|
|
380
|
+
"""
|
|
381
|
+
from core.container import DependencyContainer
|
|
382
|
+
|
|
383
|
+
container = DependencyContainer.get_instance()
|
|
384
|
+
handler = A2ATaskHandler(container)
|
|
385
|
+
|
|
386
|
+
# Authenticate and enforce ownership before re-subscribing to task events.
|
|
387
|
+
user_id = await get_user_permissive(request)
|
|
388
|
+
# Verify task exists and is not terminal
|
|
389
|
+
try:
|
|
390
|
+
task = await handler.get_task(task_id, user_id=user_id)
|
|
391
|
+
if A2ATaskState.is_terminal(task.status.state):
|
|
392
|
+
# Return final status immediately
|
|
393
|
+
return StreamingResponse(
|
|
394
|
+
_single_event_stream(task),
|
|
395
|
+
media_type="text/event-stream",
|
|
396
|
+
headers={
|
|
397
|
+
"Cache-Control": "no-cache",
|
|
398
|
+
"Connection": "keep-alive"
|
|
399
|
+
}
|
|
400
|
+
)
|
|
401
|
+
except ValueError:
|
|
402
|
+
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
|
|
403
|
+
|
|
404
|
+
# Return streaming response
|
|
405
|
+
return StreamingResponse(
|
|
406
|
+
task_event_stream(task_id, handler, historyLength),
|
|
407
|
+
media_type="text/event-stream",
|
|
408
|
+
headers={
|
|
409
|
+
"Cache-Control": "no-cache",
|
|
410
|
+
"Connection": "keep-alive",
|
|
411
|
+
"X-Accel-Buffering": "no"
|
|
412
|
+
}
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
async def _single_event_stream(task: A2ATask) -> AsyncGenerator[str, None]:
|
|
417
|
+
"""Generator for single final event (for terminal tasks)."""
|
|
418
|
+
event = TaskStatusUpdateEvent(task=task, final=True)
|
|
419
|
+
yield _format_sse_event(event)
|