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/payment_endpoints.py
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
"""Payment API endpoints for credit management and deposits."""
|
|
2
|
+
|
|
3
|
+
from fastapi import APIRouter, HTTPException, Depends, Request
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
from typing import List, Optional, Dict, Any
|
|
6
|
+
import logging
|
|
7
|
+
from api.auth_constants import ADMIN_ROLES
|
|
8
|
+
from modules.credits.pricing import pricing, WELCOME_BONUS, DEN_SIGNUP_ALLOWANCE
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
router = APIRouter(prefix="/payments", tags=["payments"])
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DepositAddressResponse(BaseModel):
|
|
16
|
+
"""Deposit address response."""
|
|
17
|
+
user_id: str
|
|
18
|
+
deposit_address: str
|
|
19
|
+
chains: List[str]
|
|
20
|
+
qr_code_url: Optional[str] = None
|
|
21
|
+
instructions: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CreditBalanceResponse(BaseModel):
|
|
25
|
+
"""Credit balance response."""
|
|
26
|
+
user_id: str
|
|
27
|
+
balance: int
|
|
28
|
+
lifetime_earned: int
|
|
29
|
+
lifetime_spent: int
|
|
30
|
+
tier: str
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TransactionResponse(BaseModel):
|
|
34
|
+
"""Credit transaction response."""
|
|
35
|
+
id: int
|
|
36
|
+
user_id: str
|
|
37
|
+
amount: int
|
|
38
|
+
transaction_type: str
|
|
39
|
+
reason: str
|
|
40
|
+
session_id: Optional[str]
|
|
41
|
+
balance_before: int
|
|
42
|
+
balance_after: int
|
|
43
|
+
timestamp: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class PaginatedTransactionsResponse(BaseModel):
|
|
47
|
+
"""Paginated transactions response with metadata."""
|
|
48
|
+
transactions: List[TransactionResponse]
|
|
49
|
+
total: int
|
|
50
|
+
limit: int
|
|
51
|
+
offset: int
|
|
52
|
+
has_more: bool
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CryptoPaymentResponse(BaseModel):
|
|
56
|
+
"""Crypto payment response."""
|
|
57
|
+
id: int
|
|
58
|
+
chain: str
|
|
59
|
+
token_symbol: str
|
|
60
|
+
amount: str
|
|
61
|
+
amount_usd: float
|
|
62
|
+
credits_purchased: int
|
|
63
|
+
status: str
|
|
64
|
+
detected_at: str
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Helper to get authenticated user from JWT — strict policy (rejects api_user / authenticated_api_user).
|
|
68
|
+
# Delegates to the canonical implementation in api.dependencies.
|
|
69
|
+
from api.dependencies import get_user_strict as get_authenticated_user
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@router.get("/deposit-address", response_model=DepositAddressResponse)
|
|
73
|
+
async def get_deposit_address(
|
|
74
|
+
request: Request,
|
|
75
|
+
user_id: str = Depends(get_authenticated_user)
|
|
76
|
+
):
|
|
77
|
+
"""Get or create deposit address for user.
|
|
78
|
+
|
|
79
|
+
Returns a unique deposit address for receiving crypto payments.
|
|
80
|
+
Credits are automatically added when deposits are detected.
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
from core.container import DependencyContainer
|
|
84
|
+
container = DependencyContainer.get_instance()
|
|
85
|
+
|
|
86
|
+
wallet_gen = container.get_service('wallet_generator')
|
|
87
|
+
db_manager = container.get_service('database_manager')
|
|
88
|
+
|
|
89
|
+
# Check if user is admin - admins don't need deposit addresses
|
|
90
|
+
role = getattr(request.state, 'role', 'user')
|
|
91
|
+
is_admin = role in ADMIN_ROLES
|
|
92
|
+
|
|
93
|
+
if not wallet_gen or not db_manager:
|
|
94
|
+
# If services not available and user is admin, return placeholder
|
|
95
|
+
if is_admin:
|
|
96
|
+
logger.info(f"Wallet generator unavailable, returning placeholder for admin {user_id}")
|
|
97
|
+
return {
|
|
98
|
+
"user_id": user_id,
|
|
99
|
+
"deposit_address": "N/A - Admin account has unlimited credits",
|
|
100
|
+
"chains": [],
|
|
101
|
+
"qr_code_url": None,
|
|
102
|
+
"instructions": "As an admin, you have unlimited credits and do not need to deposit funds."
|
|
103
|
+
}
|
|
104
|
+
raise HTTPException(
|
|
105
|
+
status_code=503,
|
|
106
|
+
detail="Payment services temporarily unavailable"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Check if user already has deposit address
|
|
110
|
+
existing = await db_manager.fetch_one("""
|
|
111
|
+
SELECT deposit_address, generated_at
|
|
112
|
+
FROM user_deposit_addresses
|
|
113
|
+
WHERE user_id = ?
|
|
114
|
+
""", (user_id,))
|
|
115
|
+
|
|
116
|
+
if existing:
|
|
117
|
+
deposit_address = existing['deposit_address']
|
|
118
|
+
logger.info(f"Retrieved existing deposit address for user {user_id}")
|
|
119
|
+
else:
|
|
120
|
+
# Generate new deposit address
|
|
121
|
+
deposit_address = wallet_gen.generate_deposit_address(user_id)
|
|
122
|
+
|
|
123
|
+
# Store in database (user should exist with deterministic ID)
|
|
124
|
+
try:
|
|
125
|
+
await db_manager.execute("""
|
|
126
|
+
INSERT INTO user_deposit_addresses (
|
|
127
|
+
user_id, deposit_address, generated_at
|
|
128
|
+
) VALUES (?, ?, datetime('now'))
|
|
129
|
+
""", (user_id, deposit_address))
|
|
130
|
+
logger.info(f"Generated new deposit address for user {user_id}: {deposit_address}")
|
|
131
|
+
except Exception as e:
|
|
132
|
+
# FK constraint - user doesn't exist, trigger re-auth
|
|
133
|
+
logger.error(f"Failed to create deposit address - user {user_id} not found: {e}")
|
|
134
|
+
raise HTTPException(
|
|
135
|
+
status_code=401,
|
|
136
|
+
detail="Session expired. Please sign in again with your wallet."
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return DepositAddressResponse(
|
|
140
|
+
user_id=user_id,
|
|
141
|
+
deposit_address=deposit_address,
|
|
142
|
+
chains=["ethereum", "sepolia"],
|
|
143
|
+
qr_code_url=f"https://chart.googleapis.com/chart?chs=200x200&cht=qr&chl={deposit_address}",
|
|
144
|
+
instructions=(
|
|
145
|
+
f"Send USDC, USDT, or ETH to this address on Ethereum mainnet or Sepolia testnet. "
|
|
146
|
+
f"Credits will be added automatically (1 credit = $0.01 USD). "
|
|
147
|
+
f"Minimum deposit: $5 USD."
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
except HTTPException:
|
|
152
|
+
raise
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.error(f"Error getting deposit address for user {user_id}: {e}", exc_info=True)
|
|
155
|
+
raise HTTPException(
|
|
156
|
+
status_code=500,
|
|
157
|
+
detail="Failed to generate deposit address. Please try again later."
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@router.get("/balance")
|
|
162
|
+
async def get_credit_balance(
|
|
163
|
+
request: Request,
|
|
164
|
+
user_id: str = Depends(get_authenticated_user)
|
|
165
|
+
):
|
|
166
|
+
"""Get current credit balance and usage statistics.
|
|
167
|
+
|
|
168
|
+
Shows:
|
|
169
|
+
- Current balance
|
|
170
|
+
- Lifetime earned/spent
|
|
171
|
+
- Tier
|
|
172
|
+
"""
|
|
173
|
+
try:
|
|
174
|
+
from core.container import DependencyContainer
|
|
175
|
+
container = DependencyContainer.get_instance()
|
|
176
|
+
|
|
177
|
+
balance_mgr = container.get_service('balance_manager')
|
|
178
|
+
tier_mgr = container.get_service('tier_manager')
|
|
179
|
+
|
|
180
|
+
# Check if user is admin - admins get unlimited credits
|
|
181
|
+
role = getattr(request.state, 'role', 'user')
|
|
182
|
+
is_admin = role in ADMIN_ROLES
|
|
183
|
+
|
|
184
|
+
if not balance_mgr:
|
|
185
|
+
# If balance manager not available and user is admin, return unlimited balance
|
|
186
|
+
if is_admin:
|
|
187
|
+
logger.info(f"Balance manager unavailable, returning unlimited balance for admin {user_id}")
|
|
188
|
+
return {
|
|
189
|
+
"user_id": user_id,
|
|
190
|
+
"balance": 999999,
|
|
191
|
+
"lifetime_earned": 999999,
|
|
192
|
+
"lifetime_spent": 0,
|
|
193
|
+
"tier": "admin"
|
|
194
|
+
}
|
|
195
|
+
raise HTTPException(
|
|
196
|
+
status_code=503,
|
|
197
|
+
detail="Balance service temporarily unavailable"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Get balance
|
|
201
|
+
balance_info = await balance_mgr.get_balance(user_id)
|
|
202
|
+
|
|
203
|
+
# Get tier
|
|
204
|
+
tier = "free"
|
|
205
|
+
if tier_mgr:
|
|
206
|
+
try:
|
|
207
|
+
tier = await tier_mgr.get_user_tier(user_id)
|
|
208
|
+
except HTTPException:
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
return CreditBalanceResponse(
|
|
212
|
+
user_id=user_id,
|
|
213
|
+
balance=balance_info['balance'],
|
|
214
|
+
lifetime_earned=balance_info['lifetime_earned'],
|
|
215
|
+
lifetime_spent=balance_info['lifetime_spent'],
|
|
216
|
+
tier=tier
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
except HTTPException:
|
|
220
|
+
raise
|
|
221
|
+
except Exception as e:
|
|
222
|
+
logger.error(f"Error getting balance for user {user_id}: {e}", exc_info=True)
|
|
223
|
+
raise HTTPException(
|
|
224
|
+
status_code=500,
|
|
225
|
+
detail="Failed to retrieve balance. Please try again later."
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@router.get("/transactions")
|
|
230
|
+
async def get_transactions(
|
|
231
|
+
request: Request,
|
|
232
|
+
user_id: str = Depends(get_authenticated_user),
|
|
233
|
+
limit: int = 100,
|
|
234
|
+
offset: int = 0,
|
|
235
|
+
paginated: bool = False
|
|
236
|
+
):
|
|
237
|
+
"""Get credit transaction history.
|
|
238
|
+
|
|
239
|
+
Shows all credit additions and deductions with reasons.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
limit: Max transactions to return (default 100, max 500)
|
|
243
|
+
offset: Skip first N transactions for pagination
|
|
244
|
+
paginated: If true, returns {transactions, total, has_more} format
|
|
245
|
+
"""
|
|
246
|
+
try:
|
|
247
|
+
from core.container import DependencyContainer
|
|
248
|
+
container = DependencyContainer.get_instance()
|
|
249
|
+
|
|
250
|
+
db_manager = container.get_service('database_manager')
|
|
251
|
+
|
|
252
|
+
# Check if user is admin
|
|
253
|
+
role = getattr(request.state, 'role', 'user')
|
|
254
|
+
is_admin = role in ADMIN_ROLES
|
|
255
|
+
|
|
256
|
+
if not db_manager:
|
|
257
|
+
# If database not available and user is admin, return empty
|
|
258
|
+
if is_admin:
|
|
259
|
+
logger.info(f"Database unavailable, returning empty transactions for admin {user_id}")
|
|
260
|
+
if paginated:
|
|
261
|
+
return {"transactions": [], "total": 0, "limit": limit, "offset": offset, "has_more": False}
|
|
262
|
+
return []
|
|
263
|
+
raise HTTPException(status_code=503, detail="Database temporarily unavailable")
|
|
264
|
+
|
|
265
|
+
# Enforce max limit to prevent abuse
|
|
266
|
+
limit = min(limit, 500)
|
|
267
|
+
|
|
268
|
+
# Get total count for pagination
|
|
269
|
+
total_result = await db_manager.fetch_one("""
|
|
270
|
+
SELECT COUNT(*) as total FROM credit_transactions WHERE user_id = ?
|
|
271
|
+
""", (user_id,))
|
|
272
|
+
total = total_result['total'] if total_result else 0
|
|
273
|
+
|
|
274
|
+
# Fetch transactions
|
|
275
|
+
transactions = await db_manager.fetch_all("""
|
|
276
|
+
SELECT
|
|
277
|
+
id,
|
|
278
|
+
user_id,
|
|
279
|
+
amount,
|
|
280
|
+
transaction_type,
|
|
281
|
+
reason,
|
|
282
|
+
session_id,
|
|
283
|
+
balance_before,
|
|
284
|
+
balance_after,
|
|
285
|
+
timestamp
|
|
286
|
+
FROM credit_transactions
|
|
287
|
+
WHERE user_id = ?
|
|
288
|
+
ORDER BY timestamp DESC
|
|
289
|
+
LIMIT ? OFFSET ?
|
|
290
|
+
""", (user_id, limit, offset))
|
|
291
|
+
|
|
292
|
+
tx_list = [
|
|
293
|
+
TransactionResponse(
|
|
294
|
+
id=tx['id'],
|
|
295
|
+
user_id=tx['user_id'],
|
|
296
|
+
amount=tx['amount'],
|
|
297
|
+
transaction_type=tx['transaction_type'],
|
|
298
|
+
reason=tx['reason'],
|
|
299
|
+
session_id=tx['session_id'],
|
|
300
|
+
balance_before=tx['balance_before'] or 0,
|
|
301
|
+
balance_after=tx['balance_after'] or 0,
|
|
302
|
+
timestamp=tx['timestamp']
|
|
303
|
+
)
|
|
304
|
+
for tx in transactions
|
|
305
|
+
]
|
|
306
|
+
|
|
307
|
+
# Return paginated or simple list based on request
|
|
308
|
+
if paginated:
|
|
309
|
+
return PaginatedTransactionsResponse(
|
|
310
|
+
transactions=tx_list,
|
|
311
|
+
total=total,
|
|
312
|
+
limit=limit,
|
|
313
|
+
offset=offset,
|
|
314
|
+
has_more=(offset + len(tx_list)) < total
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
return tx_list
|
|
318
|
+
|
|
319
|
+
except HTTPException:
|
|
320
|
+
raise
|
|
321
|
+
except Exception as e:
|
|
322
|
+
logger.error(f"Error getting transactions for user {user_id}: {e}", exc_info=True)
|
|
323
|
+
raise HTTPException(
|
|
324
|
+
status_code=500,
|
|
325
|
+
detail="Failed to retrieve transactions. Please try again later."
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
@router.get("/deposits")
|
|
330
|
+
async def get_deposits(
|
|
331
|
+
request: Request,
|
|
332
|
+
user_id: str = Depends(get_authenticated_user),
|
|
333
|
+
limit: int = 100,
|
|
334
|
+
offset: int = 0
|
|
335
|
+
):
|
|
336
|
+
"""Get crypto deposit history.
|
|
337
|
+
|
|
338
|
+
Shows all detected deposits from blockchain.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
limit: Max deposits to return (default 100, max 500)
|
|
342
|
+
offset: Skip first N deposits for pagination
|
|
343
|
+
"""
|
|
344
|
+
try:
|
|
345
|
+
from core.container import DependencyContainer
|
|
346
|
+
container = DependencyContainer.get_instance()
|
|
347
|
+
|
|
348
|
+
db_manager = container.get_service('database_manager')
|
|
349
|
+
|
|
350
|
+
# Check if user is admin
|
|
351
|
+
role = getattr(request.state, 'role', 'user')
|
|
352
|
+
is_admin = role in ADMIN_ROLES
|
|
353
|
+
|
|
354
|
+
if not db_manager:
|
|
355
|
+
# If database not available and user is admin, return empty list
|
|
356
|
+
if is_admin:
|
|
357
|
+
logger.info(f"Database unavailable, returning empty deposits for admin {user_id}")
|
|
358
|
+
return []
|
|
359
|
+
raise HTTPException(status_code=503, detail="Database temporarily unavailable")
|
|
360
|
+
|
|
361
|
+
# Enforce max limit
|
|
362
|
+
limit = min(limit, 500)
|
|
363
|
+
|
|
364
|
+
# Fetch deposits
|
|
365
|
+
deposits = await db_manager.fetch_all("""
|
|
366
|
+
SELECT
|
|
367
|
+
id,
|
|
368
|
+
chain,
|
|
369
|
+
token_symbol,
|
|
370
|
+
amount,
|
|
371
|
+
amount_usd,
|
|
372
|
+
credits_purchased,
|
|
373
|
+
status,
|
|
374
|
+
detected_at
|
|
375
|
+
FROM crypto_payments
|
|
376
|
+
WHERE user_id = ?
|
|
377
|
+
ORDER BY detected_at DESC
|
|
378
|
+
LIMIT ? OFFSET ?
|
|
379
|
+
""", (user_id, limit, offset))
|
|
380
|
+
|
|
381
|
+
return [
|
|
382
|
+
CryptoPaymentResponse(
|
|
383
|
+
id=dep['id'],
|
|
384
|
+
chain=dep['chain'],
|
|
385
|
+
token_symbol=dep['token_symbol'],
|
|
386
|
+
amount=dep['amount'],
|
|
387
|
+
amount_usd=dep['amount_usd'],
|
|
388
|
+
credits_purchased=dep['credits_purchased'],
|
|
389
|
+
status=dep['status'],
|
|
390
|
+
detected_at=dep['detected_at']
|
|
391
|
+
)
|
|
392
|
+
for dep in deposits
|
|
393
|
+
]
|
|
394
|
+
|
|
395
|
+
except HTTPException:
|
|
396
|
+
raise
|
|
397
|
+
except Exception as e:
|
|
398
|
+
logger.error(f"Error getting deposits for user {user_id}: {e}", exc_info=True)
|
|
399
|
+
raise HTTPException(
|
|
400
|
+
status_code=500,
|
|
401
|
+
detail="Failed to retrieve deposits. Please try again later."
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
@router.get("/pricing")
|
|
406
|
+
async def get_pricing():
|
|
407
|
+
"""Get credit pricing information.
|
|
408
|
+
|
|
409
|
+
Public endpoint - no auth required.
|
|
410
|
+
"""
|
|
411
|
+
return {
|
|
412
|
+
"credit_rate": pricing.CREDIT_VALUE_USD, # Dynamic from pricing config
|
|
413
|
+
"minimum_deposit_usd": 5.00,
|
|
414
|
+
"supported_tokens": [
|
|
415
|
+
{
|
|
416
|
+
"symbol": "USDC",
|
|
417
|
+
"name": "USD Coin",
|
|
418
|
+
"chains": ["ethereum", "sepolia"]
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"symbol": "USDT",
|
|
422
|
+
"name": "Tether USD",
|
|
423
|
+
"chains": ["ethereum", "sepolia"]
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"symbol": "ETH",
|
|
427
|
+
"name": "Ethereum",
|
|
428
|
+
"chains": ["ethereum", "sepolia"]
|
|
429
|
+
}
|
|
430
|
+
],
|
|
431
|
+
"tier_allowances": {
|
|
432
|
+
"free": {
|
|
433
|
+
"welcome_bonus": WELCOME_BONUS,
|
|
434
|
+
"signup_allowance": 0,
|
|
435
|
+
"requires_den_token": False
|
|
436
|
+
},
|
|
437
|
+
"holder": {
|
|
438
|
+
"welcome_bonus": WELCOME_BONUS,
|
|
439
|
+
"signup_allowance_per_token": DEN_SIGNUP_ALLOWANCE,
|
|
440
|
+
"requires_den_token": True,
|
|
441
|
+
"den_tokens_required": "1+"
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""Unified payment verification supporting credits and x402."""
|
|
2
|
+
|
|
3
|
+
from fastapi import Request, HTTPException
|
|
4
|
+
from typing import Tuple, Dict, Any
|
|
5
|
+
import logging
|
|
6
|
+
from api.auth_constants import is_admin, extract_admin_info
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def verify_payment_for_request(
|
|
12
|
+
request: Request,
|
|
13
|
+
cost_credits: int = 1
|
|
14
|
+
) -> Tuple[str, Dict[str, Any]]:
|
|
15
|
+
"""Verify payment via credits OR x402 OR admin bypass.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
Tuple of (payment_method: str, details: dict)
|
|
19
|
+
|
|
20
|
+
Raises:
|
|
21
|
+
HTTPException: If no valid payment found
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# OPTION 0: Admin bypass (if enabled)
|
|
25
|
+
user_id = getattr(request.state, 'user_id', None)
|
|
26
|
+
|
|
27
|
+
# Use centralized admin detection
|
|
28
|
+
is_admin_user, role, wallet_address = extract_admin_info(request.state)
|
|
29
|
+
|
|
30
|
+
logger.info(f"🔍 Payment verification: user={user_id}, role={role}, wallet={wallet_address}, is_admin={is_admin_user}")
|
|
31
|
+
|
|
32
|
+
# Check if admin bypass is enabled
|
|
33
|
+
from core.container import DependencyContainer
|
|
34
|
+
container = DependencyContainer.get_instance()
|
|
35
|
+
config = container.config if container else None
|
|
36
|
+
|
|
37
|
+
# Admin bypass is enabled by default (config defaults to True)
|
|
38
|
+
bypass_enabled = True
|
|
39
|
+
if config:
|
|
40
|
+
bypass_enabled = getattr(config, 'bypass_payment_for_admins', True)
|
|
41
|
+
|
|
42
|
+
if bypass_enabled and is_admin_user:
|
|
43
|
+
logger.info(f"✅ Admin {user_id} (role: {role}, wallet: {wallet_address}) bypassed payment check")
|
|
44
|
+
return "admin_bypass", {
|
|
45
|
+
"user_id": user_id,
|
|
46
|
+
"role": role,
|
|
47
|
+
"wallet": wallet_address,
|
|
48
|
+
"bypass_reason": "admin_privilege",
|
|
49
|
+
"endpoint": request.url.path
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# OPTION 1: Check for x402 payment FIRST (middleware already verified)
|
|
53
|
+
# This must come before credit check because x402 users have user_id set
|
|
54
|
+
payment_method = getattr(request.state, 'payment_method', None)
|
|
55
|
+
|
|
56
|
+
if payment_method == "x402":
|
|
57
|
+
# Payment verified by X402PaymentMiddleware
|
|
58
|
+
payer_address = getattr(request.state, 'payer_address', 'unknown')
|
|
59
|
+
logger.info(f"✅ x402 payment already verified for {payer_address[:10]}...")
|
|
60
|
+
return "x402", {
|
|
61
|
+
"payer_address": payer_address,
|
|
62
|
+
"user_id": user_id,
|
|
63
|
+
"endpoint": request.url.path
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# OPTION 2: Check for JWT (credit system)
|
|
67
|
+
if user_id and user_id not in ['api_user', 'authenticated_api_user']:
|
|
68
|
+
# User authenticated → use credit system.
|
|
69
|
+
# C1: AUTHORIZE ONLY. Do NOT deduct here — the per-token LLMUsageTracker
|
|
70
|
+
# (modules/credits/usage_tracker.py::record_llm_usage) is the single
|
|
71
|
+
# deduction path, billed on ACTUAL token usage once the call completes.
|
|
72
|
+
# Deducting a flat cost_credits here too was double-billing every request.
|
|
73
|
+
from core.container import DependencyContainer
|
|
74
|
+
container = DependencyContainer.get_instance()
|
|
75
|
+
balance_mgr = container.get_service('balance_manager')
|
|
76
|
+
|
|
77
|
+
if not balance_mgr:
|
|
78
|
+
raise HTTPException(status_code=503, detail="Credit system unavailable")
|
|
79
|
+
|
|
80
|
+
has_credits = await balance_mgr.has_sufficient_balance(user_id, cost_credits)
|
|
81
|
+
|
|
82
|
+
if not has_credits:
|
|
83
|
+
raise HTTPException(
|
|
84
|
+
status_code=402,
|
|
85
|
+
detail="Insufficient credits. Deposit more or use x402."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return "credits", {
|
|
89
|
+
"user_id": user_id,
|
|
90
|
+
"credits_deducted": 0,
|
|
91
|
+
"endpoint": request.url.path
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# OPTION 3: No payment → Return 402
|
|
95
|
+
raise HTTPException(
|
|
96
|
+
status_code=402,
|
|
97
|
+
detail="Payment required. Use credits (login) or x402 (pay-per-request)."
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def payment_required_response(
|
|
102
|
+
request: Request,
|
|
103
|
+
cost_credits: int = 1
|
|
104
|
+
) -> Dict[str, Any]:
|
|
105
|
+
"""Generate 402 response with both payment options."""
|
|
106
|
+
from modules.x402.x402_integration import get_x402_price_usd
|
|
107
|
+
|
|
108
|
+
cost_usd = cost_credits * 0.01
|
|
109
|
+
# C2: single price SSOT — the quoted x402 price MUST equal the live charge.
|
|
110
|
+
x402_cost_usd = get_x402_price_usd()
|
|
111
|
+
|
|
112
|
+
# Get x402 handler from app state
|
|
113
|
+
payment_handler = getattr(request.app.state, 'x402_handler', None)
|
|
114
|
+
|
|
115
|
+
x402_details = {}
|
|
116
|
+
if payment_handler:
|
|
117
|
+
x402_response = payment_handler.create_payment_required_response(
|
|
118
|
+
amount_usd=x402_cost_usd,
|
|
119
|
+
asset="usdc",
|
|
120
|
+
metadata={"endpoint": request.url.path, "cost_credits": cost_credits}
|
|
121
|
+
)
|
|
122
|
+
x402_details = x402_response['body']['payment']
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
"error": "Payment Required",
|
|
126
|
+
"code": "PAYMENT_REQUIRED",
|
|
127
|
+
"payment_options": {
|
|
128
|
+
"credits": {
|
|
129
|
+
"cost_usd": cost_usd,
|
|
130
|
+
"cost_credits": cost_credits,
|
|
131
|
+
"instructions": "Login with wallet at /api/auth/verify"
|
|
132
|
+
},
|
|
133
|
+
"x402": {
|
|
134
|
+
"cost_usd": x402_cost_usd,
|
|
135
|
+
"payment_details": x402_details
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|