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.
Files changed (393) hide show
  1. praisonai/__init__.py +54 -0
  2. praisonai/__main__.py +15 -0
  3. praisonai/acp/__init__.py +54 -0
  4. praisonai/acp/config.py +159 -0
  5. praisonai/acp/server.py +587 -0
  6. praisonai/acp/session.py +219 -0
  7. praisonai/adapters/__init__.py +50 -0
  8. praisonai/adapters/readers.py +395 -0
  9. praisonai/adapters/rerankers.py +315 -0
  10. praisonai/adapters/retrievers.py +394 -0
  11. praisonai/adapters/vector_stores.py +409 -0
  12. praisonai/agent_scheduler.py +337 -0
  13. praisonai/agents_generator.py +903 -0
  14. praisonai/api/call.py +292 -0
  15. praisonai/auto.py +1197 -0
  16. praisonai/capabilities/__init__.py +275 -0
  17. praisonai/capabilities/a2a.py +140 -0
  18. praisonai/capabilities/assistants.py +283 -0
  19. praisonai/capabilities/audio.py +320 -0
  20. praisonai/capabilities/batches.py +469 -0
  21. praisonai/capabilities/completions.py +336 -0
  22. praisonai/capabilities/container_files.py +155 -0
  23. praisonai/capabilities/containers.py +93 -0
  24. praisonai/capabilities/embeddings.py +158 -0
  25. praisonai/capabilities/files.py +467 -0
  26. praisonai/capabilities/fine_tuning.py +293 -0
  27. praisonai/capabilities/guardrails.py +182 -0
  28. praisonai/capabilities/images.py +330 -0
  29. praisonai/capabilities/mcp.py +190 -0
  30. praisonai/capabilities/messages.py +270 -0
  31. praisonai/capabilities/moderations.py +154 -0
  32. praisonai/capabilities/ocr.py +217 -0
  33. praisonai/capabilities/passthrough.py +204 -0
  34. praisonai/capabilities/rag.py +207 -0
  35. praisonai/capabilities/realtime.py +160 -0
  36. praisonai/capabilities/rerank.py +165 -0
  37. praisonai/capabilities/responses.py +266 -0
  38. praisonai/capabilities/search.py +109 -0
  39. praisonai/capabilities/skills.py +133 -0
  40. praisonai/capabilities/vector_store_files.py +334 -0
  41. praisonai/capabilities/vector_stores.py +304 -0
  42. praisonai/capabilities/videos.py +141 -0
  43. praisonai/chainlit_ui.py +304 -0
  44. praisonai/chat/__init__.py +106 -0
  45. praisonai/chat/app.py +125 -0
  46. praisonai/cli/__init__.py +26 -0
  47. praisonai/cli/app.py +213 -0
  48. praisonai/cli/commands/__init__.py +75 -0
  49. praisonai/cli/commands/acp.py +70 -0
  50. praisonai/cli/commands/completion.py +333 -0
  51. praisonai/cli/commands/config.py +166 -0
  52. praisonai/cli/commands/debug.py +142 -0
  53. praisonai/cli/commands/diag.py +55 -0
  54. praisonai/cli/commands/doctor.py +166 -0
  55. praisonai/cli/commands/environment.py +179 -0
  56. praisonai/cli/commands/lsp.py +112 -0
  57. praisonai/cli/commands/mcp.py +210 -0
  58. praisonai/cli/commands/profile.py +457 -0
  59. praisonai/cli/commands/run.py +228 -0
  60. praisonai/cli/commands/schedule.py +150 -0
  61. praisonai/cli/commands/serve.py +97 -0
  62. praisonai/cli/commands/session.py +212 -0
  63. praisonai/cli/commands/traces.py +145 -0
  64. praisonai/cli/commands/version.py +101 -0
  65. praisonai/cli/configuration/__init__.py +18 -0
  66. praisonai/cli/configuration/loader.py +353 -0
  67. praisonai/cli/configuration/paths.py +114 -0
  68. praisonai/cli/configuration/schema.py +164 -0
  69. praisonai/cli/features/__init__.py +268 -0
  70. praisonai/cli/features/acp.py +236 -0
  71. praisonai/cli/features/action_orchestrator.py +546 -0
  72. praisonai/cli/features/agent_scheduler.py +773 -0
  73. praisonai/cli/features/agent_tools.py +474 -0
  74. praisonai/cli/features/agents.py +375 -0
  75. praisonai/cli/features/at_mentions.py +471 -0
  76. praisonai/cli/features/auto_memory.py +182 -0
  77. praisonai/cli/features/autonomy_mode.py +490 -0
  78. praisonai/cli/features/background.py +356 -0
  79. praisonai/cli/features/base.py +168 -0
  80. praisonai/cli/features/capabilities.py +1326 -0
  81. praisonai/cli/features/checkpoints.py +338 -0
  82. praisonai/cli/features/code_intelligence.py +652 -0
  83. praisonai/cli/features/compaction.py +294 -0
  84. praisonai/cli/features/compare.py +534 -0
  85. praisonai/cli/features/cost_tracker.py +514 -0
  86. praisonai/cli/features/debug.py +810 -0
  87. praisonai/cli/features/deploy.py +517 -0
  88. praisonai/cli/features/diag.py +289 -0
  89. praisonai/cli/features/doctor/__init__.py +63 -0
  90. praisonai/cli/features/doctor/checks/__init__.py +24 -0
  91. praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
  92. praisonai/cli/features/doctor/checks/config_checks.py +366 -0
  93. praisonai/cli/features/doctor/checks/db_checks.py +366 -0
  94. praisonai/cli/features/doctor/checks/env_checks.py +543 -0
  95. praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
  96. praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
  97. praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
  98. praisonai/cli/features/doctor/checks/network_checks.py +251 -0
  99. praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
  100. praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
  101. praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
  102. praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
  103. praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
  104. praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
  105. praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
  106. praisonai/cli/features/doctor/engine.py +266 -0
  107. praisonai/cli/features/doctor/formatters.py +310 -0
  108. praisonai/cli/features/doctor/handler.py +397 -0
  109. praisonai/cli/features/doctor/models.py +264 -0
  110. praisonai/cli/features/doctor/registry.py +239 -0
  111. praisonai/cli/features/endpoints.py +1019 -0
  112. praisonai/cli/features/eval.py +560 -0
  113. praisonai/cli/features/external_agents.py +231 -0
  114. praisonai/cli/features/fast_context.py +410 -0
  115. praisonai/cli/features/flow_display.py +566 -0
  116. praisonai/cli/features/git_integration.py +651 -0
  117. praisonai/cli/features/guardrail.py +171 -0
  118. praisonai/cli/features/handoff.py +185 -0
  119. praisonai/cli/features/hooks.py +583 -0
  120. praisonai/cli/features/image.py +384 -0
  121. praisonai/cli/features/interactive_runtime.py +585 -0
  122. praisonai/cli/features/interactive_tools.py +380 -0
  123. praisonai/cli/features/interactive_tui.py +603 -0
  124. praisonai/cli/features/jobs.py +632 -0
  125. praisonai/cli/features/knowledge.py +531 -0
  126. praisonai/cli/features/lite.py +244 -0
  127. praisonai/cli/features/lsp_cli.py +225 -0
  128. praisonai/cli/features/mcp.py +169 -0
  129. praisonai/cli/features/message_queue.py +587 -0
  130. praisonai/cli/features/metrics.py +211 -0
  131. praisonai/cli/features/n8n.py +673 -0
  132. praisonai/cli/features/observability.py +293 -0
  133. praisonai/cli/features/ollama.py +361 -0
  134. praisonai/cli/features/output_style.py +273 -0
  135. praisonai/cli/features/package.py +631 -0
  136. praisonai/cli/features/performance.py +308 -0
  137. praisonai/cli/features/persistence.py +636 -0
  138. praisonai/cli/features/profile.py +226 -0
  139. praisonai/cli/features/profiler/__init__.py +81 -0
  140. praisonai/cli/features/profiler/core.py +558 -0
  141. praisonai/cli/features/profiler/optimizations.py +652 -0
  142. praisonai/cli/features/profiler/suite.py +386 -0
  143. praisonai/cli/features/profiling.py +350 -0
  144. praisonai/cli/features/queue/__init__.py +73 -0
  145. praisonai/cli/features/queue/manager.py +395 -0
  146. praisonai/cli/features/queue/models.py +286 -0
  147. praisonai/cli/features/queue/persistence.py +564 -0
  148. praisonai/cli/features/queue/scheduler.py +484 -0
  149. praisonai/cli/features/queue/worker.py +372 -0
  150. praisonai/cli/features/recipe.py +1723 -0
  151. praisonai/cli/features/recipes.py +449 -0
  152. praisonai/cli/features/registry.py +229 -0
  153. praisonai/cli/features/repo_map.py +860 -0
  154. praisonai/cli/features/router.py +466 -0
  155. praisonai/cli/features/sandbox_executor.py +515 -0
  156. praisonai/cli/features/serve.py +829 -0
  157. praisonai/cli/features/session.py +222 -0
  158. praisonai/cli/features/skills.py +856 -0
  159. praisonai/cli/features/slash_commands.py +650 -0
  160. praisonai/cli/features/telemetry.py +179 -0
  161. praisonai/cli/features/templates.py +1384 -0
  162. praisonai/cli/features/thinking.py +305 -0
  163. praisonai/cli/features/todo.py +334 -0
  164. praisonai/cli/features/tools.py +680 -0
  165. praisonai/cli/features/tui/__init__.py +83 -0
  166. praisonai/cli/features/tui/app.py +580 -0
  167. praisonai/cli/features/tui/cli.py +566 -0
  168. praisonai/cli/features/tui/debug.py +511 -0
  169. praisonai/cli/features/tui/events.py +99 -0
  170. praisonai/cli/features/tui/mock_provider.py +328 -0
  171. praisonai/cli/features/tui/orchestrator.py +652 -0
  172. praisonai/cli/features/tui/screens/__init__.py +50 -0
  173. praisonai/cli/features/tui/screens/main.py +245 -0
  174. praisonai/cli/features/tui/screens/queue.py +174 -0
  175. praisonai/cli/features/tui/screens/session.py +124 -0
  176. praisonai/cli/features/tui/screens/settings.py +148 -0
  177. praisonai/cli/features/tui/widgets/__init__.py +56 -0
  178. praisonai/cli/features/tui/widgets/chat.py +261 -0
  179. praisonai/cli/features/tui/widgets/composer.py +224 -0
  180. praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
  181. praisonai/cli/features/tui/widgets/status.py +167 -0
  182. praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
  183. praisonai/cli/features/workflow.py +720 -0
  184. praisonai/cli/legacy.py +236 -0
  185. praisonai/cli/main.py +5559 -0
  186. praisonai/cli/schedule_cli.py +54 -0
  187. praisonai/cli/state/__init__.py +31 -0
  188. praisonai/cli/state/identifiers.py +161 -0
  189. praisonai/cli/state/sessions.py +313 -0
  190. praisonai/code/__init__.py +93 -0
  191. praisonai/code/agent_tools.py +344 -0
  192. praisonai/code/diff/__init__.py +21 -0
  193. praisonai/code/diff/diff_strategy.py +432 -0
  194. praisonai/code/tools/__init__.py +27 -0
  195. praisonai/code/tools/apply_diff.py +221 -0
  196. praisonai/code/tools/execute_command.py +275 -0
  197. praisonai/code/tools/list_files.py +274 -0
  198. praisonai/code/tools/read_file.py +206 -0
  199. praisonai/code/tools/search_replace.py +248 -0
  200. praisonai/code/tools/write_file.py +217 -0
  201. praisonai/code/utils/__init__.py +46 -0
  202. praisonai/code/utils/file_utils.py +307 -0
  203. praisonai/code/utils/ignore_utils.py +308 -0
  204. praisonai/code/utils/text_utils.py +276 -0
  205. praisonai/db/__init__.py +64 -0
  206. praisonai/db/adapter.py +531 -0
  207. praisonai/deploy/__init__.py +62 -0
  208. praisonai/deploy/api.py +231 -0
  209. praisonai/deploy/docker.py +454 -0
  210. praisonai/deploy/doctor.py +367 -0
  211. praisonai/deploy/main.py +327 -0
  212. praisonai/deploy/models.py +179 -0
  213. praisonai/deploy/providers/__init__.py +33 -0
  214. praisonai/deploy/providers/aws.py +331 -0
  215. praisonai/deploy/providers/azure.py +358 -0
  216. praisonai/deploy/providers/base.py +101 -0
  217. praisonai/deploy/providers/gcp.py +314 -0
  218. praisonai/deploy/schema.py +208 -0
  219. praisonai/deploy.py +185 -0
  220. praisonai/endpoints/__init__.py +53 -0
  221. praisonai/endpoints/a2u_server.py +410 -0
  222. praisonai/endpoints/discovery.py +165 -0
  223. praisonai/endpoints/providers/__init__.py +28 -0
  224. praisonai/endpoints/providers/a2a.py +253 -0
  225. praisonai/endpoints/providers/a2u.py +208 -0
  226. praisonai/endpoints/providers/agents_api.py +171 -0
  227. praisonai/endpoints/providers/base.py +231 -0
  228. praisonai/endpoints/providers/mcp.py +263 -0
  229. praisonai/endpoints/providers/recipe.py +206 -0
  230. praisonai/endpoints/providers/tools_mcp.py +150 -0
  231. praisonai/endpoints/registry.py +131 -0
  232. praisonai/endpoints/server.py +161 -0
  233. praisonai/inbuilt_tools/__init__.py +24 -0
  234. praisonai/inbuilt_tools/autogen_tools.py +117 -0
  235. praisonai/inc/__init__.py +2 -0
  236. praisonai/inc/config.py +96 -0
  237. praisonai/inc/models.py +155 -0
  238. praisonai/integrations/__init__.py +56 -0
  239. praisonai/integrations/base.py +303 -0
  240. praisonai/integrations/claude_code.py +270 -0
  241. praisonai/integrations/codex_cli.py +255 -0
  242. praisonai/integrations/cursor_cli.py +195 -0
  243. praisonai/integrations/gemini_cli.py +222 -0
  244. praisonai/jobs/__init__.py +67 -0
  245. praisonai/jobs/executor.py +425 -0
  246. praisonai/jobs/models.py +230 -0
  247. praisonai/jobs/router.py +314 -0
  248. praisonai/jobs/server.py +186 -0
  249. praisonai/jobs/store.py +203 -0
  250. praisonai/llm/__init__.py +66 -0
  251. praisonai/llm/registry.py +382 -0
  252. praisonai/mcp_server/__init__.py +152 -0
  253. praisonai/mcp_server/adapters/__init__.py +74 -0
  254. praisonai/mcp_server/adapters/agents.py +128 -0
  255. praisonai/mcp_server/adapters/capabilities.py +168 -0
  256. praisonai/mcp_server/adapters/cli_tools.py +568 -0
  257. praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
  258. praisonai/mcp_server/adapters/knowledge.py +93 -0
  259. praisonai/mcp_server/adapters/memory.py +104 -0
  260. praisonai/mcp_server/adapters/prompts.py +306 -0
  261. praisonai/mcp_server/adapters/resources.py +124 -0
  262. praisonai/mcp_server/adapters/tools_bridge.py +280 -0
  263. praisonai/mcp_server/auth/__init__.py +48 -0
  264. praisonai/mcp_server/auth/api_key.py +291 -0
  265. praisonai/mcp_server/auth/oauth.py +460 -0
  266. praisonai/mcp_server/auth/oidc.py +289 -0
  267. praisonai/mcp_server/auth/scopes.py +260 -0
  268. praisonai/mcp_server/cli.py +852 -0
  269. praisonai/mcp_server/elicitation.py +445 -0
  270. praisonai/mcp_server/icons.py +302 -0
  271. praisonai/mcp_server/recipe_adapter.py +573 -0
  272. praisonai/mcp_server/recipe_cli.py +824 -0
  273. praisonai/mcp_server/registry.py +703 -0
  274. praisonai/mcp_server/sampling.py +422 -0
  275. praisonai/mcp_server/server.py +490 -0
  276. praisonai/mcp_server/tasks.py +443 -0
  277. praisonai/mcp_server/transports/__init__.py +18 -0
  278. praisonai/mcp_server/transports/http_stream.py +376 -0
  279. praisonai/mcp_server/transports/stdio.py +132 -0
  280. praisonai/persistence/__init__.py +84 -0
  281. praisonai/persistence/config.py +238 -0
  282. praisonai/persistence/conversation/__init__.py +25 -0
  283. praisonai/persistence/conversation/async_mysql.py +427 -0
  284. praisonai/persistence/conversation/async_postgres.py +410 -0
  285. praisonai/persistence/conversation/async_sqlite.py +371 -0
  286. praisonai/persistence/conversation/base.py +151 -0
  287. praisonai/persistence/conversation/json_store.py +250 -0
  288. praisonai/persistence/conversation/mysql.py +387 -0
  289. praisonai/persistence/conversation/postgres.py +401 -0
  290. praisonai/persistence/conversation/singlestore.py +240 -0
  291. praisonai/persistence/conversation/sqlite.py +341 -0
  292. praisonai/persistence/conversation/supabase.py +203 -0
  293. praisonai/persistence/conversation/surrealdb.py +287 -0
  294. praisonai/persistence/factory.py +301 -0
  295. praisonai/persistence/hooks/__init__.py +18 -0
  296. praisonai/persistence/hooks/agent_hooks.py +297 -0
  297. praisonai/persistence/knowledge/__init__.py +26 -0
  298. praisonai/persistence/knowledge/base.py +144 -0
  299. praisonai/persistence/knowledge/cassandra.py +232 -0
  300. praisonai/persistence/knowledge/chroma.py +295 -0
  301. praisonai/persistence/knowledge/clickhouse.py +242 -0
  302. praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
  303. praisonai/persistence/knowledge/couchbase.py +286 -0
  304. praisonai/persistence/knowledge/lancedb.py +216 -0
  305. praisonai/persistence/knowledge/langchain_adapter.py +291 -0
  306. praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
  307. praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
  308. praisonai/persistence/knowledge/milvus.py +277 -0
  309. praisonai/persistence/knowledge/mongodb_vector.py +306 -0
  310. praisonai/persistence/knowledge/pgvector.py +335 -0
  311. praisonai/persistence/knowledge/pinecone.py +253 -0
  312. praisonai/persistence/knowledge/qdrant.py +301 -0
  313. praisonai/persistence/knowledge/redis_vector.py +291 -0
  314. praisonai/persistence/knowledge/singlestore_vector.py +299 -0
  315. praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
  316. praisonai/persistence/knowledge/upstash_vector.py +266 -0
  317. praisonai/persistence/knowledge/weaviate.py +223 -0
  318. praisonai/persistence/migrations/__init__.py +10 -0
  319. praisonai/persistence/migrations/manager.py +251 -0
  320. praisonai/persistence/orchestrator.py +406 -0
  321. praisonai/persistence/state/__init__.py +21 -0
  322. praisonai/persistence/state/async_mongodb.py +200 -0
  323. praisonai/persistence/state/base.py +107 -0
  324. praisonai/persistence/state/dynamodb.py +226 -0
  325. praisonai/persistence/state/firestore.py +175 -0
  326. praisonai/persistence/state/gcs.py +155 -0
  327. praisonai/persistence/state/memory.py +245 -0
  328. praisonai/persistence/state/mongodb.py +158 -0
  329. praisonai/persistence/state/redis.py +190 -0
  330. praisonai/persistence/state/upstash.py +144 -0
  331. praisonai/persistence/tests/__init__.py +3 -0
  332. praisonai/persistence/tests/test_all_backends.py +633 -0
  333. praisonai/profiler.py +1214 -0
  334. praisonai/recipe/__init__.py +134 -0
  335. praisonai/recipe/bridge.py +278 -0
  336. praisonai/recipe/core.py +893 -0
  337. praisonai/recipe/exceptions.py +54 -0
  338. praisonai/recipe/history.py +402 -0
  339. praisonai/recipe/models.py +266 -0
  340. praisonai/recipe/operations.py +440 -0
  341. praisonai/recipe/policy.py +422 -0
  342. praisonai/recipe/registry.py +849 -0
  343. praisonai/recipe/runtime.py +214 -0
  344. praisonai/recipe/security.py +711 -0
  345. praisonai/recipe/serve.py +859 -0
  346. praisonai/recipe/server.py +613 -0
  347. praisonai/scheduler/__init__.py +45 -0
  348. praisonai/scheduler/agent_scheduler.py +552 -0
  349. praisonai/scheduler/base.py +124 -0
  350. praisonai/scheduler/daemon_manager.py +225 -0
  351. praisonai/scheduler/state_manager.py +155 -0
  352. praisonai/scheduler/yaml_loader.py +193 -0
  353. praisonai/scheduler.py +194 -0
  354. praisonai/setup/__init__.py +1 -0
  355. praisonai/setup/build.py +21 -0
  356. praisonai/setup/post_install.py +23 -0
  357. praisonai/setup/setup_conda_env.py +25 -0
  358. praisonai/setup.py +16 -0
  359. praisonai/templates/__init__.py +116 -0
  360. praisonai/templates/cache.py +364 -0
  361. praisonai/templates/dependency_checker.py +358 -0
  362. praisonai/templates/discovery.py +391 -0
  363. praisonai/templates/loader.py +564 -0
  364. praisonai/templates/registry.py +511 -0
  365. praisonai/templates/resolver.py +206 -0
  366. praisonai/templates/security.py +327 -0
  367. praisonai/templates/tool_override.py +498 -0
  368. praisonai/templates/tools_doctor.py +256 -0
  369. praisonai/test.py +105 -0
  370. praisonai/train.py +562 -0
  371. praisonai/train_vision.py +306 -0
  372. praisonai/ui/agents.py +824 -0
  373. praisonai/ui/callbacks.py +57 -0
  374. praisonai/ui/chainlit_compat.py +246 -0
  375. praisonai/ui/chat.py +532 -0
  376. praisonai/ui/code.py +717 -0
  377. praisonai/ui/colab.py +474 -0
  378. praisonai/ui/colab_chainlit.py +81 -0
  379. praisonai/ui/components/aicoder.py +284 -0
  380. praisonai/ui/context.py +283 -0
  381. praisonai/ui/database_config.py +56 -0
  382. praisonai/ui/db.py +294 -0
  383. praisonai/ui/realtime.py +488 -0
  384. praisonai/ui/realtimeclient/__init__.py +756 -0
  385. praisonai/ui/realtimeclient/tools.py +242 -0
  386. praisonai/ui/sql_alchemy.py +710 -0
  387. praisonai/upload_vision.py +140 -0
  388. praisonai/version.py +1 -0
  389. praisonai-3.0.0.dist-info/METADATA +3493 -0
  390. praisonai-3.0.0.dist-info/RECORD +393 -0
  391. praisonai-3.0.0.dist-info/WHEEL +5 -0
  392. praisonai-3.0.0.dist-info/entry_points.txt +4 -0
  393. praisonai-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,490 @@
