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/auth_constants.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Server-side auth constants — re-exports from core.constants.
|
|
2
|
+
|
|
3
|
+
The canonical definitions live in core/constants.py so agent-side code can
|
|
4
|
+
import them without depending on the api/ package. This shim preserves
|
|
5
|
+
existing `from api.auth_constants import ...` call sites.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from core.constants import ( # noqa: F401
|
|
9
|
+
VALID_ROLES,
|
|
10
|
+
ADMIN_ROLES,
|
|
11
|
+
ASSIGNABLE_ROLES,
|
|
12
|
+
MANAGEMENT_ROLES,
|
|
13
|
+
ROLE_MANAGEMENT_ROLES,
|
|
14
|
+
VALID_TIERS,
|
|
15
|
+
FULL_ACCESS_TIERS,
|
|
16
|
+
PAID_TIERS,
|
|
17
|
+
is_admin_role,
|
|
18
|
+
is_admin_wallet,
|
|
19
|
+
is_admin,
|
|
20
|
+
can_manage_users,
|
|
21
|
+
can_change_roles,
|
|
22
|
+
extract_admin_info,
|
|
23
|
+
has_full_access,
|
|
24
|
+
requires_payment,
|
|
25
|
+
validate_role,
|
|
26
|
+
validate_assignable_role,
|
|
27
|
+
validate_tier,
|
|
28
|
+
)
|
api/auth_endpoints.py
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"""Free wallet authentication endpoints using SIWE (Sign-In with Ethereum).
|
|
2
|
+
|
|
3
|
+
Replaces expensive Privy with free industry-standard SIWE.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from fastapi import APIRouter, HTTPException, Depends, Request
|
|
7
|
+
from fastapi.responses import JSONResponse
|
|
8
|
+
from pydantic import BaseModel, field_validator
|
|
9
|
+
import jwt
|
|
10
|
+
from datetime import datetime, timedelta
|
|
11
|
+
import logging
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
from api.auth_constants import is_admin_wallet
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
router = APIRouter(tags=["authentication"])
|
|
19
|
+
|
|
20
|
+
_ADDR_RE = re.compile(r"^0x[0-9a-fA-F]{40}$")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def normalize_eth_address(value: str) -> str:
|
|
24
|
+
"""Validate + EIP-55 checksum-normalize an Ethereum address.
|
|
25
|
+
|
|
26
|
+
Normalizing canonicalizes casing so the same wallet maps to ONE identity
|
|
27
|
+
(the address becomes the JWT sub / user_id / admin-allowlist key downstream).
|
|
28
|
+
Raises ValueError on a malformed address (-> 422 at the request boundary).
|
|
29
|
+
"""
|
|
30
|
+
if not isinstance(value, str) or not _ADDR_RE.match(value.strip()):
|
|
31
|
+
raise ValueError("invalid Ethereum address")
|
|
32
|
+
try:
|
|
33
|
+
from eth_utils import to_checksum_address
|
|
34
|
+
return to_checksum_address(value.strip())
|
|
35
|
+
except Exception:
|
|
36
|
+
# eth_utils missing/odd input: keep validation, skip checksum normalization.
|
|
37
|
+
return value.strip()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class NonceRequest(BaseModel):
|
|
41
|
+
"""Request nonce for wallet authentication."""
|
|
42
|
+
wallet_address: str
|
|
43
|
+
chain_id: int = 1 # Ethereum mainnet by default
|
|
44
|
+
|
|
45
|
+
@field_validator("wallet_address")
|
|
46
|
+
@classmethod
|
|
47
|
+
def _check_addr(cls, v: str) -> str:
|
|
48
|
+
return normalize_eth_address(v)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class NonceResponse(BaseModel):
|
|
52
|
+
"""SIWE message and nonce."""
|
|
53
|
+
message: str
|
|
54
|
+
nonce: str
|
|
55
|
+
issued_at: str
|
|
56
|
+
expiration: str
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class VerifyRequest(BaseModel):
|
|
60
|
+
"""Verify wallet signature."""
|
|
61
|
+
wallet_address: str
|
|
62
|
+
message: str
|
|
63
|
+
signature: str
|
|
64
|
+
nonce: str
|
|
65
|
+
chain: str = 'ethereum'
|
|
66
|
+
|
|
67
|
+
@field_validator("wallet_address")
|
|
68
|
+
@classmethod
|
|
69
|
+
def _check_addr(cls, v: str) -> str:
|
|
70
|
+
return normalize_eth_address(v)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class AuthResponse(BaseModel):
|
|
74
|
+
"""Authentication response with JWT."""
|
|
75
|
+
token: str
|
|
76
|
+
user_id: str
|
|
77
|
+
wallet_address: str
|
|
78
|
+
role: str
|
|
79
|
+
tier: str
|
|
80
|
+
expires_at: str
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@router.post("/nonce", response_model=NonceResponse)
|
|
84
|
+
async def get_nonce(request: NonceRequest):
|
|
85
|
+
"""
|
|
86
|
+
Generate SIWE message and nonce for wallet authentication.
|
|
87
|
+
|
|
88
|
+
FREE - no third-party service needed!
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
POST /api/auth/nonce
|
|
92
|
+
{
|
|
93
|
+
"wallet_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
|
94
|
+
"chain_id": 137
|
|
95
|
+
}
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
from core.container import DependencyContainer
|
|
99
|
+
import os
|
|
100
|
+
|
|
101
|
+
container = DependencyContainer.get_instance()
|
|
102
|
+
siwe_auth = container.get_service('siwe_authenticator')
|
|
103
|
+
|
|
104
|
+
if not siwe_auth:
|
|
105
|
+
raise HTTPException(status_code=500, detail="SIWE authenticator not initialized")
|
|
106
|
+
|
|
107
|
+
# Get domain from environment or default to the local webview
|
|
108
|
+
domain = os.environ.get("WEBVIEW_DOMAIN", "localhost:3000")
|
|
109
|
+
uri = f"https://{domain}"
|
|
110
|
+
|
|
111
|
+
# Create SIWE message
|
|
112
|
+
result = await siwe_auth.create_siwe_message(
|
|
113
|
+
wallet_address=request.wallet_address,
|
|
114
|
+
domain=domain,
|
|
115
|
+
uri=uri,
|
|
116
|
+
chain_id=request.chain_id
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return NonceResponse(**result)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@router.post("/verify")
|
|
123
|
+
async def verify_signature(request: VerifyRequest):
|
|
124
|
+
"""Verify wallet signature and return JWT with HTTP-only cookie."""
|
|
125
|
+
|
|
126
|
+
from core.container import DependencyContainer
|
|
127
|
+
container = DependencyContainer.get_instance()
|
|
128
|
+
|
|
129
|
+
siwe_auth = container.get_service('siwe_authenticator')
|
|
130
|
+
identity_mapper = container.get_service('identity_mapper')
|
|
131
|
+
db = container.get_service('database_manager')
|
|
132
|
+
|
|
133
|
+
if not siwe_auth or not identity_mapper or not db:
|
|
134
|
+
raise HTTPException(status_code=500, detail="Auth services unavailable")
|
|
135
|
+
|
|
136
|
+
# Verify signature
|
|
137
|
+
is_valid = await siwe_auth.verify_signature(
|
|
138
|
+
wallet_address=request.wallet_address,
|
|
139
|
+
message=request.message,
|
|
140
|
+
signature=request.signature,
|
|
141
|
+
nonce=request.nonce
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
if not is_valid:
|
|
145
|
+
raise HTTPException(status_code=401, detail="Invalid signature")
|
|
146
|
+
|
|
147
|
+
# Get or create user - ALL wallets can sign in (tier set based on token ownership)
|
|
148
|
+
# Feature-level access control enforced elsewhere (task sessions, etc.)
|
|
149
|
+
user_id = await identity_mapper.get_or_create_user(
|
|
150
|
+
wallet_address=request.wallet_address,
|
|
151
|
+
chain=request.chain
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Get user details
|
|
155
|
+
user = await db.fetch_one("""
|
|
156
|
+
SELECT role, tier FROM user_profiles WHERE user_id = ?
|
|
157
|
+
""", (user_id,))
|
|
158
|
+
|
|
159
|
+
role = user['role'] if user else 'user'
|
|
160
|
+
tier = user['tier'] if user else 'free'
|
|
161
|
+
|
|
162
|
+
# SECURITY FIX: Do NOT auto-escalate admin role
|
|
163
|
+
# Admin wallets get admin PRIVILEGES during the session but NOT persistent role change
|
|
164
|
+
# This prevents silent role escalation without audit trail
|
|
165
|
+
# To make someone a permanent admin, use the /admin/users/{id}/role endpoint
|
|
166
|
+
is_admin_by_wallet = is_admin_wallet(request.wallet_address)
|
|
167
|
+
if is_admin_by_wallet:
|
|
168
|
+
logger.info(f"Admin wallet detected: {request.wallet_address[:6]}...{request.wallet_address[-4:]} (granting session privileges, not changing role)")
|
|
169
|
+
try:
|
|
170
|
+
from modules.database.audit_log import AuditLogger
|
|
171
|
+
await AuditLogger(db).log_admin_wallet_auth(
|
|
172
|
+
wallet_address=request.wallet_address, user_id=user_id,
|
|
173
|
+
)
|
|
174
|
+
except Exception as audit_exc:
|
|
175
|
+
logger.warning(f"Failed to write admin-wallet audit trail: {audit_exc}")
|
|
176
|
+
|
|
177
|
+
# Create JWT
|
|
178
|
+
jwt_secret = container.config.jwt_secret_key
|
|
179
|
+
if not jwt_secret:
|
|
180
|
+
raise HTTPException(status_code=500, detail="JWT not configured")
|
|
181
|
+
|
|
182
|
+
# SECURITY FIX: Never log JWT secret, even partially
|
|
183
|
+
# Logging even 20 chars significantly reduces brute-force difficulty
|
|
184
|
+
|
|
185
|
+
expires_at = datetime.utcnow() + timedelta(days=7)
|
|
186
|
+
|
|
187
|
+
# Include admin_wallet flag in token for session-based admin privileges
|
|
188
|
+
# This allows admin wallets to have privileges without modifying the role in DB
|
|
189
|
+
token_payload = {
|
|
190
|
+
"sub": request.wallet_address, # WALLET AS PRIMARY! ✅
|
|
191
|
+
"user_id": user_id, # Internal DB ID
|
|
192
|
+
"chain": request.chain,
|
|
193
|
+
"tier": tier,
|
|
194
|
+
"role": role,
|
|
195
|
+
"admin_wallet": is_admin_by_wallet, # Session-based admin flag
|
|
196
|
+
"iat": datetime.utcnow(),
|
|
197
|
+
"exp": expires_at
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
token = jwt.encode(token_payload, jwt_secret, algorithm="HS256")
|
|
201
|
+
|
|
202
|
+
# Log authentication success without sensitive details
|
|
203
|
+
admin_note = " [ADMIN WALLET]" if is_admin_by_wallet else ""
|
|
204
|
+
logger.info(f"✅ Authenticated wallet {request.wallet_address[:6]}...{request.wallet_address[-4:]} (role: {role}, tier: {tier}){admin_note}")
|
|
205
|
+
|
|
206
|
+
# Create response with auth data
|
|
207
|
+
response_data = {
|
|
208
|
+
"token": token,
|
|
209
|
+
"user_id": user_id,
|
|
210
|
+
"wallet_address": request.wallet_address,
|
|
211
|
+
"role": role,
|
|
212
|
+
"tier": tier,
|
|
213
|
+
"is_admin": is_admin_by_wallet or role == 'admin',
|
|
214
|
+
"expires_at": expires_at.isoformat()
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# Create JSON response
|
|
218
|
+
response = JSONResponse(content=response_data)
|
|
219
|
+
|
|
220
|
+
# SERVER-SIDE COOKIE SETTING (more reliable than client-side)
|
|
221
|
+
# SECURITY: Use secure cookie settings based on environment
|
|
222
|
+
# - secure=True: Cookie only sent over HTTPS (nginx terminates SSL)
|
|
223
|
+
# - httponly=True: Prevents JavaScript access (XSS protection)
|
|
224
|
+
# - samesite="lax": CSRF protection while allowing navigation
|
|
225
|
+
is_production = os.environ.get("ENVIRONMENT", "production") == "production"
|
|
226
|
+
secure = is_production # Only require HTTPS in production
|
|
227
|
+
httponly = True
|
|
228
|
+
samesite = "lax"
|
|
229
|
+
max_age = 7 * 24 * 60 * 60 # 7 days
|
|
230
|
+
|
|
231
|
+
logger.debug(f"🍪 Setting auth cookie: secure={secure}, httponly={httponly}, samesite={samesite}, is_production={is_production}")
|
|
232
|
+
|
|
233
|
+
response.set_cookie(
|
|
234
|
+
key="auth_token",
|
|
235
|
+
value=token,
|
|
236
|
+
max_age=max_age,
|
|
237
|
+
path="/",
|
|
238
|
+
# domain parameter intentionally omitted - defaults to current domain
|
|
239
|
+
secure=secure,
|
|
240
|
+
httponly=httponly,
|
|
241
|
+
samesite=samesite
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
return response
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@router.get("/me")
|
|
248
|
+
async def get_current_user(request: Request):
|
|
249
|
+
"""
|
|
250
|
+
Get current authenticated user info.
|
|
251
|
+
|
|
252
|
+
Requires Authorization: Bearer <token> header.
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
# user_id is added to request.state by middleware
|
|
256
|
+
if not hasattr(request.state, 'user_id'):
|
|
257
|
+
raise HTTPException(status_code=401, detail="Not authenticated")
|
|
258
|
+
|
|
259
|
+
from core.container import DependencyContainer
|
|
260
|
+
container = DependencyContainer.get_instance()
|
|
261
|
+
tier_manager = container.get_service('tier_manager')
|
|
262
|
+
|
|
263
|
+
if tier_manager:
|
|
264
|
+
user_info = await tier_manager.get_user_info(request.state.user_id)
|
|
265
|
+
return user_info
|
|
266
|
+
else:
|
|
267
|
+
return {"user_id": request.state.user_id}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
# =============================================================================
|
|
271
|
+
# API Key Management (Option A: Self-Service for AI Agents)
|
|
272
|
+
# =============================================================================
|
|
273
|
+
|
|
274
|
+
class CreateAPIKeyRequest(BaseModel):
|
|
275
|
+
"""Request to create a new API key."""
|
|
276
|
+
name: str = "Default"
|
|
277
|
+
expires_days: int = None # None = never expires
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class APIKeyResponse(BaseModel):
|
|
281
|
+
"""Response with API key (shown only once!)."""
|
|
282
|
+
api_key: str
|
|
283
|
+
name: str
|
|
284
|
+
prefix: str
|
|
285
|
+
expires_at: str = None
|
|
286
|
+
created_at: str
|
|
287
|
+
warning: str
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class APIKeyInfo(BaseModel):
|
|
291
|
+
"""API key info (without the actual key)."""
|
|
292
|
+
prefix: str
|
|
293
|
+
name: str
|
|
294
|
+
created_at: str
|
|
295
|
+
last_used: str = None
|
|
296
|
+
expires_at: str = None
|
|
297
|
+
is_active: bool
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
@router.post("/api-keys", response_model=APIKeyResponse)
|
|
301
|
+
async def create_api_key(request: Request, key_request: CreateAPIKeyRequest):
|
|
302
|
+
"""
|
|
303
|
+
Create a new API key for programmatic access.
|
|
304
|
+
|
|
305
|
+
**IMPORTANT**: The full API key is only shown ONCE. Store it securely!
|
|
306
|
+
|
|
307
|
+
Requires:
|
|
308
|
+
- Authenticated user (JWT from wallet login)
|
|
309
|
+
- DEN token ownership (verified via tier)
|
|
310
|
+
|
|
311
|
+
Example:
|
|
312
|
+
POST /api/auth/api-keys
|
|
313
|
+
Authorization: Bearer <your-jwt>
|
|
314
|
+
{
|
|
315
|
+
"name": "My Agent",
|
|
316
|
+
"expires_days": 90
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
Response:
|
|
320
|
+
{
|
|
321
|
+
"api_key": "rob_abc123...", // SAVE THIS!
|
|
322
|
+
"name": "My Agent",
|
|
323
|
+
"prefix": "rob_abc123",
|
|
324
|
+
"expires_at": "2025-03-05T12:00:00",
|
|
325
|
+
"warning": "Store this key securely - it won't be shown again!"
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
Usage:
|
|
329
|
+
curl -H "X-API-KEY: rob_abc123..." https://your-polyrob-host.example/a2a/rpc
|
|
330
|
+
"""
|
|
331
|
+
if not hasattr(request.state, 'user_id'):
|
|
332
|
+
raise HTTPException(status_code=401, detail="Authentication required. Login with wallet first.")
|
|
333
|
+
|
|
334
|
+
user_id = request.state.user_id
|
|
335
|
+
|
|
336
|
+
from core.container import DependencyContainer
|
|
337
|
+
container = DependencyContainer.get_instance()
|
|
338
|
+
api_key_manager = container.get_service('api_key_manager')
|
|
339
|
+
|
|
340
|
+
if not api_key_manager:
|
|
341
|
+
raise HTTPException(status_code=503, detail="API key service unavailable")
|
|
342
|
+
|
|
343
|
+
try:
|
|
344
|
+
result = await api_key_manager.generate_api_key(
|
|
345
|
+
user_id=user_id,
|
|
346
|
+
name=key_request.name,
|
|
347
|
+
expires_days=key_request.expires_days
|
|
348
|
+
)
|
|
349
|
+
return APIKeyResponse(**result)
|
|
350
|
+
except ValueError as e:
|
|
351
|
+
raise HTTPException(status_code=403, detail=str(e))
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
@router.get("/api-keys", response_model=list[APIKeyInfo])
|
|
355
|
+
async def list_api_keys(request: Request):
|
|
356
|
+
"""
|
|
357
|
+
List all API keys for the current user.
|
|
358
|
+
|
|
359
|
+
Note: Only shows key prefixes, not full keys.
|
|
360
|
+
"""
|
|
361
|
+
if not hasattr(request.state, 'user_id'):
|
|
362
|
+
raise HTTPException(status_code=401, detail="Authentication required")
|
|
363
|
+
|
|
364
|
+
user_id = request.state.user_id
|
|
365
|
+
|
|
366
|
+
from core.container import DependencyContainer
|
|
367
|
+
container = DependencyContainer.get_instance()
|
|
368
|
+
api_key_manager = container.get_service('api_key_manager')
|
|
369
|
+
|
|
370
|
+
if not api_key_manager:
|
|
371
|
+
raise HTTPException(status_code=503, detail="API key service unavailable")
|
|
372
|
+
|
|
373
|
+
keys = await api_key_manager.list_user_keys(user_id)
|
|
374
|
+
return [APIKeyInfo(**k) for k in keys]
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
@router.delete("/api-keys/{key_prefix}")
|
|
378
|
+
async def revoke_api_key(request: Request, key_prefix: str):
|
|
379
|
+
"""
|
|
380
|
+
Revoke an API key.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
key_prefix: The key prefix (e.g., "rob_abc123")
|
|
384
|
+
"""
|
|
385
|
+
if not hasattr(request.state, 'user_id'):
|
|
386
|
+
raise HTTPException(status_code=401, detail="Authentication required")
|
|
387
|
+
|
|
388
|
+
user_id = request.state.user_id
|
|
389
|
+
|
|
390
|
+
from core.container import DependencyContainer
|
|
391
|
+
container = DependencyContainer.get_instance()
|
|
392
|
+
api_key_manager = container.get_service('api_key_manager')
|
|
393
|
+
|
|
394
|
+
if not api_key_manager:
|
|
395
|
+
raise HTTPException(status_code=503, detail="API key service unavailable")
|
|
396
|
+
|
|
397
|
+
success = await api_key_manager.revoke_key(user_id, key_prefix)
|
|
398
|
+
|
|
399
|
+
if not success:
|
|
400
|
+
raise HTTPException(status_code=404, detail="API key not found")
|
|
401
|
+
|
|
402
|
+
return {"success": True, "message": f"API key {key_prefix} revoked"}
|
api/auth_state.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""The canonical request.state auth contract (C4 SSOT).
|
|
2
|
+
|
|
3
|
+
Every middleware that authenticates a request — AuthenticationMiddleware,
|
|
4
|
+
JWTAuthMiddleware, X402PaymentMiddleware, and the fallback_auth_middleware in
|
|
5
|
+
api/app.py — MUST write these five fields via set_auth_state() instead of
|
|
6
|
+
setting attributes ad hoc. verify_payment_for_request and every
|
|
7
|
+
Depends(get_user_id) / get_user_strict / get_user_permissive consumer in
|
|
8
|
+
api/dependencies.py reads this contract.
|
|
9
|
+
|
|
10
|
+
Workstream B3 (owner-login session, POLYROB Console posture 1) writes the SAME
|
|
11
|
+
contract with role="owner" — this module is what B3 coordinates against.
|
|
12
|
+
"""
|
|
13
|
+
from typing import Any, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def set_auth_state(
|
|
17
|
+
state: Any,
|
|
18
|
+
*,
|
|
19
|
+
user_id: Optional[str],
|
|
20
|
+
tier: str = "free",
|
|
21
|
+
role: str = "user",
|
|
22
|
+
payment_method: Optional[str] = None,
|
|
23
|
+
authenticated: bool = True,
|
|
24
|
+
) -> None:
|
|
25
|
+
"""Write the canonical auth-state contract onto `state`.
|
|
26
|
+
|
|
27
|
+
`state` is typically a Starlette `Request.state` (a Starlette `State`
|
|
28
|
+
object) but any object that accepts attribute assignment works — this is
|
|
29
|
+
deliberately duck-typed so it's trivial to unit test with a bare
|
|
30
|
+
`types.SimpleNamespace()`.
|
|
31
|
+
"""
|
|
32
|
+
state.user_id = user_id
|
|
33
|
+
state.tier = tier
|
|
34
|
+
state.role = role
|
|
35
|
+
state.payment_method = payment_method
|
|
36
|
+
state.authenticated = authenticated
|
api/chat_via_task.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Canonical handler for the HTTP chat endpoint (/api/chat/message).
|
|
2
|
+
|
|
3
|
+
Chat is served purely by the unified task agent's synchronous ``chat_once`` — the
|
|
4
|
+
legacy ``ChatAgent`` was retired (HANDOFF-C, 2026-06-19). There is no legacy path
|
|
5
|
+
to fall back to, so any failure returns a graceful ``MessageResponse(success=False)``
|
|
6
|
+
rather than ``None``. This module is the single seam between the public HTTP chat
|
|
7
|
+
contract and the one agent core.
|
|
8
|
+
"""
|
|
9
|
+
import logging
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
from api.models import MessageResponse
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
_UNAVAILABLE_TEXT = "Chat is temporarily unavailable. Please try again."
|
|
17
|
+
_ERROR_TEXT = "Sorry, something went wrong handling your message."
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def handle_chat_via_task_agent(
|
|
21
|
+
container,
|
|
22
|
+
user_id: str,
|
|
23
|
+
text: str,
|
|
24
|
+
chat_id: Optional[str],
|
|
25
|
+
) -> MessageResponse:
|
|
26
|
+
"""Serve one chat turn from the unified task agent.
|
|
27
|
+
|
|
28
|
+
Always returns a ``MessageResponse``: ``success=True`` with the agent reply,
|
|
29
|
+
or ``success=False`` with a user-safe message when the agent is unavailable
|
|
30
|
+
or ``chat_once`` raises (logged as ``chat.error`` — there is no legacy agent
|
|
31
|
+
to fall back to).
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
task_agent = container.get_agent("task_agent") if container else None
|
|
35
|
+
if not task_agent or not hasattr(task_agent, "chat_once"):
|
|
36
|
+
logger.error("chat.error: task_agent unavailable")
|
|
37
|
+
return MessageResponse(success=False, text=_UNAVAILABLE_TEXT)
|
|
38
|
+
reply = await task_agent.chat_once(user_id=user_id, text=text, chat_id=chat_id)
|
|
39
|
+
return MessageResponse(success=True, text=str(reply or ""))
|
|
40
|
+
except Exception as e:
|
|
41
|
+
logger.error(f"chat.error: {e}", exc_info=True)
|
|
42
|
+
return MessageResponse(success=False, text=_ERROR_TEXT)
|