PraisonAI 3.0.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.
- praisonai/__init__.py +54 -0
- praisonai/__main__.py +15 -0
- praisonai/acp/__init__.py +54 -0
- praisonai/acp/config.py +159 -0
- praisonai/acp/server.py +587 -0
- praisonai/acp/session.py +219 -0
- praisonai/adapters/__init__.py +50 -0
- praisonai/adapters/readers.py +395 -0
- praisonai/adapters/rerankers.py +315 -0
- praisonai/adapters/retrievers.py +394 -0
- praisonai/adapters/vector_stores.py +409 -0
- praisonai/agent_scheduler.py +337 -0
- praisonai/agents_generator.py +903 -0
- praisonai/api/call.py +292 -0
- praisonai/auto.py +1197 -0
- praisonai/capabilities/__init__.py +275 -0
- praisonai/capabilities/a2a.py +140 -0
- praisonai/capabilities/assistants.py +283 -0
- praisonai/capabilities/audio.py +320 -0
- praisonai/capabilities/batches.py +469 -0
- praisonai/capabilities/completions.py +336 -0
- praisonai/capabilities/container_files.py +155 -0
- praisonai/capabilities/containers.py +93 -0
- praisonai/capabilities/embeddings.py +158 -0
- praisonai/capabilities/files.py +467 -0
- praisonai/capabilities/fine_tuning.py +293 -0
- praisonai/capabilities/guardrails.py +182 -0
- praisonai/capabilities/images.py +330 -0
- praisonai/capabilities/mcp.py +190 -0
- praisonai/capabilities/messages.py +270 -0
- praisonai/capabilities/moderations.py +154 -0
- praisonai/capabilities/ocr.py +217 -0
- praisonai/capabilities/passthrough.py +204 -0
- praisonai/capabilities/rag.py +207 -0
- praisonai/capabilities/realtime.py +160 -0
- praisonai/capabilities/rerank.py +165 -0
- praisonai/capabilities/responses.py +266 -0
- praisonai/capabilities/search.py +109 -0
- praisonai/capabilities/skills.py +133 -0
- praisonai/capabilities/vector_store_files.py +334 -0
- praisonai/capabilities/vector_stores.py +304 -0
- praisonai/capabilities/videos.py +141 -0
- praisonai/chainlit_ui.py +304 -0
- praisonai/chat/__init__.py +106 -0
- praisonai/chat/app.py +125 -0
- praisonai/cli/__init__.py +26 -0
- praisonai/cli/app.py +213 -0
- praisonai/cli/commands/__init__.py +75 -0
- praisonai/cli/commands/acp.py +70 -0
- praisonai/cli/commands/completion.py +333 -0
- praisonai/cli/commands/config.py +166 -0
- praisonai/cli/commands/debug.py +142 -0
- praisonai/cli/commands/diag.py +55 -0
- praisonai/cli/commands/doctor.py +166 -0
- praisonai/cli/commands/environment.py +179 -0
- praisonai/cli/commands/lsp.py +112 -0
- praisonai/cli/commands/mcp.py +210 -0
- praisonai/cli/commands/profile.py +457 -0
- praisonai/cli/commands/run.py +228 -0
- praisonai/cli/commands/schedule.py +150 -0
- praisonai/cli/commands/serve.py +97 -0
- praisonai/cli/commands/session.py +212 -0
- praisonai/cli/commands/traces.py +145 -0
- praisonai/cli/commands/version.py +101 -0
- praisonai/cli/configuration/__init__.py +18 -0
- praisonai/cli/configuration/loader.py +353 -0
- praisonai/cli/configuration/paths.py +114 -0
- praisonai/cli/configuration/schema.py +164 -0
- praisonai/cli/features/__init__.py +268 -0
- praisonai/cli/features/acp.py +236 -0
- praisonai/cli/features/action_orchestrator.py +546 -0
- praisonai/cli/features/agent_scheduler.py +773 -0
- praisonai/cli/features/agent_tools.py +474 -0
- praisonai/cli/features/agents.py +375 -0
- praisonai/cli/features/at_mentions.py +471 -0
- praisonai/cli/features/auto_memory.py +182 -0
- praisonai/cli/features/autonomy_mode.py +490 -0
- praisonai/cli/features/background.py +356 -0
- praisonai/cli/features/base.py +168 -0
- praisonai/cli/features/capabilities.py +1326 -0
- praisonai/cli/features/checkpoints.py +338 -0
- praisonai/cli/features/code_intelligence.py +652 -0
- praisonai/cli/features/compaction.py +294 -0
- praisonai/cli/features/compare.py +534 -0
- praisonai/cli/features/cost_tracker.py +514 -0
- praisonai/cli/features/debug.py +810 -0
- praisonai/cli/features/deploy.py +517 -0
- praisonai/cli/features/diag.py +289 -0
- praisonai/cli/features/doctor/__init__.py +63 -0
- praisonai/cli/features/doctor/checks/__init__.py +24 -0
- praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
- praisonai/cli/features/doctor/checks/config_checks.py +366 -0
- praisonai/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai/cli/features/doctor/checks/env_checks.py +543 -0
- praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
- praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
- praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
- praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai/cli/features/doctor/engine.py +266 -0
- praisonai/cli/features/doctor/formatters.py +310 -0
- praisonai/cli/features/doctor/handler.py +397 -0
- praisonai/cli/features/doctor/models.py +264 -0
- praisonai/cli/features/doctor/registry.py +239 -0
- praisonai/cli/features/endpoints.py +1019 -0
- praisonai/cli/features/eval.py +560 -0
- praisonai/cli/features/external_agents.py +231 -0
- praisonai/cli/features/fast_context.py +410 -0
- praisonai/cli/features/flow_display.py +566 -0
- praisonai/cli/features/git_integration.py +651 -0
- praisonai/cli/features/guardrail.py +171 -0
- praisonai/cli/features/handoff.py +185 -0
- praisonai/cli/features/hooks.py +583 -0
- praisonai/cli/features/image.py +384 -0
- praisonai/cli/features/interactive_runtime.py +585 -0
- praisonai/cli/features/interactive_tools.py +380 -0
- praisonai/cli/features/interactive_tui.py +603 -0
- praisonai/cli/features/jobs.py +632 -0
- praisonai/cli/features/knowledge.py +531 -0
- praisonai/cli/features/lite.py +244 -0
- praisonai/cli/features/lsp_cli.py +225 -0
- praisonai/cli/features/mcp.py +169 -0
- praisonai/cli/features/message_queue.py +587 -0
- praisonai/cli/features/metrics.py +211 -0
- praisonai/cli/features/n8n.py +673 -0
- praisonai/cli/features/observability.py +293 -0
- praisonai/cli/features/ollama.py +361 -0
- praisonai/cli/features/output_style.py +273 -0
- praisonai/cli/features/package.py +631 -0
- praisonai/cli/features/performance.py +308 -0
- praisonai/cli/features/persistence.py +636 -0
- praisonai/cli/features/profile.py +226 -0
- praisonai/cli/features/profiler/__init__.py +81 -0
- praisonai/cli/features/profiler/core.py +558 -0
- praisonai/cli/features/profiler/optimizations.py +652 -0
- praisonai/cli/features/profiler/suite.py +386 -0
- praisonai/cli/features/profiling.py +350 -0
- praisonai/cli/features/queue/__init__.py +73 -0
- praisonai/cli/features/queue/manager.py +395 -0
- praisonai/cli/features/queue/models.py +286 -0
- praisonai/cli/features/queue/persistence.py +564 -0
- praisonai/cli/features/queue/scheduler.py +484 -0
- praisonai/cli/features/queue/worker.py +372 -0
- praisonai/cli/features/recipe.py +1723 -0
- praisonai/cli/features/recipes.py +449 -0
- praisonai/cli/features/registry.py +229 -0
- praisonai/cli/features/repo_map.py +860 -0
- praisonai/cli/features/router.py +466 -0
- praisonai/cli/features/sandbox_executor.py +515 -0
- praisonai/cli/features/serve.py +829 -0
- praisonai/cli/features/session.py +222 -0
- praisonai/cli/features/skills.py +856 -0
- praisonai/cli/features/slash_commands.py +650 -0
- praisonai/cli/features/telemetry.py +179 -0
- praisonai/cli/features/templates.py +1384 -0
- praisonai/cli/features/thinking.py +305 -0
- praisonai/cli/features/todo.py +334 -0
- praisonai/cli/features/tools.py +680 -0
- praisonai/cli/features/tui/__init__.py +83 -0
- praisonai/cli/features/tui/app.py +580 -0
- praisonai/cli/features/tui/cli.py +566 -0
- praisonai/cli/features/tui/debug.py +511 -0
- praisonai/cli/features/tui/events.py +99 -0
- praisonai/cli/features/tui/mock_provider.py +328 -0
- praisonai/cli/features/tui/orchestrator.py +652 -0
- praisonai/cli/features/tui/screens/__init__.py +50 -0
- praisonai/cli/features/tui/screens/main.py +245 -0
- praisonai/cli/features/tui/screens/queue.py +174 -0
- praisonai/cli/features/tui/screens/session.py +124 -0
- praisonai/cli/features/tui/screens/settings.py +148 -0
- praisonai/cli/features/tui/widgets/__init__.py +56 -0
- praisonai/cli/features/tui/widgets/chat.py +261 -0
- praisonai/cli/features/tui/widgets/composer.py +224 -0
- praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
- praisonai/cli/features/tui/widgets/status.py +167 -0
- praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
- praisonai/cli/features/workflow.py +720 -0
- praisonai/cli/legacy.py +236 -0
- praisonai/cli/main.py +5559 -0
- praisonai/cli/schedule_cli.py +54 -0
- praisonai/cli/state/__init__.py +31 -0
- praisonai/cli/state/identifiers.py +161 -0
- praisonai/cli/state/sessions.py +313 -0
- praisonai/code/__init__.py +93 -0
- praisonai/code/agent_tools.py +344 -0
- praisonai/code/diff/__init__.py +21 -0
- praisonai/code/diff/diff_strategy.py +432 -0
- praisonai/code/tools/__init__.py +27 -0
- praisonai/code/tools/apply_diff.py +221 -0
- praisonai/code/tools/execute_command.py +275 -0
- praisonai/code/tools/list_files.py +274 -0
- praisonai/code/tools/read_file.py +206 -0
- praisonai/code/tools/search_replace.py +248 -0
- praisonai/code/tools/write_file.py +217 -0
- praisonai/code/utils/__init__.py +46 -0
- praisonai/code/utils/file_utils.py +307 -0
- praisonai/code/utils/ignore_utils.py +308 -0
- praisonai/code/utils/text_utils.py +276 -0
- praisonai/db/__init__.py +64 -0
- praisonai/db/adapter.py +531 -0
- praisonai/deploy/__init__.py +62 -0
- praisonai/deploy/api.py +231 -0
- praisonai/deploy/docker.py +454 -0
- praisonai/deploy/doctor.py +367 -0
- praisonai/deploy/main.py +327 -0
- praisonai/deploy/models.py +179 -0
- praisonai/deploy/providers/__init__.py +33 -0
- praisonai/deploy/providers/aws.py +331 -0
- praisonai/deploy/providers/azure.py +358 -0
- praisonai/deploy/providers/base.py +101 -0
- praisonai/deploy/providers/gcp.py +314 -0
- praisonai/deploy/schema.py +208 -0
- praisonai/deploy.py +185 -0
- praisonai/endpoints/__init__.py +53 -0
- praisonai/endpoints/a2u_server.py +410 -0
- praisonai/endpoints/discovery.py +165 -0
- praisonai/endpoints/providers/__init__.py +28 -0
- praisonai/endpoints/providers/a2a.py +253 -0
- praisonai/endpoints/providers/a2u.py +208 -0
- praisonai/endpoints/providers/agents_api.py +171 -0
- praisonai/endpoints/providers/base.py +231 -0
- praisonai/endpoints/providers/mcp.py +263 -0
- praisonai/endpoints/providers/recipe.py +206 -0
- praisonai/endpoints/providers/tools_mcp.py +150 -0
- praisonai/endpoints/registry.py +131 -0
- praisonai/endpoints/server.py +161 -0
- praisonai/inbuilt_tools/__init__.py +24 -0
- praisonai/inbuilt_tools/autogen_tools.py +117 -0
- praisonai/inc/__init__.py +2 -0
- praisonai/inc/config.py +96 -0
- praisonai/inc/models.py +155 -0
- praisonai/integrations/__init__.py +56 -0
- praisonai/integrations/base.py +303 -0
- praisonai/integrations/claude_code.py +270 -0
- praisonai/integrations/codex_cli.py +255 -0
- praisonai/integrations/cursor_cli.py +195 -0
- praisonai/integrations/gemini_cli.py +222 -0
- praisonai/jobs/__init__.py +67 -0
- praisonai/jobs/executor.py +425 -0
- praisonai/jobs/models.py +230 -0
- praisonai/jobs/router.py +314 -0
- praisonai/jobs/server.py +186 -0
- praisonai/jobs/store.py +203 -0
- praisonai/llm/__init__.py +66 -0
- praisonai/llm/registry.py +382 -0
- praisonai/mcp_server/__init__.py +152 -0
- praisonai/mcp_server/adapters/__init__.py +74 -0
- praisonai/mcp_server/adapters/agents.py +128 -0
- praisonai/mcp_server/adapters/capabilities.py +168 -0
- praisonai/mcp_server/adapters/cli_tools.py +568 -0
- praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
- praisonai/mcp_server/adapters/knowledge.py +93 -0
- praisonai/mcp_server/adapters/memory.py +104 -0
- praisonai/mcp_server/adapters/prompts.py +306 -0
- praisonai/mcp_server/adapters/resources.py +124 -0
- praisonai/mcp_server/adapters/tools_bridge.py +280 -0
- praisonai/mcp_server/auth/__init__.py +48 -0
- praisonai/mcp_server/auth/api_key.py +291 -0
- praisonai/mcp_server/auth/oauth.py +460 -0
- praisonai/mcp_server/auth/oidc.py +289 -0
- praisonai/mcp_server/auth/scopes.py +260 -0
- praisonai/mcp_server/cli.py +852 -0
- praisonai/mcp_server/elicitation.py +445 -0
- praisonai/mcp_server/icons.py +302 -0
- praisonai/mcp_server/recipe_adapter.py +573 -0
- praisonai/mcp_server/recipe_cli.py +824 -0
- praisonai/mcp_server/registry.py +703 -0
- praisonai/mcp_server/sampling.py +422 -0
- praisonai/mcp_server/server.py +490 -0
- praisonai/mcp_server/tasks.py +443 -0
- praisonai/mcp_server/transports/__init__.py +18 -0
- praisonai/mcp_server/transports/http_stream.py +376 -0
- praisonai/mcp_server/transports/stdio.py +132 -0
- praisonai/persistence/__init__.py +84 -0
- praisonai/persistence/config.py +238 -0
- praisonai/persistence/conversation/__init__.py +25 -0
- praisonai/persistence/conversation/async_mysql.py +427 -0
- praisonai/persistence/conversation/async_postgres.py +410 -0
- praisonai/persistence/conversation/async_sqlite.py +371 -0
- praisonai/persistence/conversation/base.py +151 -0
- praisonai/persistence/conversation/json_store.py +250 -0
- praisonai/persistence/conversation/mysql.py +387 -0
- praisonai/persistence/conversation/postgres.py +401 -0
- praisonai/persistence/conversation/singlestore.py +240 -0
- praisonai/persistence/conversation/sqlite.py +341 -0
- praisonai/persistence/conversation/supabase.py +203 -0
- praisonai/persistence/conversation/surrealdb.py +287 -0
- praisonai/persistence/factory.py +301 -0
- praisonai/persistence/hooks/__init__.py +18 -0
- praisonai/persistence/hooks/agent_hooks.py +297 -0
- praisonai/persistence/knowledge/__init__.py +26 -0
- praisonai/persistence/knowledge/base.py +144 -0
- praisonai/persistence/knowledge/cassandra.py +232 -0
- praisonai/persistence/knowledge/chroma.py +295 -0
- praisonai/persistence/knowledge/clickhouse.py +242 -0
- praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
- praisonai/persistence/knowledge/couchbase.py +286 -0
- praisonai/persistence/knowledge/lancedb.py +216 -0
- praisonai/persistence/knowledge/langchain_adapter.py +291 -0
- praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
- praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
- praisonai/persistence/knowledge/milvus.py +277 -0
- praisonai/persistence/knowledge/mongodb_vector.py +306 -0
- praisonai/persistence/knowledge/pgvector.py +335 -0
- praisonai/persistence/knowledge/pinecone.py +253 -0
- praisonai/persistence/knowledge/qdrant.py +301 -0
- praisonai/persistence/knowledge/redis_vector.py +291 -0
- praisonai/persistence/knowledge/singlestore_vector.py +299 -0
- praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
- praisonai/persistence/knowledge/upstash_vector.py +266 -0
- praisonai/persistence/knowledge/weaviate.py +223 -0
- praisonai/persistence/migrations/__init__.py +10 -0
- praisonai/persistence/migrations/manager.py +251 -0
- praisonai/persistence/orchestrator.py +406 -0
- praisonai/persistence/state/__init__.py +21 -0
- praisonai/persistence/state/async_mongodb.py +200 -0
- praisonai/persistence/state/base.py +107 -0
- praisonai/persistence/state/dynamodb.py +226 -0
- praisonai/persistence/state/firestore.py +175 -0
- praisonai/persistence/state/gcs.py +155 -0
- praisonai/persistence/state/memory.py +245 -0
- praisonai/persistence/state/mongodb.py +158 -0
- praisonai/persistence/state/redis.py +190 -0
- praisonai/persistence/state/upstash.py +144 -0
- praisonai/persistence/tests/__init__.py +3 -0
- praisonai/persistence/tests/test_all_backends.py +633 -0
- praisonai/profiler.py +1214 -0
- praisonai/recipe/__init__.py +134 -0
- praisonai/recipe/bridge.py +278 -0
- praisonai/recipe/core.py +893 -0
- praisonai/recipe/exceptions.py +54 -0
- praisonai/recipe/history.py +402 -0
- praisonai/recipe/models.py +266 -0
- praisonai/recipe/operations.py +440 -0
- praisonai/recipe/policy.py +422 -0
- praisonai/recipe/registry.py +849 -0
- praisonai/recipe/runtime.py +214 -0
- praisonai/recipe/security.py +711 -0
- praisonai/recipe/serve.py +859 -0
- praisonai/recipe/server.py +613 -0
- praisonai/scheduler/__init__.py +45 -0
- praisonai/scheduler/agent_scheduler.py +552 -0
- praisonai/scheduler/base.py +124 -0
- praisonai/scheduler/daemon_manager.py +225 -0
- praisonai/scheduler/state_manager.py +155 -0
- praisonai/scheduler/yaml_loader.py +193 -0
- praisonai/scheduler.py +194 -0
- praisonai/setup/__init__.py +1 -0
- praisonai/setup/build.py +21 -0
- praisonai/setup/post_install.py +23 -0
- praisonai/setup/setup_conda_env.py +25 -0
- praisonai/setup.py +16 -0
- praisonai/templates/__init__.py +116 -0
- praisonai/templates/cache.py +364 -0
- praisonai/templates/dependency_checker.py +358 -0
- praisonai/templates/discovery.py +391 -0
- praisonai/templates/loader.py +564 -0
- praisonai/templates/registry.py +511 -0
- praisonai/templates/resolver.py +206 -0
- praisonai/templates/security.py +327 -0
- praisonai/templates/tool_override.py +498 -0
- praisonai/templates/tools_doctor.py +256 -0
- praisonai/test.py +105 -0
- praisonai/train.py +562 -0
- praisonai/train_vision.py +306 -0
- praisonai/ui/agents.py +824 -0
- praisonai/ui/callbacks.py +57 -0
- praisonai/ui/chainlit_compat.py +246 -0
- praisonai/ui/chat.py +532 -0
- praisonai/ui/code.py +717 -0
- praisonai/ui/colab.py +474 -0
- praisonai/ui/colab_chainlit.py +81 -0
- praisonai/ui/components/aicoder.py +284 -0
- praisonai/ui/context.py +283 -0
- praisonai/ui/database_config.py +56 -0
- praisonai/ui/db.py +294 -0
- praisonai/ui/realtime.py +488 -0
- praisonai/ui/realtimeclient/__init__.py +756 -0
- praisonai/ui/realtimeclient/tools.py +242 -0
- praisonai/ui/sql_alchemy.py +710 -0
- praisonai/upload_vision.py +140 -0
- praisonai/version.py +1 -0
- praisonai-3.0.0.dist-info/METADATA +3493 -0
- praisonai-3.0.0.dist-info/RECORD +393 -0
- praisonai-3.0.0.dist-info/WHEEL +5 -0
- praisonai-3.0.0.dist-info/entry_points.txt +4 -0
- praisonai-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TUI Widgets for PraisonAI.
|
|
3
|
+
|
|
4
|
+
Reusable UI components for the TUI application.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from .chat import ChatWidget
|
|
11
|
+
from .composer import ComposerWidget
|
|
12
|
+
from .status import StatusWidget
|
|
13
|
+
from .queue_panel import QueuePanelWidget
|
|
14
|
+
from .tool_panel import ToolPanelWidget
|
|
15
|
+
|
|
16
|
+
_lazy_cache = {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def __getattr__(name: str):
|
|
20
|
+
"""Lazy load widgets."""
|
|
21
|
+
global _lazy_cache
|
|
22
|
+
|
|
23
|
+
if name in _lazy_cache:
|
|
24
|
+
return _lazy_cache[name]
|
|
25
|
+
|
|
26
|
+
if name == "ChatWidget":
|
|
27
|
+
from .chat import ChatWidget
|
|
28
|
+
_lazy_cache[name] = ChatWidget
|
|
29
|
+
return ChatWidget
|
|
30
|
+
elif name == "ComposerWidget":
|
|
31
|
+
from .composer import ComposerWidget
|
|
32
|
+
_lazy_cache[name] = ComposerWidget
|
|
33
|
+
return ComposerWidget
|
|
34
|
+
elif name == "StatusWidget":
|
|
35
|
+
from .status import StatusWidget
|
|
36
|
+
_lazy_cache[name] = StatusWidget
|
|
37
|
+
return StatusWidget
|
|
38
|
+
elif name == "QueuePanelWidget":
|
|
39
|
+
from .queue_panel import QueuePanelWidget
|
|
40
|
+
_lazy_cache[name] = QueuePanelWidget
|
|
41
|
+
return QueuePanelWidget
|
|
42
|
+
elif name == "ToolPanelWidget":
|
|
43
|
+
from .tool_panel import ToolPanelWidget
|
|
44
|
+
_lazy_cache[name] = ToolPanelWidget
|
|
45
|
+
return ToolPanelWidget
|
|
46
|
+
|
|
47
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
"ChatWidget",
|
|
52
|
+
"ComposerWidget",
|
|
53
|
+
"StatusWidget",
|
|
54
|
+
"QueuePanelWidget",
|
|
55
|
+
"ToolPanelWidget",
|
|
56
|
+
]
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Chat Widget for PraisonAI TUI.
|
|
3
|
+
|
|
4
|
+
Displays chat history with streaming support.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List, Optional
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
import time
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from textual.widget import Widget
|
|
13
|
+
from textual.widgets import Static, RichLog
|
|
14
|
+
from textual.containers import ScrollableContainer, Vertical
|
|
15
|
+
from textual.reactive import reactive
|
|
16
|
+
from textual.message import Message
|
|
17
|
+
from rich.markdown import Markdown
|
|
18
|
+
from rich.panel import Panel
|
|
19
|
+
from rich.text import Text
|
|
20
|
+
TEXTUAL_AVAILABLE = True
|
|
21
|
+
except ImportError:
|
|
22
|
+
TEXTUAL_AVAILABLE = False
|
|
23
|
+
Widget = object
|
|
24
|
+
Message = object
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class ChatMessage:
|
|
29
|
+
"""A single chat message."""
|
|
30
|
+
role: str # "user", "assistant", "system", "tool"
|
|
31
|
+
content: str
|
|
32
|
+
timestamp: float = field(default_factory=time.time)
|
|
33
|
+
run_id: Optional[str] = None
|
|
34
|
+
agent_name: Optional[str] = None
|
|
35
|
+
is_streaming: bool = False
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def display_role(self) -> str:
|
|
39
|
+
"""Get display name for role."""
|
|
40
|
+
if self.role == "user":
|
|
41
|
+
return "You"
|
|
42
|
+
elif self.role == "assistant":
|
|
43
|
+
return self.agent_name or "Assistant"
|
|
44
|
+
elif self.role == "system":
|
|
45
|
+
return "System"
|
|
46
|
+
elif self.role == "tool":
|
|
47
|
+
return "Tool"
|
|
48
|
+
return self.role.title()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if TEXTUAL_AVAILABLE:
|
|
52
|
+
class ChatWidget(ScrollableContainer):
|
|
53
|
+
"""
|
|
54
|
+
Widget for displaying chat history.
|
|
55
|
+
|
|
56
|
+
Features:
|
|
57
|
+
- Streaming message updates
|
|
58
|
+
- Markdown rendering
|
|
59
|
+
- Auto-scroll to bottom
|
|
60
|
+
- Message history management
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
DEFAULT_CSS = """
|
|
64
|
+
ChatWidget {
|
|
65
|
+
height: 100%;
|
|
66
|
+
border: solid $primary;
|
|
67
|
+
background: $surface;
|
|
68
|
+
padding: 0 1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
ChatWidget .message-user {
|
|
72
|
+
background: $primary-darken-2;
|
|
73
|
+
margin: 1 0;
|
|
74
|
+
padding: 1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
ChatWidget .message-assistant {
|
|
78
|
+
background: $surface-darken-1;
|
|
79
|
+
margin: 1 0;
|
|
80
|
+
padding: 1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ChatWidget .message-system {
|
|
84
|
+
background: $warning-darken-3;
|
|
85
|
+
margin: 1 0;
|
|
86
|
+
padding: 1;
|
|
87
|
+
color: $text-muted;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
ChatWidget .message-streaming {
|
|
91
|
+
border: dashed $accent;
|
|
92
|
+
}
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
class MessageAdded(Message):
|
|
96
|
+
"""Event when a message is added."""
|
|
97
|
+
def __init__(self, message: ChatMessage):
|
|
98
|
+
self.message = message
|
|
99
|
+
super().__init__()
|
|
100
|
+
|
|
101
|
+
class StreamingUpdate(Message):
|
|
102
|
+
"""Event when streaming content updates."""
|
|
103
|
+
def __init__(self, run_id: str, content: str):
|
|
104
|
+
self.run_id = run_id
|
|
105
|
+
self.content = content
|
|
106
|
+
super().__init__()
|
|
107
|
+
|
|
108
|
+
def __init__(
|
|
109
|
+
self,
|
|
110
|
+
max_messages: int = 1000,
|
|
111
|
+
name: Optional[str] = None,
|
|
112
|
+
id: Optional[str] = None,
|
|
113
|
+
classes: Optional[str] = None,
|
|
114
|
+
):
|
|
115
|
+
super().__init__(name=name, id=id, classes=classes)
|
|
116
|
+
self._messages: List[ChatMessage] = []
|
|
117
|
+
self._max_messages = max_messages
|
|
118
|
+
self._streaming_widgets: dict = {}
|
|
119
|
+
|
|
120
|
+
def compose(self):
|
|
121
|
+
"""Compose the widget."""
|
|
122
|
+
yield Vertical(id="chat-messages")
|
|
123
|
+
|
|
124
|
+
async def add_message(self, message: ChatMessage) -> None:
|
|
125
|
+
"""Add a message to the chat."""
|
|
126
|
+
self._messages.append(message)
|
|
127
|
+
|
|
128
|
+
# Trim old messages if needed
|
|
129
|
+
if len(self._messages) > self._max_messages:
|
|
130
|
+
self._messages = self._messages[-self._max_messages:]
|
|
131
|
+
|
|
132
|
+
# Create message widget
|
|
133
|
+
await self._render_message(message)
|
|
134
|
+
|
|
135
|
+
# Auto-scroll to bottom
|
|
136
|
+
self.scroll_end(animate=False)
|
|
137
|
+
|
|
138
|
+
self.post_message(self.MessageAdded(message))
|
|
139
|
+
|
|
140
|
+
async def _render_message(self, message: ChatMessage) -> None:
|
|
141
|
+
"""Render a single message."""
|
|
142
|
+
container = self.query_one("#chat-messages", Vertical)
|
|
143
|
+
|
|
144
|
+
# Create role label
|
|
145
|
+
role_style = {
|
|
146
|
+
"user": "bold cyan",
|
|
147
|
+
"assistant": "bold green",
|
|
148
|
+
"system": "bold yellow",
|
|
149
|
+
"tool": "bold magenta",
|
|
150
|
+
}.get(message.role, "bold")
|
|
151
|
+
|
|
152
|
+
role_text = Text(f"{message.display_role}:", style=role_style)
|
|
153
|
+
|
|
154
|
+
# Create content
|
|
155
|
+
try:
|
|
156
|
+
content = Markdown(message.content)
|
|
157
|
+
except Exception:
|
|
158
|
+
content = Text(message.content)
|
|
159
|
+
|
|
160
|
+
# Create panel
|
|
161
|
+
css_class = f"message-{message.role}"
|
|
162
|
+
if message.is_streaming:
|
|
163
|
+
css_class += " message-streaming"
|
|
164
|
+
|
|
165
|
+
widget_id = f"msg-{message.run_id or id(message)}"
|
|
166
|
+
|
|
167
|
+
panel = Static(
|
|
168
|
+
Panel(content, title=str(role_text), border_style=role_style),
|
|
169
|
+
id=widget_id,
|
|
170
|
+
classes=css_class,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
await container.mount(panel)
|
|
174
|
+
|
|
175
|
+
if message.is_streaming:
|
|
176
|
+
self._streaming_widgets[message.run_id] = widget_id
|
|
177
|
+
|
|
178
|
+
async def update_streaming(self, run_id: str, content: str) -> None:
|
|
179
|
+
"""Update a streaming message."""
|
|
180
|
+
if run_id not in self._streaming_widgets:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
widget_id = self._streaming_widgets[run_id]
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
widget = self.query_one(f"#{widget_id}", Static)
|
|
187
|
+
|
|
188
|
+
# Find the message
|
|
189
|
+
for msg in self._messages:
|
|
190
|
+
if msg.run_id == run_id:
|
|
191
|
+
msg.content = content
|
|
192
|
+
break
|
|
193
|
+
|
|
194
|
+
# Update content
|
|
195
|
+
try:
|
|
196
|
+
rendered = Markdown(content + " ▌")
|
|
197
|
+
except Exception:
|
|
198
|
+
rendered = Text(content + " ▌")
|
|
199
|
+
|
|
200
|
+
widget.update(Panel(rendered, title="Assistant", border_style="bold green"))
|
|
201
|
+
|
|
202
|
+
# Auto-scroll
|
|
203
|
+
self.scroll_end(animate=False)
|
|
204
|
+
|
|
205
|
+
except Exception:
|
|
206
|
+
pass
|
|
207
|
+
|
|
208
|
+
async def complete_streaming(self, run_id: str, final_content: str) -> None:
|
|
209
|
+
"""Complete a streaming message."""
|
|
210
|
+
if run_id not in self._streaming_widgets:
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
widget_id = self._streaming_widgets.pop(run_id)
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
widget = self.query_one(f"#{widget_id}", Static)
|
|
217
|
+
|
|
218
|
+
# Update message
|
|
219
|
+
for msg in self._messages:
|
|
220
|
+
if msg.run_id == run_id:
|
|
221
|
+
msg.content = final_content
|
|
222
|
+
msg.is_streaming = False
|
|
223
|
+
break
|
|
224
|
+
|
|
225
|
+
# Update content without cursor
|
|
226
|
+
try:
|
|
227
|
+
rendered = Markdown(final_content)
|
|
228
|
+
except Exception:
|
|
229
|
+
rendered = Text(final_content)
|
|
230
|
+
|
|
231
|
+
widget.update(Panel(rendered, title="Assistant", border_style="bold green"))
|
|
232
|
+
widget.remove_class("message-streaming")
|
|
233
|
+
|
|
234
|
+
except Exception:
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
async def clear(self) -> None:
|
|
238
|
+
"""Clear all messages."""
|
|
239
|
+
self._messages.clear()
|
|
240
|
+
self._streaming_widgets.clear()
|
|
241
|
+
|
|
242
|
+
container = self.query_one("#chat-messages", Vertical)
|
|
243
|
+
await container.remove_children()
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def messages(self) -> List[ChatMessage]:
|
|
247
|
+
"""Get all messages."""
|
|
248
|
+
return self._messages.copy()
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def message_count(self) -> int:
|
|
252
|
+
"""Get message count."""
|
|
253
|
+
return len(self._messages)
|
|
254
|
+
|
|
255
|
+
else:
|
|
256
|
+
class ChatWidget:
|
|
257
|
+
"""Placeholder when Textual is not available."""
|
|
258
|
+
def __init__(self, *args, **kwargs):
|
|
259
|
+
raise ImportError(
|
|
260
|
+
"Textual is required for TUI. Install with: pip install praisonai[tui]"
|
|
261
|
+
)
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Composer Widget for PraisonAI TUI.
|
|
3
|
+
|
|
4
|
+
Input area for composing messages with slash command support.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Callable, List, Optional
|
|
8
|
+
import asyncio
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
from textual.widget import Widget
|
|
12
|
+
from textual.widgets import TextArea, Input
|
|
13
|
+
from textual.containers import Horizontal, Vertical
|
|
14
|
+
from textual.message import Message
|
|
15
|
+
from textual.binding import Binding
|
|
16
|
+
from textual import events
|
|
17
|
+
from rich.text import Text
|
|
18
|
+
TEXTUAL_AVAILABLE = True
|
|
19
|
+
except ImportError:
|
|
20
|
+
TEXTUAL_AVAILABLE = False
|
|
21
|
+
Widget = object
|
|
22
|
+
Message = object
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if TEXTUAL_AVAILABLE:
|
|
26
|
+
class ComposerWidget(Vertical):
|
|
27
|
+
"""
|
|
28
|
+
Input composer for chat messages.
|
|
29
|
+
|
|
30
|
+
Features:
|
|
31
|
+
- Multi-line input
|
|
32
|
+
- Slash command detection
|
|
33
|
+
- @ mention support
|
|
34
|
+
- History navigation
|
|
35
|
+
- Send on Enter or Ctrl+Enter
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
BINDINGS = [
|
|
39
|
+
Binding("ctrl+enter", "submit", "Send", show=True),
|
|
40
|
+
Binding("escape", "cancel", "Cancel", show=False),
|
|
41
|
+
Binding("up", "history_prev", "Previous", show=False),
|
|
42
|
+
Binding("down", "history_next", "Next", show=False),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
DEFAULT_CSS = """
|
|
46
|
+
ComposerWidget {
|
|
47
|
+
height: auto;
|
|
48
|
+
max-height: 10;
|
|
49
|
+
border: solid $primary;
|
|
50
|
+
background: $surface;
|
|
51
|
+
padding: 0 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
ComposerWidget TextArea {
|
|
55
|
+
height: auto;
|
|
56
|
+
min-height: 3;
|
|
57
|
+
max-height: 8;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
ComposerWidget .hint {
|
|
61
|
+
color: $text-muted;
|
|
62
|
+
text-style: italic;
|
|
63
|
+
}
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
class Submitted(Message):
|
|
67
|
+
"""Event when message is submitted."""
|
|
68
|
+
def __init__(self, content: str, is_command: bool = False):
|
|
69
|
+
self.content = content
|
|
70
|
+
self.is_command = is_command
|
|
71
|
+
super().__init__()
|
|
72
|
+
|
|
73
|
+
class CommandDetected(Message):
|
|
74
|
+
"""Event when a slash command is detected."""
|
|
75
|
+
def __init__(self, command: str, args: str):
|
|
76
|
+
self.command = command
|
|
77
|
+
self.args = args
|
|
78
|
+
super().__init__()
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
placeholder: str = "Type your message... (Ctrl+Enter to send, /help for commands)",
|
|
83
|
+
multiline: bool = True,
|
|
84
|
+
name: Optional[str] = None,
|
|
85
|
+
id: Optional[str] = None,
|
|
86
|
+
classes: Optional[str] = None,
|
|
87
|
+
):
|
|
88
|
+
super().__init__(name=name, id=id, classes=classes)
|
|
89
|
+
self._placeholder = placeholder
|
|
90
|
+
self._multiline = multiline
|
|
91
|
+
self._history: List[str] = []
|
|
92
|
+
self._history_index = -1
|
|
93
|
+
self._current_input = ""
|
|
94
|
+
self._is_processing = False
|
|
95
|
+
|
|
96
|
+
def compose(self):
|
|
97
|
+
"""Compose the widget."""
|
|
98
|
+
yield TextArea(
|
|
99
|
+
"",
|
|
100
|
+
id="composer-input",
|
|
101
|
+
language=None,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def on_mount(self) -> None:
|
|
105
|
+
"""Handle mount event."""
|
|
106
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
107
|
+
text_area.focus()
|
|
108
|
+
|
|
109
|
+
async def on_text_area_changed(self, event: TextArea.Changed) -> None:
|
|
110
|
+
"""Handle text changes."""
|
|
111
|
+
content = event.text_area.text
|
|
112
|
+
|
|
113
|
+
# Detect slash commands
|
|
114
|
+
if content.startswith("/"):
|
|
115
|
+
parts = content[1:].split(maxsplit=1)
|
|
116
|
+
if parts:
|
|
117
|
+
command = parts[0]
|
|
118
|
+
args = parts[1] if len(parts) > 1 else ""
|
|
119
|
+
self.post_message(self.CommandDetected(command, args))
|
|
120
|
+
|
|
121
|
+
def on_key(self, event: events.Key) -> None:
|
|
122
|
+
"""Handle key events."""
|
|
123
|
+
# Submit on Enter (single line mode) or Ctrl+Enter
|
|
124
|
+
if event.key == "enter" and not self._multiline:
|
|
125
|
+
event.prevent_default()
|
|
126
|
+
self.action_submit()
|
|
127
|
+
elif event.key == "ctrl+enter":
|
|
128
|
+
event.prevent_default()
|
|
129
|
+
self.action_submit()
|
|
130
|
+
|
|
131
|
+
def action_submit(self) -> None:
|
|
132
|
+
"""Submit the current input."""
|
|
133
|
+
if self._is_processing:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
137
|
+
content = text_area.text.strip()
|
|
138
|
+
|
|
139
|
+
if not content:
|
|
140
|
+
return
|
|
141
|
+
|
|
142
|
+
# Add to history
|
|
143
|
+
if content and (not self._history or self._history[-1] != content):
|
|
144
|
+
self._history.append(content)
|
|
145
|
+
self._history_index = -1
|
|
146
|
+
|
|
147
|
+
# Check if it's a command
|
|
148
|
+
is_command = content.startswith("/")
|
|
149
|
+
|
|
150
|
+
# Clear input
|
|
151
|
+
text_area.clear()
|
|
152
|
+
|
|
153
|
+
# Emit event
|
|
154
|
+
self.post_message(self.Submitted(content, is_command))
|
|
155
|
+
|
|
156
|
+
def action_cancel(self) -> None:
|
|
157
|
+
"""Cancel current input."""
|
|
158
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
159
|
+
text_area.clear()
|
|
160
|
+
self._history_index = -1
|
|
161
|
+
|
|
162
|
+
def action_history_prev(self) -> None:
|
|
163
|
+
"""Navigate to previous history item."""
|
|
164
|
+
if not self._history:
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
168
|
+
|
|
169
|
+
if self._history_index == -1:
|
|
170
|
+
self._current_input = text_area.text
|
|
171
|
+
self._history_index = len(self._history) - 1
|
|
172
|
+
elif self._history_index > 0:
|
|
173
|
+
self._history_index -= 1
|
|
174
|
+
|
|
175
|
+
text_area.clear()
|
|
176
|
+
text_area.insert(self._history[self._history_index])
|
|
177
|
+
|
|
178
|
+
def action_history_next(self) -> None:
|
|
179
|
+
"""Navigate to next history item."""
|
|
180
|
+
if self._history_index == -1:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
184
|
+
|
|
185
|
+
if self._history_index < len(self._history) - 1:
|
|
186
|
+
self._history_index += 1
|
|
187
|
+
text_area.clear()
|
|
188
|
+
text_area.insert(self._history[self._history_index])
|
|
189
|
+
else:
|
|
190
|
+
self._history_index = -1
|
|
191
|
+
text_area.clear()
|
|
192
|
+
text_area.insert(self._current_input)
|
|
193
|
+
|
|
194
|
+
def set_processing(self, processing: bool) -> None:
|
|
195
|
+
"""Set processing state."""
|
|
196
|
+
self._is_processing = processing
|
|
197
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
198
|
+
text_area.disabled = processing
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def text(self) -> str:
|
|
202
|
+
"""Get current text."""
|
|
203
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
204
|
+
return text_area.text
|
|
205
|
+
|
|
206
|
+
@text.setter
|
|
207
|
+
def text(self, value: str) -> None:
|
|
208
|
+
"""Set current text."""
|
|
209
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
210
|
+
text_area.clear()
|
|
211
|
+
text_area.insert(value)
|
|
212
|
+
|
|
213
|
+
def focus_input(self) -> None:
|
|
214
|
+
"""Focus the input area."""
|
|
215
|
+
text_area = self.query_one("#composer-input", TextArea)
|
|
216
|
+
text_area.focus()
|
|
217
|
+
|
|
218
|
+
else:
|
|
219
|
+
class ComposerWidget:
|
|
220
|
+
"""Placeholder when Textual is not available."""
|
|
221
|
+
def __init__(self, *args, **kwargs):
|
|
222
|
+
raise ImportError(
|
|
223
|
+
"Textual is required for TUI. Install with: pip install praisonai[tui]"
|
|
224
|
+
)
|