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
agents/base_agent.py
ADDED
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
"""Base agent class for all bot agents."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import asyncio
|
|
5
|
+
from typing import List, Optional, Dict, Any, Union, TYPE_CHECKING, Awaitable
|
|
6
|
+
from abc import abstractmethod
|
|
7
|
+
|
|
8
|
+
from core.base_component import BaseComponent
|
|
9
|
+
from core.config import BotConfig
|
|
10
|
+
from core.container import DependencyContainer
|
|
11
|
+
from core.exceptions import AgentError
|
|
12
|
+
from core.version import get_version
|
|
13
|
+
from modules.memory.models import ConversationContext, Message
|
|
14
|
+
from modules.llm.llm_client import LLMClient
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from agents.personality.character import Character
|
|
18
|
+
from modules.memory.memory_manager import MemoryManager
|
|
19
|
+
# Already imported above, just keeping for type checking
|
|
20
|
+
# from modules.llm.llm_client import LLMClient
|
|
21
|
+
|
|
22
|
+
class BaseAgent(BaseComponent):
|
|
23
|
+
"""Base class for all agents."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, *, config: BotConfig, container: DependencyContainer, name: str):
|
|
26
|
+
"""Initialize base agent."""
|
|
27
|
+
super().__init__(name=name, config=config, container=container)
|
|
28
|
+
|
|
29
|
+
# Initialize core components - all will be properly set in _initialize()
|
|
30
|
+
self.llm_client = None
|
|
31
|
+
self.knowledge_base = None
|
|
32
|
+
self.character_manager = None
|
|
33
|
+
self.active_character = None
|
|
34
|
+
self.memory_manager = None
|
|
35
|
+
self.system_prompt_manager = None
|
|
36
|
+
|
|
37
|
+
# Initialize state
|
|
38
|
+
self._initialized = False
|
|
39
|
+
self._enabled = True
|
|
40
|
+
self._last_result = None
|
|
41
|
+
self._init_lock = asyncio.Lock()
|
|
42
|
+
self.llm_available = False
|
|
43
|
+
|
|
44
|
+
# LLM config with character settings if available
|
|
45
|
+
self.llm_config = {
|
|
46
|
+
'model_type': 'claude-sonnet-4-5',
|
|
47
|
+
'temperature': 0.7,
|
|
48
|
+
'max_tokens': 4096,
|
|
49
|
+
'top_p': 0.9,
|
|
50
|
+
'top_k': 50
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Update with character settings if available
|
|
54
|
+
if self.active_character and hasattr(self.active_character, 'settings'):
|
|
55
|
+
self.llm_config.update(self.active_character.settings)
|
|
56
|
+
|
|
57
|
+
def _get_default_character(self):
|
|
58
|
+
"""Get default character configuration."""
|
|
59
|
+
return {
|
|
60
|
+
'name': 'Assistant',
|
|
61
|
+
'personality': 'Helpful and professional',
|
|
62
|
+
'background': 'An AI assistant designed to help users with various tasks',
|
|
63
|
+
'traits': ['helpful', 'knowledgeable', 'professional']
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async def _initialize(self) -> None:
|
|
67
|
+
"""Initialize agent base components."""
|
|
68
|
+
try:
|
|
69
|
+
# Initialize LLM client
|
|
70
|
+
if self.container:
|
|
71
|
+
# Try getting preferred LLM client first, falling back to any available client
|
|
72
|
+
self.llm_client = self._get_preferred_llm_client()
|
|
73
|
+
if not self.llm_client:
|
|
74
|
+
self.logger.warning("Preferred LLM client not available, will try to use any available client")
|
|
75
|
+
self.llm_client = self.container.get_service('llm')
|
|
76
|
+
if not self.llm_client:
|
|
77
|
+
self.logger.warning("Primary LLM client not available, will try alternative clients")
|
|
78
|
+
# Try specific clients in order of preference
|
|
79
|
+
for client_name in ['anthropic_client', 'openai_client']:
|
|
80
|
+
if self.container.has_service(client_name):
|
|
81
|
+
self.llm_client = self.container.get_service(client_name)
|
|
82
|
+
self.logger.info(f"Using {client_name} as fallback")
|
|
83
|
+
break
|
|
84
|
+
|
|
85
|
+
if not self.llm_client:
|
|
86
|
+
self.llm_available = False
|
|
87
|
+
self.logger.error("No LLM client available - agent functionality will be limited")
|
|
88
|
+
else:
|
|
89
|
+
self.llm_available = True
|
|
90
|
+
|
|
91
|
+
# Get optional services properly, only if they exist
|
|
92
|
+
if self.container.has_service('memory_manager'):
|
|
93
|
+
self.memory_manager = self.container.get_service('memory_manager')
|
|
94
|
+
|
|
95
|
+
if self.container.has_service('system_prompt_manager'):
|
|
96
|
+
self.system_prompt_manager = self.container.get_service('system_prompt_manager')
|
|
97
|
+
|
|
98
|
+
if self.container.has_service('knowledge_base'):
|
|
99
|
+
self.knowledge_base = self.container.get_service('knowledge_base')
|
|
100
|
+
|
|
101
|
+
# Get character manager and role-specific character
|
|
102
|
+
if self.container.has_service('character_manager'):
|
|
103
|
+
self.character_manager = self.container.get_service('character_manager')
|
|
104
|
+
try:
|
|
105
|
+
self.active_character = await self.character_manager.get_character_for_role(self.name)
|
|
106
|
+
if self.active_character:
|
|
107
|
+
self.logger.debug(f"Using character: {self.active_character.name}")
|
|
108
|
+
else:
|
|
109
|
+
self.logger.debug("No specific character assigned, using default settings")
|
|
110
|
+
except Exception as e:
|
|
111
|
+
self.logger.debug(f"Could not load character: {e}, using default settings")
|
|
112
|
+
|
|
113
|
+
self.logger.info(f"{self.name} agent base components initialized")
|
|
114
|
+
else:
|
|
115
|
+
raise AgentError("Container is required for agent initialization")
|
|
116
|
+
|
|
117
|
+
except Exception as e:
|
|
118
|
+
self.logger.error(f"Error initializing agent base components: {e}")
|
|
119
|
+
raise
|
|
120
|
+
|
|
121
|
+
def _get_preferred_llm_client(self) -> Optional[LLMClient]:
|
|
122
|
+
"""Get preferred LLM client based on agent configuration."""
|
|
123
|
+
if not self.container:
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
# Get preferred client name from config
|
|
127
|
+
preferred_client = self.config.get(self.name, {}).get('llm_client')
|
|
128
|
+
if not preferred_client:
|
|
129
|
+
# Default preference - use GPT-4.1 for task agent
|
|
130
|
+
if self.name == 'task_agent':
|
|
131
|
+
preferred_client = 'openai_client'
|
|
132
|
+
else:
|
|
133
|
+
preferred_client = 'anthropic_client'
|
|
134
|
+
|
|
135
|
+
# Try to get the preferred client
|
|
136
|
+
client = self.container.get_service(preferred_client)
|
|
137
|
+
if client:
|
|
138
|
+
self.logger.info(f"Using preferred LLM client: {preferred_client}")
|
|
139
|
+
return client
|
|
140
|
+
|
|
141
|
+
# If preferred client is not available, use any client
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
async def _cleanup(self) -> None:
|
|
145
|
+
"""Clean up agent resources."""
|
|
146
|
+
try:
|
|
147
|
+
if self.llm_client:
|
|
148
|
+
await self.llm_client.cleanup()
|
|
149
|
+
self.logger.info(f"{self.name} agent cleaned up")
|
|
150
|
+
except Exception as e:
|
|
151
|
+
self.logger.error(f"Error cleaning up {self.name} agent: {e}")
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def required_services(self) -> Dict[str, str]:
|
|
155
|
+
"""Get required services."""
|
|
156
|
+
return {
|
|
157
|
+
'llm_client': 'LLM service for text generation',
|
|
158
|
+
'memory_manager': 'Memory management service'
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def is_enabled(self) -> bool:
|
|
163
|
+
"""Check if agent is enabled."""
|
|
164
|
+
return self._initialized and self.llm_available
|
|
165
|
+
|
|
166
|
+
async def initialize(self) -> None:
|
|
167
|
+
"""Initialize agent and its components."""
|
|
168
|
+
try:
|
|
169
|
+
await self._initialize()
|
|
170
|
+
if self.active_character:
|
|
171
|
+
self.logger.info(f"{self.name} agent initialized with character {self.active_character.name}")
|
|
172
|
+
else:
|
|
173
|
+
self.logger.info(f"{self.name} agent initialized")
|
|
174
|
+
except Exception as e:
|
|
175
|
+
self.logger.error(f"Failed to initialize {self.name} agent: {str(e)}")
|
|
176
|
+
raise AgentError(f"Failed to initialize agent: {str(e)}")
|
|
177
|
+
|
|
178
|
+
async def set_character(self, character: 'Character') -> None:
|
|
179
|
+
"""Set or update the agent's character."""
|
|
180
|
+
try:
|
|
181
|
+
self.active_character = character
|
|
182
|
+
if self.llm_client:
|
|
183
|
+
self.llm_client.active_character = character
|
|
184
|
+
if self.system_prompt_manager:
|
|
185
|
+
await self.system_prompt_manager.set_prompt(
|
|
186
|
+
self.name,
|
|
187
|
+
self.system_prompt_manager.get_prompt(self.name, character=character)
|
|
188
|
+
)
|
|
189
|
+
self.logger.info(f"Updated {self.name} agent character to {character.name}")
|
|
190
|
+
except Exception as e:
|
|
191
|
+
self.logger.error(f"Error setting character: {e}")
|
|
192
|
+
raise AgentError(f"Failed to set character: {str(e)}")
|
|
193
|
+
|
|
194
|
+
async def get_character_info(self) -> Optional[Dict[str, Any]]:
|
|
195
|
+
"""Get information about the current character."""
|
|
196
|
+
if not self.active_character:
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
"name": self.active_character.name,
|
|
201
|
+
"bio": self.active_character.bio,
|
|
202
|
+
"style": self.active_character.style,
|
|
203
|
+
"knowledge": self.active_character.knowledge,
|
|
204
|
+
"topics": self.active_character.topics,
|
|
205
|
+
"adjectives": self.active_character.adjectives
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async def set_llm_client(self, client_name: str) -> bool:
|
|
209
|
+
"""Set the LLM client to use for this agent.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
client_name: Name of the client to use ('anthropic_client', 'openai_client', 'llm')
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
bool: True if client was set successfully, False otherwise
|
|
216
|
+
"""
|
|
217
|
+
if not self.container:
|
|
218
|
+
self.logger.error("No container available to get LLM client")
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
# Get the client from container
|
|
222
|
+
client = self.container.get_service(client_name)
|
|
223
|
+
if not client:
|
|
224
|
+
self.logger.error(f"LLM client '{client_name}' not found")
|
|
225
|
+
return False
|
|
226
|
+
|
|
227
|
+
# Set client and log
|
|
228
|
+
self.llm_client = client
|
|
229
|
+
self.logger.info(f"Switched to LLM client: {client_name} ({client.__class__.__name__})")
|
|
230
|
+
|
|
231
|
+
return True
|
|
232
|
+
|
|
233
|
+
async def get_llm_settings(self) -> Dict[str, Any]:
|
|
234
|
+
"""Get current LLM settings for this agent.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
Dict containing current LLM settings
|
|
238
|
+
"""
|
|
239
|
+
if not self.llm_client:
|
|
240
|
+
return self.llm_config
|
|
241
|
+
|
|
242
|
+
# Get client type
|
|
243
|
+
client_type = self.llm_client.__class__.__name__.lower()
|
|
244
|
+
|
|
245
|
+
# Get model information
|
|
246
|
+
model_info = {
|
|
247
|
+
"name": getattr(self.llm_client, 'model_type', 'unknown'),
|
|
248
|
+
"provider": client_type.replace('client', ''),
|
|
249
|
+
"temperature": getattr(self.llm_client, 'temperature', self.llm_config.get('temperature', 0.7)),
|
|
250
|
+
"max_tokens": getattr(self.llm_client, 'max_tokens', self.llm_config.get('max_tokens', 1000)),
|
|
251
|
+
"initialized": getattr(self.llm_client, '_initialized', False),
|
|
252
|
+
"client_name": getattr(self.llm_client, 'name', client_type)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return model_info
|
|
256
|
+
|
|
257
|
+
async def refresh_llm_status(self) -> None:
|
|
258
|
+
"""Refresh the current LLM client status.
|
|
259
|
+
|
|
260
|
+
This method ensures the current LLM client information is up-to-date.
|
|
261
|
+
Used primarily by the settings handler to get accurate client status.
|
|
262
|
+
"""
|
|
263
|
+
if not self.llm_client:
|
|
264
|
+
self.logger.warning("No LLM client to refresh")
|
|
265
|
+
return
|
|
266
|
+
|
|
267
|
+
# If the client has an initialize method, check its status
|
|
268
|
+
if hasattr(self.llm_client, 'initialize') and not getattr(self.llm_client, '_initialized', False):
|
|
269
|
+
try:
|
|
270
|
+
self.logger.debug(f"Refreshing LLM client {self.llm_client.__class__.__name__}")
|
|
271
|
+
await self.llm_client.initialize()
|
|
272
|
+
except Exception as e:
|
|
273
|
+
self.logger.error(f"Error refreshing LLM client: {e}")
|
|
274
|
+
|
|
275
|
+
# Log the current status
|
|
276
|
+
status = {
|
|
277
|
+
"client": self.llm_client.__class__.__name__,
|
|
278
|
+
"name": getattr(self.llm_client, 'name', self.llm_client.__class__.__name__.lower()),
|
|
279
|
+
"initialized": getattr(self.llm_client, '_initialized', False)
|
|
280
|
+
}
|
|
281
|
+
self.logger.debug(f"LLM client status: {status}")
|
|
282
|
+
|
|
283
|
+
async def update_llm_settings(self, settings: Dict[str, Any]) -> bool:
|
|
284
|
+
"""Update LLM settings for this agent.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
settings: Dictionary of settings to update
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
bool: True if settings were updated successfully
|
|
291
|
+
"""
|
|
292
|
+
if not self.llm_client:
|
|
293
|
+
self.logger.error("No LLM client available")
|
|
294
|
+
return False
|
|
295
|
+
|
|
296
|
+
try:
|
|
297
|
+
# Extract client_name if provided
|
|
298
|
+
client_name = settings.pop('client_name', None)
|
|
299
|
+
|
|
300
|
+
# If client_name is provided, we may need to switch clients
|
|
301
|
+
if client_name and client_name != getattr(self.llm_client, 'name', None):
|
|
302
|
+
# Only switch if it's different from current
|
|
303
|
+
if self.container:
|
|
304
|
+
new_client = self.container.get_service(client_name)
|
|
305
|
+
if new_client:
|
|
306
|
+
# Ensure the client is initialized
|
|
307
|
+
if not getattr(new_client, '_initialized', False) and hasattr(new_client, 'initialize'):
|
|
308
|
+
await new_client.initialize()
|
|
309
|
+
|
|
310
|
+
self.llm_client = new_client
|
|
311
|
+
self.logger.info(f"Switched to client: {client_name}")
|
|
312
|
+
else:
|
|
313
|
+
self.logger.warning(f"Client {client_name} not found in container")
|
|
314
|
+
return False
|
|
315
|
+
|
|
316
|
+
# Try using update_settings method if available
|
|
317
|
+
if hasattr(self.llm_client, 'update_settings'):
|
|
318
|
+
self.llm_client.update_settings(settings)
|
|
319
|
+
self.logger.info(f"Updated settings via update_settings: {settings}")
|
|
320
|
+
|
|
321
|
+
# Also update our local config
|
|
322
|
+
self.llm_config.update(settings)
|
|
323
|
+
return True
|
|
324
|
+
|
|
325
|
+
# Otherwise update attributes directly
|
|
326
|
+
for key, value in settings.items():
|
|
327
|
+
# Update the client instance attributes directly
|
|
328
|
+
if hasattr(self.llm_client, key):
|
|
329
|
+
# Save previous value for logging
|
|
330
|
+
prev_val = getattr(self.llm_client, key)
|
|
331
|
+
# Set the new value
|
|
332
|
+
setattr(self.llm_client, key, value)
|
|
333
|
+
self.logger.info(f"Updated {key} = {value} (was {prev_val})")
|
|
334
|
+
else:
|
|
335
|
+
self.logger.warning(f"LLM client {self.llm_client.__class__.__name__} does not have attribute {key}")
|
|
336
|
+
|
|
337
|
+
# Also update our local config for future reference
|
|
338
|
+
self.llm_config[key] = value
|
|
339
|
+
|
|
340
|
+
return True
|
|
341
|
+
except Exception as e:
|
|
342
|
+
self.logger.error(f"Error updating LLM settings: {e}")
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
async def get_available_llm_clients(self) -> Dict[str, Dict[str, Any]]:
|
|
346
|
+
"""Get information about available LLM clients.
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
Dict mapping client names to client information
|
|
350
|
+
"""
|
|
351
|
+
result = {}
|
|
352
|
+
|
|
353
|
+
# Try to get LLM manager if available
|
|
354
|
+
llm_manager = self.container.get_service('llm_manager')
|
|
355
|
+
if llm_manager:
|
|
356
|
+
# Use LLM manager to get client info
|
|
357
|
+
return await llm_manager.get_available_clients()
|
|
358
|
+
|
|
359
|
+
# Manual fallback if LLM manager not available
|
|
360
|
+
for client_name in ['anthropic_client', 'openai_client', 'llm']:
|
|
361
|
+
client = self.container.get_service(client_name)
|
|
362
|
+
if client:
|
|
363
|
+
# Get basic information
|
|
364
|
+
result[client_name] = {
|
|
365
|
+
'name': client_name,
|
|
366
|
+
'model': getattr(client, 'model_type', 'unknown'),
|
|
367
|
+
'initialized': getattr(client, '_initialized', False),
|
|
368
|
+
'is_primary': (client_name == 'llm')
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return result
|
|
372
|
+
|
|
373
|
+
async def _prepare_context(
|
|
374
|
+
self,
|
|
375
|
+
input_text: str,
|
|
376
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
377
|
+
) -> Dict[str, Any]:
|
|
378
|
+
"""Prepare base context for response generation."""
|
|
379
|
+
try:
|
|
380
|
+
# Get system prompt
|
|
381
|
+
system_prompt = ""
|
|
382
|
+
if self.system_prompt_manager:
|
|
383
|
+
system_prompt = await self.system_prompt_manager.get_prompt(
|
|
384
|
+
role=self.name,
|
|
385
|
+
model_type=self.llm_client.__class__.__name__.lower().replace('client', ''),
|
|
386
|
+
character=self.active_character
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
# Get knowledge context if available
|
|
390
|
+
knowledge_context = ""
|
|
391
|
+
if self.memory_manager and self.memory_manager.knowledge_base:
|
|
392
|
+
entries = await self.memory_manager.knowledge_base.search(
|
|
393
|
+
query=input_text,
|
|
394
|
+
top_k=3
|
|
395
|
+
)
|
|
396
|
+
if entries:
|
|
397
|
+
knowledge_context = "\n\n".join(e["text"] for e in entries)
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
"system": system_prompt,
|
|
401
|
+
"knowledge_context": knowledge_context,
|
|
402
|
+
"messages": []
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
except Exception as e:
|
|
406
|
+
self.logger.error(f"Error preparing context: {e}")
|
|
407
|
+
return {
|
|
408
|
+
"system": "",
|
|
409
|
+
"knowledge_context": "",
|
|
410
|
+
"messages": []
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
@abstractmethod
|
|
414
|
+
async def process_input(
|
|
415
|
+
self,
|
|
416
|
+
input_text: str,
|
|
417
|
+
context_id: Optional[str] = None,
|
|
418
|
+
user_id: Optional[str] = None,
|
|
419
|
+
chat_id: Optional[str] = None,
|
|
420
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
421
|
+
) -> str:
|
|
422
|
+
"""Process input and generate response."""
|
|
423
|
+
raise NotImplementedError("Subclasses must implement process_input")
|
|
424
|
+
|
|
425
|
+
@abstractmethod
|
|
426
|
+
async def start_conversation(
|
|
427
|
+
self,
|
|
428
|
+
user_id: str,
|
|
429
|
+
chat_id: Optional[str] = None,
|
|
430
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
431
|
+
) -> bool:
|
|
432
|
+
"""Start a new conversation."""
|
|
433
|
+
raise NotImplementedError("Subclasses must implement start_conversation")
|
|
434
|
+
|
|
435
|
+
def get_capabilities(self) -> Dict[str, Any]:
|
|
436
|
+
"""Get agent capability information.
|
|
437
|
+
|
|
438
|
+
Returns:
|
|
439
|
+
Dictionary with agent capabilities
|
|
440
|
+
"""
|
|
441
|
+
# Determine required and optional services
|
|
442
|
+
required_services = []
|
|
443
|
+
optional_services = []
|
|
444
|
+
|
|
445
|
+
# Check which services are available
|
|
446
|
+
if self.llm_client:
|
|
447
|
+
required_services.append("llm")
|
|
448
|
+
if self.memory_manager:
|
|
449
|
+
optional_services.append("memory")
|
|
450
|
+
if self.knowledge_base:
|
|
451
|
+
optional_services.append("knowledge_base")
|
|
452
|
+
if self.character_manager:
|
|
453
|
+
optional_services.append("character_manager")
|
|
454
|
+
|
|
455
|
+
# Build features list based on agent type
|
|
456
|
+
features = []
|
|
457
|
+
if hasattr(self, 'process_message'):
|
|
458
|
+
features.append("message_processing")
|
|
459
|
+
if hasattr(self, 'handle_command'):
|
|
460
|
+
features.append("command_handling")
|
|
461
|
+
if hasattr(self, 'process'):
|
|
462
|
+
features.append("generic_processing")
|
|
463
|
+
if hasattr(self, 'create_session'):
|
|
464
|
+
features.append("session_management")
|
|
465
|
+
if hasattr(self, 'run_automation'):
|
|
466
|
+
features.append("automation")
|
|
467
|
+
|
|
468
|
+
return {
|
|
469
|
+
"id": self.name,
|
|
470
|
+
"name": self.__class__.__name__,
|
|
471
|
+
"version": getattr(self, 'version', None) or get_version(),
|
|
472
|
+
"enabled": self._enabled,
|
|
473
|
+
"features": features,
|
|
474
|
+
"required_services": required_services,
|
|
475
|
+
"optional_services": optional_services,
|
|
476
|
+
"description": self.__doc__ or f"{self.__class__.__name__} agent",
|
|
477
|
+
"initialized": self._initialized,
|
|
478
|
+
"llm_available": self.llm_available,
|
|
479
|
+
"llm_config": self.llm_config if self.llm_config else {}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
@abstractmethod
|
|
483
|
+
async def cleanup(self) -> None:
|
|
484
|
+
"""Clean up agent resources."""
|
|
485
|
+
pass
|
|
486
|
+
|
|
487
|
+
async def generate_response(
|
|
488
|
+
self,
|
|
489
|
+
messages: Optional[List[Message]] = None,
|
|
490
|
+
prompt: Optional[Union[str, Dict[str, Any]]] = None,
|
|
491
|
+
system: Optional[str] = None,
|
|
492
|
+
context: Optional[Any] = None,
|
|
493
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
494
|
+
max_tokens: Optional[int] = None,
|
|
495
|
+
temperature: Optional[float] = None
|
|
496
|
+
) -> str:
|
|
497
|
+
"""Generate response using LLM."""
|
|
498
|
+
try:
|
|
499
|
+
if not self.llm_client:
|
|
500
|
+
self.logger.error("No LLM client available")
|
|
501
|
+
return "I'm unable to respond right now due to a configuration issue. Please try again later."
|
|
502
|
+
|
|
503
|
+
# Get character info if available
|
|
504
|
+
character_info = None
|
|
505
|
+
if self.active_character:
|
|
506
|
+
character_info = {
|
|
507
|
+
"name": self.active_character.name,
|
|
508
|
+
"bio": self.active_character.bio,
|
|
509
|
+
"traits": self.active_character.adjectives,
|
|
510
|
+
"style": self.active_character.style
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
# Determine appropriate parameters based on LLM client type
|
|
514
|
+
llm_client_type = self.llm_client.__class__.__name__.lower()
|
|
515
|
+
model_name = getattr(self.llm_client, 'model_type', 'unknown')
|
|
516
|
+
|
|
517
|
+
# Get current values from the client itself
|
|
518
|
+
client_temperature = getattr(self.llm_client, 'temperature', None)
|
|
519
|
+
client_max_tokens = getattr(self.llm_client, 'max_tokens', None)
|
|
520
|
+
|
|
521
|
+
# Use passed values, client values, or config defaults - in that order of priority
|
|
522
|
+
request_temperature = temperature or client_temperature or self.llm_config.get('temperature', 0.7)
|
|
523
|
+
request_max_tokens = max_tokens or client_max_tokens or self.llm_config.get('max_tokens', 4096)
|
|
524
|
+
|
|
525
|
+
# Log request parameters
|
|
526
|
+
self.logger.info(f"LLM Request | Model: {model_name} | Client: {llm_client_type} | " +
|
|
527
|
+
f"Temp: {request_temperature} | Max Tokens: {request_max_tokens}")
|
|
528
|
+
|
|
529
|
+
# Initialize with default parameters
|
|
530
|
+
llm_params = {
|
|
531
|
+
"temperature": request_temperature,
|
|
532
|
+
"max_tokens": request_max_tokens
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
# Format messages based on client type
|
|
536
|
+
formatted_messages = []
|
|
537
|
+
|
|
538
|
+
# If messages is a list of Message objects, convert to dict format
|
|
539
|
+
if messages and isinstance(messages, list):
|
|
540
|
+
if messages and isinstance(messages[0], dict):
|
|
541
|
+
# Already in dict format
|
|
542
|
+
formatted_messages = messages
|
|
543
|
+
else:
|
|
544
|
+
for msg in messages:
|
|
545
|
+
if hasattr(msg, 'to_dict'):
|
|
546
|
+
formatted_messages.append(msg.to_dict())
|
|
547
|
+
elif hasattr(msg, 'role') and hasattr(msg, 'content'):
|
|
548
|
+
formatted_messages.append({
|
|
549
|
+
'role': msg.role,
|
|
550
|
+
'content': msg.content
|
|
551
|
+
})
|
|
552
|
+
# If prompt is provided as a dict with messages
|
|
553
|
+
elif prompt and isinstance(prompt, dict) and 'messages' in prompt:
|
|
554
|
+
for msg in prompt['messages']:
|
|
555
|
+
if isinstance(msg, dict):
|
|
556
|
+
formatted_messages.append(msg)
|
|
557
|
+
elif hasattr(msg, 'to_dict'):
|
|
558
|
+
formatted_messages.append(msg.to_dict())
|
|
559
|
+
elif hasattr(msg, 'role') and hasattr(msg, 'content'):
|
|
560
|
+
formatted_messages.append({
|
|
561
|
+
'role': msg.role,
|
|
562
|
+
'content': msg.content
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
# If system is in prompt, use it
|
|
566
|
+
if 'system' in prompt and not system:
|
|
567
|
+
system = prompt['system']
|
|
568
|
+
|
|
569
|
+
# If prompt is a string, use it as a single user message
|
|
570
|
+
elif prompt and isinstance(prompt, str):
|
|
571
|
+
formatted_messages.append({
|
|
572
|
+
'role': 'user',
|
|
573
|
+
'content': prompt
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
# Add system message if available (but not for Anthropic)
|
|
577
|
+
system_content = system
|
|
578
|
+
if system and 'anthropic' not in llm_client_type:
|
|
579
|
+
# Check if there's already a system message
|
|
580
|
+
has_system = any(msg.get('role') == 'system' for msg in formatted_messages)
|
|
581
|
+
if not has_system:
|
|
582
|
+
formatted_messages.insert(0, {
|
|
583
|
+
'role': 'system',
|
|
584
|
+
'content': system
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
# Log how many messages we've prepared
|
|
588
|
+
self.logger.debug(f"Prepared {len(formatted_messages)} messages for LLM, system message: {'present' if system else 'absent'}")
|
|
589
|
+
|
|
590
|
+
# Make the request to the LLM client based on its specific API
|
|
591
|
+
response = None
|
|
592
|
+
|
|
593
|
+
if 'anthropic' in llm_client_type:
|
|
594
|
+
# For Anthropic, we need to:
|
|
595
|
+
# 1. Extract any system messages from the formatted_messages
|
|
596
|
+
# 2. Pass system content separately
|
|
597
|
+
# 3. Filter metadata for Anthropic API
|
|
598
|
+
|
|
599
|
+
# First check if there's a system message in formatted_messages and extract it
|
|
600
|
+
anthropic_messages = []
|
|
601
|
+
for msg in formatted_messages:
|
|
602
|
+
if msg.get('role') == 'system':
|
|
603
|
+
if not system_content: # Only use if we don't already have system content
|
|
604
|
+
system_content = msg.get('content', '')
|
|
605
|
+
else:
|
|
606
|
+
anthropic_messages.append(msg)
|
|
607
|
+
|
|
608
|
+
# Create a filtered version of metadata - Anthropic only allows specific metadata fields
|
|
609
|
+
anthropic_metadata = None
|
|
610
|
+
if metadata:
|
|
611
|
+
# Only pass through user_id which is allowed in Anthropic's metadata
|
|
612
|
+
anthropic_metadata = {}
|
|
613
|
+
if 'user_id' in metadata:
|
|
614
|
+
anthropic_metadata['user_id'] = metadata['user_id']
|
|
615
|
+
|
|
616
|
+
if len(anthropic_metadata) == 0:
|
|
617
|
+
anthropic_metadata = None
|
|
618
|
+
|
|
619
|
+
# Make the API call with system parameter separate from messages
|
|
620
|
+
response = await self.llm_client.generate_response(
|
|
621
|
+
messages=anthropic_messages, # Send messages WITHOUT system role
|
|
622
|
+
system=system_content, # Pass system content separately
|
|
623
|
+
metadata=anthropic_metadata, # Use filtered metadata
|
|
624
|
+
**llm_params
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
elif 'openai' in llm_client_type or 'llama' in llm_client_type:
|
|
628
|
+
# For OpenAI/Llama just pass messages with system message included
|
|
629
|
+
|
|
630
|
+
# For OpenAI specifically, make sure metadata is properly formatted
|
|
631
|
+
# (OpenAI expects character to be a string, not an object)
|
|
632
|
+
if 'openai' in llm_client_type and metadata:
|
|
633
|
+
openai_metadata = {}
|
|
634
|
+
|
|
635
|
+
# Handle special case for 'character'
|
|
636
|
+
if 'character' in metadata and isinstance(metadata['character'], dict):
|
|
637
|
+
if 'name' in metadata['character']:
|
|
638
|
+
openai_metadata['character'] = metadata['character']['name']
|
|
639
|
+
|
|
640
|
+
# Copy other simple values
|
|
641
|
+
for k, v in metadata.items():
|
|
642
|
+
if k != 'character' and isinstance(v, (str, int, float, bool)):
|
|
643
|
+
openai_metadata[k] = v
|
|
644
|
+
|
|
645
|
+
# Check if we have any metadata to send
|
|
646
|
+
if openai_metadata:
|
|
647
|
+
# For OpenAI, we need to decide if we want to enable store
|
|
648
|
+
# Based on settings, we may choose to enable or disable metadata
|
|
649
|
+
use_metadata = True
|
|
650
|
+
# Get store setting from llm_params if available
|
|
651
|
+
store_enabled = llm_params.get('store', False)
|
|
652
|
+
|
|
653
|
+
if use_metadata and not store_enabled:
|
|
654
|
+
# We could enable store here, but for now let's just log and skip metadata
|
|
655
|
+
self.logger.warning("OpenAI metadata provided but store not enabled, skipping metadata")
|
|
656
|
+
# Skip sending metadata
|
|
657
|
+
response = await self.llm_client.generate_response(
|
|
658
|
+
messages=formatted_messages,
|
|
659
|
+
**llm_params
|
|
660
|
+
)
|
|
661
|
+
else:
|
|
662
|
+
# Send metadata along with store=True
|
|
663
|
+
response = await self.llm_client.generate_response(
|
|
664
|
+
messages=formatted_messages,
|
|
665
|
+
metadata=openai_metadata,
|
|
666
|
+
store=True,
|
|
667
|
+
**llm_params
|
|
668
|
+
)
|
|
669
|
+
else:
|
|
670
|
+
# No metadata to send
|
|
671
|
+
response = await self.llm_client.generate_response(
|
|
672
|
+
messages=formatted_messages,
|
|
673
|
+
**llm_params
|
|
674
|
+
)
|
|
675
|
+
else:
|
|
676
|
+
# For Llama or when no metadata present
|
|
677
|
+
response = await self.llm_client.generate_response(
|
|
678
|
+
messages=formatted_messages,
|
|
679
|
+
metadata=metadata,
|
|
680
|
+
**llm_params
|
|
681
|
+
)
|
|
682
|
+
|
|
683
|
+
else:
|
|
684
|
+
# Generic fallback - try to be robust for any client type
|
|
685
|
+
# Pass both system and messages separately, and as a combined 'prompt'
|
|
686
|
+
prompt_bundle = {
|
|
687
|
+
"messages": formatted_messages,
|
|
688
|
+
"system": system
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
response = await self.llm_client.generate_response(
|
|
692
|
+
messages=formatted_messages,
|
|
693
|
+
system=system,
|
|
694
|
+
prompt=prompt_bundle,
|
|
695
|
+
metadata=metadata,
|
|
696
|
+
**llm_params
|
|
697
|
+
)
|
|
698
|
+
|
|
699
|
+
# Log response details
|
|
700
|
+
client_type = self.llm_client.__class__.__name__
|
|
701
|
+
model_name = getattr(self.llm_client, 'model_type', 'unknown')
|
|
702
|
+
|
|
703
|
+
# Try to extract token usage from response if available
|
|
704
|
+
token_info = "Token usage unknown"
|
|
705
|
+
try:
|
|
706
|
+
if hasattr(response, 'usage'):
|
|
707
|
+
usage = response.usage
|
|
708
|
+
token_info = f"Tokens: {usage.prompt_tokens} prompt + {usage.completion_tokens} completion = {usage.total_tokens} total"
|
|
709
|
+
elif hasattr(self.llm_client, 'last_response') and hasattr(self.llm_client.last_response, 'usage'):
|
|
710
|
+
usage = self.llm_client.last_response.usage
|
|
711
|
+
token_info = f"Tokens: {usage.prompt_tokens} prompt + {usage.completion_tokens} completion = {usage.total_tokens} total"
|
|
712
|
+
except Exception as e:
|
|
713
|
+
self.logger.debug(f"Could not extract token usage: {e}")
|
|
714
|
+
|
|
715
|
+
# Log consolidated information
|
|
716
|
+
self.logger.info(f"LLM Response | Model: {model_name} | Client: {client_type} | {token_info}")
|
|
717
|
+
|
|
718
|
+
# Extract string content from response
|
|
719
|
+
if isinstance(response, str):
|
|
720
|
+
return response
|
|
721
|
+
elif hasattr(response, 'content'):
|
|
722
|
+
return response.content
|
|
723
|
+
elif hasattr(response, 'choices') and len(response.choices) > 0:
|
|
724
|
+
# OpenAI-style response
|
|
725
|
+
return response.choices[0].message.content
|
|
726
|
+
elif hasattr(response, 'text'):
|
|
727
|
+
return response.text
|
|
728
|
+
else:
|
|
729
|
+
# Try to convert to string as last resort
|
|
730
|
+
return str(response)
|
|
731
|
+
|
|
732
|
+
except Exception as e:
|
|
733
|
+
self.logger.error(f"Error generating response: {e}")
|
|
734
|
+
raise
|
|
735
|
+
|
|
736
|
+
def _validate_dependencies(self) -> None:
|
|
737
|
+
"""Validate dependencies."""
|
|
738
|
+
if not self.llm_client:
|
|
739
|
+
self.llm_available = False
|
|
740
|
+
self.logger.warning(f"{self.name} agent initialized without LLM - some features will be disabled")
|
|
741
|
+
return
|
|
742
|
+
self.llm_available = True
|
|
743
|
+
|