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,585 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Interactive Runtime for PraisonAI.
|
|
3
|
+
|
|
4
|
+
Provides the core runtime that powers both TUI interactive mode and debug non-interactive mode.
|
|
5
|
+
Manages LSP and ACP subsystem lifecycle with graceful degradation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
import time
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SubsystemStatus(Enum):
|
|
20
|
+
"""Status of a subsystem."""
|
|
21
|
+
NOT_STARTED = "not_started"
|
|
22
|
+
STARTING = "starting"
|
|
23
|
+
READY = "ready"
|
|
24
|
+
FAILED = "failed"
|
|
25
|
+
STOPPED = "stopped"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class SubsystemState:
|
|
30
|
+
"""State of a subsystem."""
|
|
31
|
+
status: SubsystemStatus = SubsystemStatus.NOT_STARTED
|
|
32
|
+
error: Optional[str] = None
|
|
33
|
+
start_time: Optional[float] = None
|
|
34
|
+
ready_time: Optional[float] = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class RuntimeConfig:
|
|
39
|
+
"""Configuration for InteractiveRuntime."""
|
|
40
|
+
workspace: str = "."
|
|
41
|
+
lsp_enabled: bool = True
|
|
42
|
+
acp_enabled: bool = True
|
|
43
|
+
approval_mode: str = "manual" # manual, auto, scoped
|
|
44
|
+
trace_enabled: bool = False
|
|
45
|
+
trace_file: Optional[str] = None
|
|
46
|
+
json_output: bool = False
|
|
47
|
+
timeout: float = 60.0
|
|
48
|
+
model: Optional[str] = None
|
|
49
|
+
verbose: bool = False
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class TraceEntry:
|
|
54
|
+
"""A single trace entry."""
|
|
55
|
+
timestamp: float
|
|
56
|
+
category: str # lsp, acp, tool, llm, file
|
|
57
|
+
action: str
|
|
58
|
+
params: Dict[str, Any] = field(default_factory=dict)
|
|
59
|
+
result: Optional[Any] = None
|
|
60
|
+
duration_ms: Optional[float] = None
|
|
61
|
+
error: Optional[str] = None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass
|
|
65
|
+
class RuntimeTrace:
|
|
66
|
+
"""Trace of a runtime session."""
|
|
67
|
+
version: str = "1.0"
|
|
68
|
+
start_time: float = field(default_factory=time.time)
|
|
69
|
+
end_time: Optional[float] = None
|
|
70
|
+
config: Optional[RuntimeConfig] = None
|
|
71
|
+
entries: List[TraceEntry] = field(default_factory=list)
|
|
72
|
+
|
|
73
|
+
def add_entry(self, category: str, action: str, params: Dict[str, Any] = None,
|
|
74
|
+
result: Any = None, duration_ms: float = None, error: str = None):
|
|
75
|
+
"""Add a trace entry."""
|
|
76
|
+
self.entries.append(TraceEntry(
|
|
77
|
+
timestamp=time.time(),
|
|
78
|
+
category=category,
|
|
79
|
+
action=action,
|
|
80
|
+
params=params or {},
|
|
81
|
+
result=result,
|
|
82
|
+
duration_ms=duration_ms,
|
|
83
|
+
error=error
|
|
84
|
+
))
|
|
85
|
+
|
|
86
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
87
|
+
"""Convert trace to dictionary."""
|
|
88
|
+
return {
|
|
89
|
+
"version": self.version,
|
|
90
|
+
"start_time": self.start_time,
|
|
91
|
+
"end_time": self.end_time,
|
|
92
|
+
"config": {
|
|
93
|
+
"workspace": self.config.workspace if self.config else None,
|
|
94
|
+
"lsp_enabled": self.config.lsp_enabled if self.config else None,
|
|
95
|
+
"acp_enabled": self.config.acp_enabled if self.config else None,
|
|
96
|
+
"approval_mode": self.config.approval_mode if self.config else None,
|
|
97
|
+
} if self.config else None,
|
|
98
|
+
"entries": [
|
|
99
|
+
{
|
|
100
|
+
"timestamp": e.timestamp,
|
|
101
|
+
"category": e.category,
|
|
102
|
+
"action": e.action,
|
|
103
|
+
"params": e.params,
|
|
104
|
+
"result": e.result,
|
|
105
|
+
"duration_ms": e.duration_ms,
|
|
106
|
+
"error": e.error
|
|
107
|
+
}
|
|
108
|
+
for e in self.entries
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class InteractiveRuntime:
|
|
114
|
+
"""
|
|
115
|
+
Core runtime for interactive coding assistant.
|
|
116
|
+
|
|
117
|
+
Manages:
|
|
118
|
+
- LSP subsystem for code intelligence
|
|
119
|
+
- ACP subsystem for action orchestration
|
|
120
|
+
- Trace collection for debugging
|
|
121
|
+
- Graceful degradation when subsystems fail
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
def __init__(self, config: RuntimeConfig = None):
|
|
125
|
+
"""Initialize the runtime."""
|
|
126
|
+
self.config = config or RuntimeConfig()
|
|
127
|
+
self._lsp_state = SubsystemState()
|
|
128
|
+
self._acp_state = SubsystemState()
|
|
129
|
+
self._lsp_client = None
|
|
130
|
+
self._acp_session = None
|
|
131
|
+
self._trace = RuntimeTrace(config=self.config) if self.config.trace_enabled else None
|
|
132
|
+
self._started = False
|
|
133
|
+
self._read_only = False # Enforced when ACP fails
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def lsp_ready(self) -> bool:
|
|
137
|
+
"""Check if LSP is ready."""
|
|
138
|
+
return self._lsp_state.status == SubsystemStatus.READY
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def acp_ready(self) -> bool:
|
|
142
|
+
"""Check if ACP is ready."""
|
|
143
|
+
return self._acp_state.status == SubsystemStatus.READY
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def read_only(self) -> bool:
|
|
147
|
+
"""Check if runtime is in read-only mode."""
|
|
148
|
+
return self._read_only or not self.acp_ready
|
|
149
|
+
|
|
150
|
+
def get_status(self) -> Dict[str, Any]:
|
|
151
|
+
"""Get runtime status."""
|
|
152
|
+
return {
|
|
153
|
+
"started": self._started,
|
|
154
|
+
"workspace": self.config.workspace,
|
|
155
|
+
"lsp": {
|
|
156
|
+
"enabled": self.config.lsp_enabled,
|
|
157
|
+
"status": self._lsp_state.status.value,
|
|
158
|
+
"ready": self.lsp_ready,
|
|
159
|
+
"error": self._lsp_state.error
|
|
160
|
+
},
|
|
161
|
+
"acp": {
|
|
162
|
+
"enabled": self.config.acp_enabled,
|
|
163
|
+
"status": self._acp_state.status.value,
|
|
164
|
+
"ready": self.acp_ready,
|
|
165
|
+
"error": self._acp_state.error
|
|
166
|
+
},
|
|
167
|
+
"read_only": self.read_only,
|
|
168
|
+
"approval_mode": self.config.approval_mode
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async def start(self) -> Dict[str, Any]:
|
|
172
|
+
"""
|
|
173
|
+
Start the runtime and all enabled subsystems.
|
|
174
|
+
|
|
175
|
+
Returns status dict with subsystem states.
|
|
176
|
+
"""
|
|
177
|
+
if self._started:
|
|
178
|
+
return self.get_status()
|
|
179
|
+
|
|
180
|
+
workspace = Path(self.config.workspace).resolve()
|
|
181
|
+
if not workspace.exists():
|
|
182
|
+
workspace.mkdir(parents=True, exist_ok=True)
|
|
183
|
+
|
|
184
|
+
self.config.workspace = str(workspace)
|
|
185
|
+
|
|
186
|
+
# Start subsystems in parallel
|
|
187
|
+
tasks = []
|
|
188
|
+
if self.config.lsp_enabled:
|
|
189
|
+
tasks.append(self._start_lsp())
|
|
190
|
+
if self.config.acp_enabled:
|
|
191
|
+
tasks.append(self._start_acp())
|
|
192
|
+
|
|
193
|
+
if tasks:
|
|
194
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
195
|
+
|
|
196
|
+
# Enforce read-only if ACP failed
|
|
197
|
+
if self.config.acp_enabled and not self.acp_ready:
|
|
198
|
+
self._read_only = True
|
|
199
|
+
logger.warning("ACP unavailable - runtime is READ-ONLY")
|
|
200
|
+
|
|
201
|
+
self._started = True
|
|
202
|
+
|
|
203
|
+
if self._trace:
|
|
204
|
+
self._trace.add_entry(
|
|
205
|
+
category="runtime",
|
|
206
|
+
action="start",
|
|
207
|
+
params={"workspace": self.config.workspace},
|
|
208
|
+
result=self.get_status()
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
return self.get_status()
|
|
212
|
+
|
|
213
|
+
async def _start_lsp(self):
|
|
214
|
+
"""Start LSP subsystem."""
|
|
215
|
+
self._lsp_state.status = SubsystemStatus.STARTING
|
|
216
|
+
self._lsp_state.start_time = time.time()
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
# Lazy import LSP client
|
|
220
|
+
from praisonaiagents.lsp import LSPClient
|
|
221
|
+
|
|
222
|
+
# Detect language from workspace
|
|
223
|
+
language = self._detect_workspace_language()
|
|
224
|
+
|
|
225
|
+
self._lsp_client = LSPClient(
|
|
226
|
+
language=language,
|
|
227
|
+
root_uri=f"file://{self.config.workspace}"
|
|
228
|
+
)
|
|
229
|
+
await self._lsp_client.start()
|
|
230
|
+
|
|
231
|
+
# Wait for initialization
|
|
232
|
+
if self._lsp_client.is_running:
|
|
233
|
+
self._lsp_state.status = SubsystemStatus.READY
|
|
234
|
+
self._lsp_state.ready_time = time.time()
|
|
235
|
+
logger.info(f"LSP ready for {language}")
|
|
236
|
+
else:
|
|
237
|
+
raise RuntimeError("LSP client failed to start")
|
|
238
|
+
|
|
239
|
+
except ImportError as e:
|
|
240
|
+
self._lsp_state.status = SubsystemStatus.FAILED
|
|
241
|
+
self._lsp_state.error = f"LSP module not available: {e}"
|
|
242
|
+
logger.warning(self._lsp_state.error)
|
|
243
|
+
except Exception as e:
|
|
244
|
+
self._lsp_state.status = SubsystemStatus.FAILED
|
|
245
|
+
self._lsp_state.error = str(e)
|
|
246
|
+
logger.warning(f"LSP failed to start: {e}")
|
|
247
|
+
|
|
248
|
+
async def _start_acp(self):
|
|
249
|
+
"""Start ACP subsystem (in-process session)."""
|
|
250
|
+
self._acp_state.status = SubsystemStatus.STARTING
|
|
251
|
+
self._acp_state.start_time = time.time()
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
# Lazy import ACP
|
|
255
|
+
from praisonai.acp.session import ACPSession
|
|
256
|
+
from pathlib import Path
|
|
257
|
+
|
|
258
|
+
# Create a session for the workspace
|
|
259
|
+
self._acp_session = ACPSession.create(
|
|
260
|
+
workspace=Path(self.config.workspace)
|
|
261
|
+
)
|
|
262
|
+
self._acp_session.mode = self.config.approval_mode
|
|
263
|
+
|
|
264
|
+
self._acp_state.status = SubsystemStatus.READY
|
|
265
|
+
self._acp_state.ready_time = time.time()
|
|
266
|
+
logger.info("ACP session ready")
|
|
267
|
+
|
|
268
|
+
except ImportError as e:
|
|
269
|
+
self._acp_state.status = SubsystemStatus.FAILED
|
|
270
|
+
self._acp_state.error = f"ACP module not available: {e}"
|
|
271
|
+
logger.warning(self._acp_state.error)
|
|
272
|
+
except Exception as e:
|
|
273
|
+
self._acp_state.status = SubsystemStatus.FAILED
|
|
274
|
+
self._acp_state.error = str(e)
|
|
275
|
+
logger.warning(f"ACP failed to start: {e}")
|
|
276
|
+
|
|
277
|
+
async def stop(self):
|
|
278
|
+
"""Stop the runtime and all subsystems."""
|
|
279
|
+
if self._lsp_client:
|
|
280
|
+
try:
|
|
281
|
+
await self._lsp_client.stop()
|
|
282
|
+
except Exception as e:
|
|
283
|
+
logger.warning(f"Error stopping LSP: {e}")
|
|
284
|
+
self._lsp_state.status = SubsystemStatus.STOPPED
|
|
285
|
+
|
|
286
|
+
if self._acp_session:
|
|
287
|
+
# ACPSession is a dataclass, no close method needed
|
|
288
|
+
self._acp_session = None
|
|
289
|
+
self._acp_state.status = SubsystemStatus.STOPPED
|
|
290
|
+
|
|
291
|
+
if self._trace:
|
|
292
|
+
self._trace.end_time = time.time()
|
|
293
|
+
self._trace.add_entry(
|
|
294
|
+
category="runtime",
|
|
295
|
+
action="stop",
|
|
296
|
+
result=self.get_status()
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
self._started = False
|
|
300
|
+
|
|
301
|
+
def _detect_workspace_language(self) -> str:
|
|
302
|
+
"""Detect primary language in workspace."""
|
|
303
|
+
workspace = Path(self.config.workspace)
|
|
304
|
+
|
|
305
|
+
# Count files by extension
|
|
306
|
+
extensions = {}
|
|
307
|
+
for ext in [".py", ".js", ".ts", ".tsx", ".jsx", ".go", ".rs", ".java"]:
|
|
308
|
+
count = len(list(workspace.rglob(f"*{ext}")))
|
|
309
|
+
if count > 0:
|
|
310
|
+
extensions[ext] = count
|
|
311
|
+
|
|
312
|
+
if not extensions:
|
|
313
|
+
return "python" # Default
|
|
314
|
+
|
|
315
|
+
# Map extensions to languages
|
|
316
|
+
ext_to_lang = {
|
|
317
|
+
".py": "python",
|
|
318
|
+
".js": "javascript",
|
|
319
|
+
".ts": "typescript",
|
|
320
|
+
".tsx": "typescript",
|
|
321
|
+
".jsx": "javascript",
|
|
322
|
+
".go": "go",
|
|
323
|
+
".rs": "rust",
|
|
324
|
+
".java": "java"
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
# Return language with most files
|
|
328
|
+
top_ext = max(extensions, key=extensions.get)
|
|
329
|
+
return ext_to_lang.get(top_ext, "python")
|
|
330
|
+
|
|
331
|
+
# LSP Operations
|
|
332
|
+
async def lsp_get_symbols(self, file_path: str) -> List[Dict[str, Any]]:
|
|
333
|
+
"""Get symbols in a file via LSP."""
|
|
334
|
+
if not self.lsp_ready:
|
|
335
|
+
return []
|
|
336
|
+
|
|
337
|
+
start = time.time()
|
|
338
|
+
try:
|
|
339
|
+
# Use workspace symbols or document symbols
|
|
340
|
+
result = await self._lsp_client.get_document_symbols(file_path)
|
|
341
|
+
duration = (time.time() - start) * 1000
|
|
342
|
+
|
|
343
|
+
if self._trace:
|
|
344
|
+
self._trace.add_entry(
|
|
345
|
+
category="lsp",
|
|
346
|
+
action="get_symbols",
|
|
347
|
+
params={"file": file_path},
|
|
348
|
+
result={"count": len(result) if result else 0},
|
|
349
|
+
duration_ms=duration
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
return result or []
|
|
353
|
+
except Exception as e:
|
|
354
|
+
if self._trace:
|
|
355
|
+
self._trace.add_entry(
|
|
356
|
+
category="lsp",
|
|
357
|
+
action="get_symbols",
|
|
358
|
+
params={"file": file_path},
|
|
359
|
+
error=str(e)
|
|
360
|
+
)
|
|
361
|
+
return []
|
|
362
|
+
|
|
363
|
+
async def lsp_get_definition(self, file_path: str, line: int, col: int) -> List[Dict[str, Any]]:
|
|
364
|
+
"""Get definition location via LSP."""
|
|
365
|
+
if not self.lsp_ready:
|
|
366
|
+
return []
|
|
367
|
+
|
|
368
|
+
start = time.time()
|
|
369
|
+
try:
|
|
370
|
+
result = await self._lsp_client.get_definition(file_path, line, col)
|
|
371
|
+
duration = (time.time() - start) * 1000
|
|
372
|
+
|
|
373
|
+
if self._trace:
|
|
374
|
+
self._trace.add_entry(
|
|
375
|
+
category="lsp",
|
|
376
|
+
action="get_definition",
|
|
377
|
+
params={"file": file_path, "line": line, "col": col},
|
|
378
|
+
result={"count": len(result) if result else 0},
|
|
379
|
+
duration_ms=duration
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
return [loc.__dict__ if hasattr(loc, '__dict__') else loc for loc in (result or [])]
|
|
383
|
+
except Exception as e:
|
|
384
|
+
if self._trace:
|
|
385
|
+
self._trace.add_entry(
|
|
386
|
+
category="lsp",
|
|
387
|
+
action="get_definition",
|
|
388
|
+
params={"file": file_path, "line": line, "col": col},
|
|
389
|
+
error=str(e)
|
|
390
|
+
)
|
|
391
|
+
return []
|
|
392
|
+
|
|
393
|
+
async def lsp_get_references(self, file_path: str, line: int, col: int) -> List[Dict[str, Any]]:
|
|
394
|
+
"""Get references via LSP."""
|
|
395
|
+
if not self.lsp_ready:
|
|
396
|
+
return []
|
|
397
|
+
|
|
398
|
+
start = time.time()
|
|
399
|
+
try:
|
|
400
|
+
result = await self._lsp_client.get_references(file_path, line, col)
|
|
401
|
+
duration = (time.time() - start) * 1000
|
|
402
|
+
|
|
403
|
+
if self._trace:
|
|
404
|
+
self._trace.add_entry(
|
|
405
|
+
category="lsp",
|
|
406
|
+
action="get_references",
|
|
407
|
+
params={"file": file_path, "line": line, "col": col},
|
|
408
|
+
result={"count": len(result) if result else 0},
|
|
409
|
+
duration_ms=duration
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
return [loc.__dict__ if hasattr(loc, '__dict__') else loc for loc in (result or [])]
|
|
413
|
+
except Exception as e:
|
|
414
|
+
if self._trace:
|
|
415
|
+
self._trace.add_entry(
|
|
416
|
+
category="lsp",
|
|
417
|
+
action="get_references",
|
|
418
|
+
params={"file": file_path, "line": line, "col": col},
|
|
419
|
+
error=str(e)
|
|
420
|
+
)
|
|
421
|
+
return []
|
|
422
|
+
|
|
423
|
+
async def lsp_get_diagnostics(self, file_path: str = None) -> List[Dict[str, Any]]:
|
|
424
|
+
"""Get diagnostics via LSP."""
|
|
425
|
+
if not self.lsp_ready:
|
|
426
|
+
return []
|
|
427
|
+
|
|
428
|
+
start = time.time()
|
|
429
|
+
try:
|
|
430
|
+
if file_path:
|
|
431
|
+
result = await self._lsp_client.get_diagnostics(file_path)
|
|
432
|
+
else:
|
|
433
|
+
result = self._lsp_client._diagnostics # All cached diagnostics
|
|
434
|
+
duration = (time.time() - start) * 1000
|
|
435
|
+
|
|
436
|
+
if self._trace:
|
|
437
|
+
self._trace.add_entry(
|
|
438
|
+
category="lsp",
|
|
439
|
+
action="get_diagnostics",
|
|
440
|
+
params={"file": file_path},
|
|
441
|
+
result={"count": len(result) if result else 0},
|
|
442
|
+
duration_ms=duration
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
return [d.__dict__ if hasattr(d, '__dict__') else d for d in (result or [])]
|
|
446
|
+
except Exception as e:
|
|
447
|
+
if self._trace:
|
|
448
|
+
self._trace.add_entry(
|
|
449
|
+
category="lsp",
|
|
450
|
+
action="get_diagnostics",
|
|
451
|
+
params={"file": file_path},
|
|
452
|
+
error=str(e)
|
|
453
|
+
)
|
|
454
|
+
return []
|
|
455
|
+
|
|
456
|
+
# ACP Operations
|
|
457
|
+
async def acp_create_plan(self, prompt: str) -> Dict[str, Any]:
|
|
458
|
+
"""Create an action plan via ACP session tracking."""
|
|
459
|
+
if not self.acp_ready:
|
|
460
|
+
return {"error": "ACP not available", "read_only": True}
|
|
461
|
+
|
|
462
|
+
start = time.time()
|
|
463
|
+
try:
|
|
464
|
+
# ACP session tracks the plan but doesn't create it
|
|
465
|
+
# Return empty steps - ActionOrchestrator handles actual planning
|
|
466
|
+
result = {"steps": [], "prompt": prompt}
|
|
467
|
+
duration = (time.time() - start) * 1000
|
|
468
|
+
|
|
469
|
+
if self._trace:
|
|
470
|
+
self._trace.add_entry(
|
|
471
|
+
category="acp",
|
|
472
|
+
action="create_plan",
|
|
473
|
+
params={"prompt": prompt[:100]},
|
|
474
|
+
result=result,
|
|
475
|
+
duration_ms=duration
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
return result
|
|
479
|
+
except Exception as e:
|
|
480
|
+
if self._trace:
|
|
481
|
+
self._trace.add_entry(
|
|
482
|
+
category="acp",
|
|
483
|
+
action="create_plan",
|
|
484
|
+
params={"prompt": prompt[:100]},
|
|
485
|
+
error=str(e)
|
|
486
|
+
)
|
|
487
|
+
return {"error": str(e)}
|
|
488
|
+
|
|
489
|
+
async def acp_apply_plan(self, plan: Dict[str, Any], auto_approve: bool = False) -> Dict[str, Any]:
|
|
490
|
+
"""Apply an action plan via ACP session tracking."""
|
|
491
|
+
if self.read_only:
|
|
492
|
+
return {"error": "Runtime is read-only", "applied": False}
|
|
493
|
+
|
|
494
|
+
start = time.time()
|
|
495
|
+
try:
|
|
496
|
+
# Track the action in session
|
|
497
|
+
if self._acp_session:
|
|
498
|
+
self._acp_session.add_tool_call(
|
|
499
|
+
tool_call_id=f"plan_{int(time.time())}",
|
|
500
|
+
title="apply_plan",
|
|
501
|
+
status="applied" if auto_approve else "pending"
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
result = {"applied": True, "auto_approve": auto_approve}
|
|
505
|
+
duration = (time.time() - start) * 1000
|
|
506
|
+
|
|
507
|
+
if self._trace:
|
|
508
|
+
self._trace.add_entry(
|
|
509
|
+
category="acp",
|
|
510
|
+
action="apply_plan",
|
|
511
|
+
params={"plan_id": plan.get("id"), "auto_approve": auto_approve},
|
|
512
|
+
result=result,
|
|
513
|
+
duration_ms=duration
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
return result
|
|
517
|
+
except Exception as e:
|
|
518
|
+
if self._trace:
|
|
519
|
+
self._trace.add_entry(
|
|
520
|
+
category="acp",
|
|
521
|
+
action="apply_plan",
|
|
522
|
+
params={"plan_id": plan.get("id")},
|
|
523
|
+
error=str(e)
|
|
524
|
+
)
|
|
525
|
+
return {"error": str(e), "applied": False}
|
|
526
|
+
|
|
527
|
+
def get_trace(self) -> Optional[RuntimeTrace]:
|
|
528
|
+
"""Get the runtime trace."""
|
|
529
|
+
return self._trace
|
|
530
|
+
|
|
531
|
+
def save_trace(self, path: str = None):
|
|
532
|
+
"""Save trace to file."""
|
|
533
|
+
if not self._trace:
|
|
534
|
+
return
|
|
535
|
+
|
|
536
|
+
import json
|
|
537
|
+
path = path or self.config.trace_file or "praisonai_trace.json"
|
|
538
|
+
with open(path, "w") as f:
|
|
539
|
+
json.dump(self._trace.to_dict(), f, indent=2, default=str)
|
|
540
|
+
logger.info(f"Trace saved to {path}")
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def create_runtime(
|
|
544
|
+
workspace: str = ".",
|
|
545
|
+
lsp: bool = True,
|
|
546
|
+
acp: bool = True,
|
|
547
|
+
approval: str = "manual",
|
|
548
|
+
trace: bool = False,
|
|
549
|
+
trace_file: str = None,
|
|
550
|
+
json_output: bool = False,
|
|
551
|
+
timeout: float = 60.0,
|
|
552
|
+
model: str = None,
|
|
553
|
+
verbose: bool = False
|
|
554
|
+
) -> InteractiveRuntime:
|
|
555
|
+
"""
|
|
556
|
+
Factory function to create an InteractiveRuntime.
|
|
557
|
+
|
|
558
|
+
Args:
|
|
559
|
+
workspace: Workspace root directory
|
|
560
|
+
lsp: Enable LSP subsystem
|
|
561
|
+
acp: Enable ACP subsystem
|
|
562
|
+
approval: Approval mode (manual, auto, scoped)
|
|
563
|
+
trace: Enable trace collection
|
|
564
|
+
trace_file: Path to save trace
|
|
565
|
+
json_output: Enable JSON output mode
|
|
566
|
+
timeout: Operation timeout
|
|
567
|
+
model: LLM model to use
|
|
568
|
+
verbose: Enable verbose output
|
|
569
|
+
|
|
570
|
+
Returns:
|
|
571
|
+
Configured InteractiveRuntime instance
|
|
572
|
+
"""
|
|
573
|
+
config = RuntimeConfig(
|
|
574
|
+
workspace=workspace,
|
|
575
|
+
lsp_enabled=lsp,
|
|
576
|
+
acp_enabled=acp,
|
|
577
|
+
approval_mode=approval,
|
|
578
|
+
trace_enabled=trace,
|
|
579
|
+
trace_file=trace_file,
|
|
580
|
+
json_output=json_output,
|
|
581
|
+
timeout=timeout,
|
|
582
|
+
model=model,
|
|
583
|
+
verbose=verbose
|
|
584
|
+
)
|
|
585
|
+
return InteractiveRuntime(config)
|