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,328 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock Provider for PraisonAI TUI Testing.
|
|
3
|
+
|
|
4
|
+
Provides deterministic, replayable responses for CI and headless testing.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import hashlib
|
|
9
|
+
import json
|
|
10
|
+
import random
|
|
11
|
+
import time
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, AsyncIterator, Callable, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class MockResponse:
|
|
19
|
+
"""A mock response configuration."""
|
|
20
|
+
content: str
|
|
21
|
+
chunks: List[str] = field(default_factory=list)
|
|
22
|
+
delay_per_chunk: float = 0.05
|
|
23
|
+
tool_calls: List[Dict[str, Any]] = field(default_factory=list)
|
|
24
|
+
error: Optional[str] = None
|
|
25
|
+
tokens: int = 0
|
|
26
|
+
cost: float = 0.0
|
|
27
|
+
|
|
28
|
+
def __post_init__(self):
|
|
29
|
+
if not self.chunks and self.content:
|
|
30
|
+
# Split content into word chunks
|
|
31
|
+
words = self.content.split()
|
|
32
|
+
self.chunks = []
|
|
33
|
+
for i in range(0, len(words), 3):
|
|
34
|
+
chunk = " ".join(words[i:i+3])
|
|
35
|
+
if i > 0:
|
|
36
|
+
chunk = " " + chunk
|
|
37
|
+
self.chunks.append(chunk)
|
|
38
|
+
|
|
39
|
+
if not self.tokens:
|
|
40
|
+
self.tokens = len(self.content.split()) * 2 # Rough estimate
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class MockProviderConfig:
|
|
45
|
+
"""Configuration for mock provider."""
|
|
46
|
+
seed: int = 42
|
|
47
|
+
default_delay: float = 0.05
|
|
48
|
+
simulate_errors: bool = False
|
|
49
|
+
error_rate: float = 0.1
|
|
50
|
+
record_mode: bool = False
|
|
51
|
+
playback_file: Optional[str] = None
|
|
52
|
+
|
|
53
|
+
# Canned responses by input pattern
|
|
54
|
+
responses: Dict[str, MockResponse] = field(default_factory=dict)
|
|
55
|
+
|
|
56
|
+
# Default response if no pattern matches
|
|
57
|
+
default_response: Optional[MockResponse] = None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class MockProvider:
|
|
61
|
+
"""
|
|
62
|
+
Mock LLM provider for testing.
|
|
63
|
+
|
|
64
|
+
Features:
|
|
65
|
+
- Deterministic responses based on seed
|
|
66
|
+
- Streaming simulation
|
|
67
|
+
- Tool call simulation
|
|
68
|
+
- Error injection
|
|
69
|
+
- Record/playback mode
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(self, config: Optional[MockProviderConfig] = None):
|
|
73
|
+
self.config = config or MockProviderConfig()
|
|
74
|
+
self._rng = random.Random(self.config.seed)
|
|
75
|
+
self._recordings: List[Dict[str, Any]] = []
|
|
76
|
+
self._playback_index = 0
|
|
77
|
+
|
|
78
|
+
# Load playback file if specified
|
|
79
|
+
if self.config.playback_file:
|
|
80
|
+
self._load_playback()
|
|
81
|
+
|
|
82
|
+
# Setup default responses
|
|
83
|
+
self._setup_defaults()
|
|
84
|
+
|
|
85
|
+
def _setup_defaults(self) -> None:
|
|
86
|
+
"""Setup default canned responses."""
|
|
87
|
+
defaults = {
|
|
88
|
+
"hello": MockResponse(
|
|
89
|
+
content="Hello! I'm a mock AI assistant. How can I help you today?",
|
|
90
|
+
tokens=20,
|
|
91
|
+
cost=0.0001,
|
|
92
|
+
),
|
|
93
|
+
"help": MockResponse(
|
|
94
|
+
content="I can help you with various tasks. Just ask me anything!",
|
|
95
|
+
tokens=15,
|
|
96
|
+
cost=0.00008,
|
|
97
|
+
),
|
|
98
|
+
"test": MockResponse(
|
|
99
|
+
content="This is a test response. Everything is working correctly.",
|
|
100
|
+
tokens=12,
|
|
101
|
+
cost=0.00006,
|
|
102
|
+
),
|
|
103
|
+
"error": MockResponse(
|
|
104
|
+
content="",
|
|
105
|
+
error="Simulated error for testing",
|
|
106
|
+
),
|
|
107
|
+
"tool": MockResponse(
|
|
108
|
+
content="I'll use a tool to help with that.",
|
|
109
|
+
tool_calls=[{
|
|
110
|
+
"id": "call_mock_001",
|
|
111
|
+
"name": "mock_tool",
|
|
112
|
+
"arguments": {"query": "test"},
|
|
113
|
+
}],
|
|
114
|
+
tokens=25,
|
|
115
|
+
cost=0.00012,
|
|
116
|
+
),
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for pattern, response in defaults.items():
|
|
120
|
+
if pattern not in self.config.responses:
|
|
121
|
+
self.config.responses[pattern] = response
|
|
122
|
+
|
|
123
|
+
if not self.config.default_response:
|
|
124
|
+
self.config.default_response = MockResponse(
|
|
125
|
+
content="I understand your request. Here's a mock response for testing purposes. "
|
|
126
|
+
"This response is generated deterministically based on the input.",
|
|
127
|
+
tokens=30,
|
|
128
|
+
cost=0.00015,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def _load_playback(self) -> None:
|
|
132
|
+
"""Load recordings for playback."""
|
|
133
|
+
if not self.config.playback_file:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
path = Path(self.config.playback_file)
|
|
137
|
+
if path.exists():
|
|
138
|
+
with open(path) as f:
|
|
139
|
+
for line in f:
|
|
140
|
+
self._recordings.append(json.loads(line))
|
|
141
|
+
|
|
142
|
+
def _save_recording(self, input_content: str, response: MockResponse) -> None:
|
|
143
|
+
"""Save a recording."""
|
|
144
|
+
if not self.config.record_mode or not self.config.playback_file:
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
record = {
|
|
148
|
+
"timestamp": time.time(),
|
|
149
|
+
"input": input_content,
|
|
150
|
+
"response": {
|
|
151
|
+
"content": response.content,
|
|
152
|
+
"chunks": response.chunks,
|
|
153
|
+
"tool_calls": response.tool_calls,
|
|
154
|
+
"tokens": response.tokens,
|
|
155
|
+
"cost": response.cost,
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
path = Path(self.config.playback_file)
|
|
160
|
+
with open(path, "a") as f:
|
|
161
|
+
f.write(json.dumps(record) + "\n")
|
|
162
|
+
|
|
163
|
+
def _get_response(self, input_content: str) -> MockResponse:
|
|
164
|
+
"""Get response for input."""
|
|
165
|
+
# Check playback mode
|
|
166
|
+
if self._recordings and self._playback_index < len(self._recordings):
|
|
167
|
+
record = self._recordings[self._playback_index]
|
|
168
|
+
self._playback_index += 1
|
|
169
|
+
return MockResponse(**record["response"])
|
|
170
|
+
|
|
171
|
+
# Check for pattern match
|
|
172
|
+
input_lower = input_content.lower()
|
|
173
|
+
for pattern, response in self.config.responses.items():
|
|
174
|
+
if pattern in input_lower:
|
|
175
|
+
return response
|
|
176
|
+
|
|
177
|
+
# Simulate random error
|
|
178
|
+
if self.config.simulate_errors and self._rng.random() < self.config.error_rate:
|
|
179
|
+
return MockResponse(content="", error="Random simulated error")
|
|
180
|
+
|
|
181
|
+
# Generate deterministic response based on input hash
|
|
182
|
+
input_hash = hashlib.md5(input_content.encode()).hexdigest()
|
|
183
|
+
seed = int(input_hash[:8], 16)
|
|
184
|
+
rng = random.Random(seed)
|
|
185
|
+
|
|
186
|
+
# Generate varied response
|
|
187
|
+
templates = [
|
|
188
|
+
"I've processed your request about '{topic}'. Here's what I found...",
|
|
189
|
+
"Regarding '{topic}', I can provide the following information...",
|
|
190
|
+
"Thank you for asking about '{topic}'. Let me explain...",
|
|
191
|
+
"Based on your query about '{topic}', here's my response...",
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
topic = input_content[:30] if len(input_content) > 30 else input_content
|
|
195
|
+
template = rng.choice(templates)
|
|
196
|
+
content = template.format(topic=topic)
|
|
197
|
+
|
|
198
|
+
# Add some mock content
|
|
199
|
+
content += " This is a deterministic mock response generated for testing. "
|
|
200
|
+
content += f"Input hash: {input_hash[:8]}. "
|
|
201
|
+
content += "The response is reproducible given the same input."
|
|
202
|
+
|
|
203
|
+
return MockResponse(
|
|
204
|
+
content=content,
|
|
205
|
+
tokens=len(content.split()) * 2,
|
|
206
|
+
cost=len(content) * 0.000001,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
async def generate(
|
|
210
|
+
self,
|
|
211
|
+
input_content: str,
|
|
212
|
+
model: str = "mock-model",
|
|
213
|
+
stream: bool = True,
|
|
214
|
+
on_chunk: Optional[Callable[[str], None]] = None,
|
|
215
|
+
) -> Dict[str, Any]:
|
|
216
|
+
"""
|
|
217
|
+
Generate a mock response.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
input_content: The input prompt
|
|
221
|
+
model: Model name (ignored for mock)
|
|
222
|
+
stream: Whether to stream the response
|
|
223
|
+
on_chunk: Callback for streaming chunks
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
Response dict with content, tokens, cost
|
|
227
|
+
"""
|
|
228
|
+
response = self._get_response(input_content)
|
|
229
|
+
|
|
230
|
+
# Record if in record mode
|
|
231
|
+
if self.config.record_mode:
|
|
232
|
+
self._save_recording(input_content, response)
|
|
233
|
+
|
|
234
|
+
# Check for error
|
|
235
|
+
if response.error:
|
|
236
|
+
raise Exception(response.error)
|
|
237
|
+
|
|
238
|
+
# Stream chunks
|
|
239
|
+
if stream and on_chunk:
|
|
240
|
+
for chunk in response.chunks:
|
|
241
|
+
await asyncio.sleep(response.delay_per_chunk)
|
|
242
|
+
on_chunk(chunk)
|
|
243
|
+
else:
|
|
244
|
+
# Non-streaming delay
|
|
245
|
+
await asyncio.sleep(len(response.chunks) * response.delay_per_chunk)
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
"content": response.content,
|
|
249
|
+
"tokens": response.tokens,
|
|
250
|
+
"cost": response.cost,
|
|
251
|
+
"tool_calls": response.tool_calls,
|
|
252
|
+
"model": model,
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async def stream(
|
|
256
|
+
self,
|
|
257
|
+
input_content: str,
|
|
258
|
+
model: str = "mock-model",
|
|
259
|
+
) -> AsyncIterator[str]:
|
|
260
|
+
"""
|
|
261
|
+
Stream a mock response.
|
|
262
|
+
|
|
263
|
+
Yields chunks of the response.
|
|
264
|
+
"""
|
|
265
|
+
response = self._get_response(input_content)
|
|
266
|
+
|
|
267
|
+
if response.error:
|
|
268
|
+
raise Exception(response.error)
|
|
269
|
+
|
|
270
|
+
for chunk in response.chunks:
|
|
271
|
+
await asyncio.sleep(response.delay_per_chunk)
|
|
272
|
+
yield chunk
|
|
273
|
+
|
|
274
|
+
def reset(self) -> None:
|
|
275
|
+
"""Reset provider state."""
|
|
276
|
+
self._rng = random.Random(self.config.seed)
|
|
277
|
+
self._playback_index = 0
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class MockExecutor:
|
|
281
|
+
"""
|
|
282
|
+
Mock executor for queue worker testing.
|
|
283
|
+
|
|
284
|
+
Simulates agent execution with configurable behavior.
|
|
285
|
+
"""
|
|
286
|
+
|
|
287
|
+
def __init__(self, provider: Optional[MockProvider] = None):
|
|
288
|
+
self.provider = provider or MockProvider()
|
|
289
|
+
|
|
290
|
+
async def execute(
|
|
291
|
+
self,
|
|
292
|
+
input_content: str,
|
|
293
|
+
agent_config: Dict[str, Any],
|
|
294
|
+
on_output: Optional[Callable[[str], None]] = None,
|
|
295
|
+
) -> Dict[str, Any]:
|
|
296
|
+
"""Execute a mock agent run."""
|
|
297
|
+
model = agent_config.get("model", "mock-model")
|
|
298
|
+
|
|
299
|
+
result = await self.provider.generate(
|
|
300
|
+
input_content=input_content,
|
|
301
|
+
model=model,
|
|
302
|
+
stream=True,
|
|
303
|
+
on_chunk=on_output,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
"output": result["content"],
|
|
308
|
+
"metrics": {
|
|
309
|
+
"tokens": result["tokens"],
|
|
310
|
+
"cost": result["cost"],
|
|
311
|
+
},
|
|
312
|
+
"tool_calls": result.get("tool_calls", []),
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
# Convenience function for tests
|
|
317
|
+
def create_mock_provider(
|
|
318
|
+
seed: int = 42,
|
|
319
|
+
responses: Optional[Dict[str, str]] = None,
|
|
320
|
+
) -> MockProvider:
|
|
321
|
+
"""Create a mock provider with optional custom responses."""
|
|
322
|
+
config = MockProviderConfig(seed=seed)
|
|
323
|
+
|
|
324
|
+
if responses:
|
|
325
|
+
for pattern, content in responses.items():
|
|
326
|
+
config.responses[pattern] = MockResponse(content=content)
|
|
327
|
+
|
|
328
|
+
return MockProvider(config)
|