1
+ """
2
+ Autonomy Modes for PraisonAI CLI.
3
+
4
+ Inspired by Codex CLI's approval modes and Gemini CLI's approval settings.
5
+ Provides configurable autonomy levels: suggest, auto-edit, full-auto.
6
+
7
+ Architecture:
8
+ - AutonomyMode: Enum for different autonomy levels
9
+ - AutonomyPolicy: Policy configuration for each mode
10
+ - AutonomyManager: Manages mode transitions and approvals
11
+ """
12
+
13
+ from dataclasses import dataclass, field
14
+ from typing import Any, Callable, Dict, Optional, Set
15
+ from enum import Enum
16
+ import logging
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class AutonomyMode(Enum):
22
+ """
23
+ Autonomy levels for agent execution.
24
+
25
+ Inspired by Codex CLI's approval modes:
26
+ - SUGGEST: Read-only, requires approval for all changes
27
+ - AUTO_EDIT: Auto-approve file edits, require approval for commands
28
+ - FULL_AUTO: Auto-approve everything (YOLO mode)
29
+ """
30
+ SUGGEST = "suggest" # Default: ask for approval on everything
31
+ AUTO_EDIT = "auto_edit" # Auto-approve file edits only
32
+ FULL_AUTO = "full_auto" # Auto-approve everything (dangerous)
33
+
34
+ @classmethod
35
+ def from_string(cls, value: str) -> "AutonomyMode":
36
+ """Parse mode from string."""
37
+ value = value.lower().strip().replace("-", "_")
38
+ for mode in cls:
39
+ if mode.value == value:
40
+ return mode
41
+ raise ValueError(f"Unknown autonomy mode: {value}")
42
+
43
+
44
+ class ActionType(Enum):
45
+ """Types of actions that require approval."""
46
+ FILE_READ = "file_read"
47
+ FILE_WRITE = "file_write"
48
+ FILE_DELETE = "file_delete"
49
+ SHELL_COMMAND = "shell_command"
50
+ NETWORK_REQUEST = "network_request"
51
+ CODE_EXECUTION = "code_execution"
52
+ GIT_OPERATION = "git_operation"
53
+ TOOL_CALL = "tool_call"
54
+
55
+
56
+ @dataclass
57
+ class ActionRequest:
58
+ """
59
+ Request for an action that may require approval.
60
+
61
+ Attributes:
62
+ action_type: Type of action
63
+ description: Human-readable description
64
+ details: Additional details (file path, command, etc.)
65
+ risk_level: Estimated risk (low, medium, high)
66
+ reversible: Whether the action can be undone
67
+ """
68
+ action_type: ActionType
69
+ description: str
70
+ details: Dict[str, Any] = field(default_factory=dict)
71
+ risk_level: str = "medium"
72
+ reversible: bool = True
73
+
74
+ def __str__(self) -> str:
75
+ return f"{self.action_type.value}: {self.description}"
76
+
77
+
78
+ @dataclass
79
+ class ApprovalResult:
80
+ """Result of an approval request."""
81
+ approved: bool
82
+ reason: Optional[str] = None
83
+ modified_action: Optional[ActionRequest] = None
84
+ remember_choice: bool = False
85
+
86
+
87
+ @dataclass
88
+ class AutonomyPolicy:
89
+ """
90
+ Policy configuration for autonomy mode.
91
+
92
+ Defines which actions are auto-approved, require approval,
93
+ or are blocked entirely.
94
+ """
95
+ mode: AutonomyMode
96
+
97
+ # Actions that are auto-approved
98
+ auto_approve: Set[ActionType] = field(default_factory=set)
99
+
100
+ # Actions that always require approval
101
+ require_approval: Set[ActionType] = field(default_factory=set)
102
+
103
+ # Actions that are blocked entirely
104
+ blocked: Set[ActionType] = field(default_factory=set)
105
+
106
+ # Trusted paths for file operations
107
+ trusted_paths: Set[str] = field(default_factory=set)
108
+
109
+ # Trusted commands (patterns)
110
+ trusted_commands: Set[str] = field(default_factory=set)
111
+
112
+ # Maximum auto-approved actions before requiring confirmation
113
+ max_auto_actions: int = 10
114
+
115
+ # Whether to show what would be done in suggest mode
116
+ show_preview: bool = True
117
+
118
+ @classmethod
119
+ def for_mode(cls, mode: AutonomyMode) -> "AutonomyPolicy":
120
+ """Create default policy for a given mode."""
121
+ if mode == AutonomyMode.SUGGEST:
122
+ return cls(
123
+ mode=mode,
124
+ auto_approve={ActionType.FILE_READ},
125
+ require_approval={
126
+ ActionType.FILE_WRITE,
127
+ ActionType.FILE_DELETE,
128
+ ActionType.SHELL_COMMAND,
129
+ ActionType.CODE_EXECUTION,
130
+ ActionType.GIT_OPERATION,
131
+ ActionType.NETWORK_REQUEST,
132
+ ActionType.TOOL_CALL,
133
+ },
134
+ blocked=set(),
135
+ show_preview=True
136
+ )
137
+ elif mode == AutonomyMode.AUTO_EDIT:
138
+ return cls(
139
+ mode=mode,
140
+ auto_approve={
141
+ ActionType.FILE_READ,
142
+ ActionType.FILE_WRITE,
143
+ ActionType.TOOL_CALL,
144
+ },
145
+ require_approval={
146
+ ActionType.FILE_DELETE,
147
+ ActionType.SHELL_COMMAND,
148
+ ActionType.CODE_EXECUTION,
149
+ ActionType.GIT_OPERATION,
150
+ ActionType.NETWORK_REQUEST,
151
+ },
152
+ blocked=set(),
153
+ show_preview=True
154
+ )
155
+ elif mode == AutonomyMode.FULL_AUTO:
156
+ return cls(
157
+ mode=mode,
158
+ auto_approve={
159
+ ActionType.FILE_READ,
160
+ ActionType.FILE_WRITE,
161
+ ActionType.FILE_DELETE,
162
+ ActionType.SHELL_COMMAND,
163
+ ActionType.CODE_EXECUTION,
164
+ ActionType.GIT_OPERATION,
165
+ ActionType.NETWORK_REQUEST,
166
+ ActionType.TOOL_CALL,
167
+ },
168
+ require_approval=set(),
169
+ blocked=set(),
170
+ show_preview=False,
171
+ max_auto_actions=100
172
+ )
173
+ else:
174
+ raise ValueError(f"Unknown mode: {mode}")
175
+
176
+
177
+ class AutonomyManager:
178
+ """
179
+ Manages autonomy mode and approval flow.
180
+
181
+ Handles:
182
+ - Mode transitions
183
+ - Approval requests
184
+ - Action tracking
185
+ - Policy enforcement
186
+ """
187
+
188
+ def __init__(
189
+ self,
190
+ mode: AutonomyMode = AutonomyMode.SUGGEST,
191
+ policy: Optional[AutonomyPolicy] = None,
192
+ approval_callback: Optional[Callable[[ActionRequest], ApprovalResult]] = None,
193
+ verbose: bool = False
194
+ ):
195
+ self.mode = mode
196
+ self.policy = policy or AutonomyPolicy.for_mode(mode)
197
+ self.approval_callback = approval_callback or self._default_approval
198
+ self.verbose = verbose
199
+
200
+ # Tracking
201
+ self._action_count = 0
202
+ self._auto_approved_count = 0
203
+ self._denied_count = 0
204
+ self._remembered_approvals: Dict[str, bool] = {}
205
+
206
+ def set_mode(self, mode: AutonomyMode) -> None:
207
+ """Change the autonomy mode."""
208
+ old_mode = self.mode
209
+ self.mode = mode
210
+ self.policy = AutonomyPolicy.for_mode(mode)
211
+
212
+ if self.verbose:
213
+ logger.info(f"Autonomy mode changed: {old_mode.value} -> {mode.value}")
214
+
215
+ def request_approval(self, action: ActionRequest) -> ApprovalResult:
216
+ """
217
+ Request approval for an action.
218
+
219
+ Returns:
220
+ ApprovalResult with approval decision
221
+ """
222
+ self._action_count += 1
223
+
224
+ # Check if blocked
225
+ if action.action_type in self.policy.blocked:
226
+ self._denied_count += 1
227
+ return ApprovalResult(
228
+ approved=False,
229
+ reason=f"Action type '{action.action_type.value}' is blocked by policy"
230
+ )
231
+
232
+ # Check remembered approvals
233
+ action_key = self._get_action_key(action)
234
+ if action_key in self._remembered_approvals:
235
+ approved = self._remembered_approvals[action_key]
236
+ if approved:
237
+ self._auto_approved_count += 1
238
+ else:
239
+ self._denied_count += 1
240
+ return ApprovalResult(approved=approved, reason="Remembered choice")
241
+
242
+ # Check if auto-approved
243
+ if action.action_type in self.policy.auto_approve:
244
+ # Check max auto actions
245
+ if self._auto_approved_count >= self.policy.max_auto_actions:
246
+ # Force approval after max auto actions
247
+ return self._request_user_approval(action)
248
+
249
+ self._auto_approved_count += 1
250
+ return ApprovalResult(approved=True, reason="Auto-approved by policy")
251
+
252
+ # Check if requires approval
253
+ if action.action_type in self.policy.require_approval:
254
+ return self._request_user_approval(action)
255
+
256
+ # Default: require approval for unknown action types
257
+ return self._request_user_approval(action)
258
+
259
+ def _request_user_approval(self, action: ActionRequest) -> ApprovalResult:
260
+ """Request approval from user via callback."""
261
+ result = self.approval_callback(action)
262
+
263
+ if result.remember_choice:
264
+ action_key = self._get_action_key(action)
265
+ self._remembered_approvals[action_key] = result.approved
266
+
267
+ if result.approved:
268
+ self._auto_approved_count += 1
269
+ else:
270
+ self._denied_count += 1
271
+
272
+ return result
273
+
274
+ def _get_action_key(self, action: ActionRequest) -> str:
275
+ """Generate a key for remembering approval decisions."""
276
+ # Use action type and relevant details
277
+ key_parts = [action.action_type.value]
278
+
279
+ if "path" in action.details:
280
+ key_parts.append(action.details["path"])
281
+ if "command" in action.details:
282
+ key_parts.append(action.details["command"])
283
+
284
+ return ":".join(key_parts)
285
+
286
+ def _default_approval(self, action: ActionRequest) -> ApprovalResult:
287
+ """Default approval callback using console input."""
288
+ from rich.console import Console
289
+ from rich.panel import Panel
290
+ from rich.prompt import Confirm
291
+
292
+ console = Console()
293
+
294
+ # Build action description
295
+ risk_color = {
296
+ "low": "green",
297
+ "medium": "yellow",
298
+ "high": "red"
299
+ }.get(action.risk_level, "white")
300
+
301
+ details_str = "\n".join(
302
+ f" {k}: {v}" for k, v in action.details.items()
303
+ ) if action.details else " (no details)"
304
+
305
+ panel_content = f"""
306
+ [bold]{action.description}[/bold]
307
+
308
+ Type: {action.action_type.value}
309
+ Risk: [{risk_color}]{action.risk_level}[/{risk_color}]
310
+ Reversible: {"Yes" if action.reversible else "No"}
311
+
312
+ Details:
313
+ {details_str}
314
+ """
315
+
316
+ console.print(Panel(
317
+ panel_content,
318
+ title="🔒 Approval Required",
319
+ border_style="yellow"
320
+ ))
321
+
322
+ approved = Confirm.ask("Approve this action?", default=False)
323
+ remember = False
324
+
325
+ if approved:
326
+ remember = Confirm.ask("Remember this choice for similar actions?", default=False)
327
+
328
+ return ApprovalResult(
329
+ approved=approved,
330
+ remember_choice=remember
331
+ )
332
+
333
+ def get_stats(self) -> Dict[str, int]:
334
+ """Get approval statistics."""
335
+ return {
336
+ "total_actions": self._action_count,
337
+ "auto_approved": self._auto_approved_count,
338
+ "denied": self._denied_count,
339
+ "remembered": len(self._remembered_approvals)
340
+ }
341
+
342
+ def reset_stats(self) -> None:
343
+ """Reset approval statistics."""
344
+ self._action_count = 0
345
+ self._auto_approved_count = 0
346
+ self._denied_count = 0
347
+
348
+ def clear_remembered(self) -> None:
349
+ """Clear remembered approval decisions."""
350
+ self._remembered_approvals.clear()
351
+
352
+
353
+ # ============================================================================
354
+ # CLI Integration Handler
355
+ # ============================================================================
356
+
357
+ class AutonomyModeHandler:
358
+ """
359
+ Handler for integrating autonomy modes with PraisonAI CLI.
360
+ """
361
+
362
+ def __init__(self, verbose: bool = False):
363
+ self.verbose = verbose
364
+ self._manager: Optional[AutonomyManager] = None
365
+
366
+ @property
367
+ def feature_name(self) -> str:
368
+ return "autonomy_mode"
369
+
370
+ def initialize(
371
+ self,
372
+ mode: str = "suggest",
373
+ approval_callback: Optional[Callable[[ActionRequest], ApprovalResult]] = None
374
+ ) -> AutonomyManager:
375
+ """
376
+ Initialize the autonomy manager.
377
+
378
+ Args:
379
+ mode: Autonomy mode string (suggest, auto_edit, full_auto)
380
+ approval_callback: Optional custom approval callback
381
+
382
+ Returns:
383
+ Configured AutonomyManager
384
+ """
385
+ try:
386
+ autonomy_mode = AutonomyMode.from_string(mode)
387
+ except ValueError:
388
+ logger.warning(f"Unknown mode '{mode}', defaulting to 'suggest'")
389
+ autonomy_mode = AutonomyMode.SUGGEST
390
+
391
+ self._manager = AutonomyManager(
392
+ mode=autonomy_mode,
393
+ approval_callback=approval_callback,
394
+ verbose=self.verbose
395
+ )
396
+
397
+ if self.verbose:
398
+ from rich import print as rprint
399
+ rprint(f"[cyan]Autonomy mode: {autonomy_mode.value}[/cyan]")
400
+
401
+ return self._manager
402
+
403
+ def get_manager(self) -> Optional[AutonomyManager]:
404
+ """Get the current autonomy manager."""
405
+ return self._manager
406
+
407
+ def request_approval(self, action: ActionRequest) -> ApprovalResult:
408
+ """Request approval for an action."""
409
+ if not self._manager:
410
+ self._manager = self.initialize()
411
+
412
+ return self._manager.request_approval(action)
413
+
414
+ def set_mode(self, mode: str) -> None:
415
+ """Change the autonomy mode."""
416
+ if not self._manager:
417
+ self.initialize(mode)
418
+ else:
419
+ try:
420
+ autonomy_mode = AutonomyMode.from_string(mode)
421
+ self._manager.set_mode(autonomy_mode)
422
+ except ValueError as e:
423
+ logger.error(f"Failed to set mode: {e}")
424
+
425
+ def get_mode(self) -> str:
426
+ """Get the current autonomy mode."""
427
+ if self._manager:
428
+ return self._manager.mode.value
429
+ return AutonomyMode.SUGGEST.value
430
+
431
+
432
+ # ============================================================================
433
+ # Convenience Functions
434
+ # ============================================================================
435
+
436
+ def create_file_write_action(path: str, content_preview: str = "") -> ActionRequest:
437
+ """Create an action request for file write."""
438
+ return ActionRequest(
439
+ action_type=ActionType.FILE_WRITE,
440
+ description=f"Write to file: {path}",
441
+ details={
442
+ "path": path,
443
+ "preview": content_preview[:200] if content_preview else "(no preview)"
444
+ },
445
+ risk_level="medium",
446
+ reversible=True
447
+ )
448
+
449
+
450
+ def create_shell_command_action(command: str, cwd: str = ".") -> ActionRequest:
451
+ """Create an action request for shell command."""
452
+ # Assess risk based on command
453
+ dangerous_patterns = ["rm ", "sudo ", "chmod ", "chown ", "> /", "| sh", "curl |"]
454
+ risk = "high" if any(p in command for p in dangerous_patterns) else "medium"
455
+
456
+ return ActionRequest(
457
+ action_type=ActionType.SHELL_COMMAND,
458
+ description=f"Execute command: {command}",
459
+ details={
460
+ "command": command,
461
+ "cwd": cwd
462
+ },
463
+ risk_level=risk,
464
+ reversible=False
465
+ )
466
+
467
+
468
+ def create_git_action(operation: str, details: Dict[str, Any] = None) -> ActionRequest:
469
+ """Create an action request for git operation."""
470
+ return ActionRequest(
471
+ action_type=ActionType.GIT_OPERATION,
472
+ description=f"Git {operation}",
473
+ details=details or {},
474
+ risk_level="low" if operation in ["status", "log", "diff"] else "medium",
475
+ reversible=operation not in ["push", "force-push"]
476
+ )
477
+
478
+
479
+ def create_tool_call_action(tool_name: str, args: Dict[str, Any] = None) -> ActionRequest:
480
+ """Create an action request for tool call."""
481
+ return ActionRequest(
482
+ action_type=ActionType.TOOL_CALL,
483
+ description=f"Call tool: {tool_name}",
484
+ details={
485
+ "tool": tool_name,
486
+ "args": args or {}
487
+ },
488
+ risk_level="low",
489
+ reversible=True
490
+ )