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,422 @@
1
+ """
2
+ Recipe Policy Module
3
+
4
+ Provides policy management for recipes:
5
+ - Policy packs (reusable org-wide policies)
6
+ - Tool allow/deny enforcement
7
+ - Network/file restrictions
8
+ - PII defaults
9
+ - Mode enforcement (dev/prod)
10
+ """
11
+
12
+ import json
13
+ from pathlib import Path
14
+ from typing import Any, Dict, List, Optional, Set, Union
15
+
16
+ import yaml
17
+
18
+
19
+ class PolicyError(Exception):
20
+ """Base exception for policy operations."""
21
+ pass
22
+
23
+
24
+ class PolicyDeniedError(PolicyError):
25
+ """Action denied by policy."""
26
+ pass
27
+
28
+
29
+ # Default denied tools (dangerous by default)
30
+ DEFAULT_DENIED_TOOLS: Set[str] = {
31
+ "shell.exec",
32
+ "shell.run",
33
+ "shell_tool",
34
+ "execute_command",
35
+ "file.write",
36
+ "file.delete",
37
+ "fs.write",
38
+ "fs.delete",
39
+ "network.unrestricted",
40
+ "db.write",
41
+ "db.delete",
42
+ "db.drop",
43
+ }
44
+
45
+ # Default allowed tools (safe by default)
46
+ DEFAULT_ALLOWED_TOOLS: Set[str] = {
47
+ "web.search",
48
+ "web_search",
49
+ "tavily_search",
50
+ "file.read",
51
+ "fs.read",
52
+ "db.query",
53
+ "db.read",
54
+ }
55
+
56
+
57
+ class PolicyPack:
58
+ """
59
+ Reusable policy pack for org-wide policy management.
60
+
61
+ Policy pack YAML format:
62
+ ```yaml
63
+ name: my-org-policy
64
+ version: "1.0"
65
+ description: Organization-wide security policy
66
+
67
+ tools:
68
+ allow:
69
+ - web.search
70
+ - db.query
71
+ deny:
72
+ - shell.exec
73
+ - file.write
74
+
75
+ network:
76
+ allow_domains:
77
+ - api.openai.com
78
+ - api.anthropic.com
79
+ deny_domains:
80
+ - localhost
81
+ - 127.0.0.1
82
+
83
+ files:
84
+ allow_paths:
85
+ - /tmp
86
+ - ./outputs
87
+ deny_paths:
88
+ - /etc
89
+ - /var
90
+
91
+ pii:
92
+ mode: redact # allow, deny, redact
93
+ fields:
94
+ - email
95
+ - phone
96
+ - ssn
97
+
98
+ data:
99
+ retention_days: 30
100
+ export_allowed: true
101
+
102
+ modes:
103
+ dev:
104
+ allow_interactive_prompts: true
105
+ strict_tool_enforcement: false
106
+ prod:
107
+ allow_interactive_prompts: false
108
+ strict_tool_enforcement: true
109
+ require_auth: true
110
+ ```
111
+ """
112
+
113
+ def __init__(
114
+ self,
115
+ name: str = "default",
116
+ config: Optional[Dict[str, Any]] = None,
117
+ ):
118
+ """Initialize policy pack."""
119
+ self.name = name
120
+ self.config = config or {}
121
+
122
+ # Tool policies
123
+ self.allowed_tools: Set[str] = set(self.config.get("tools", {}).get("allow", []))
124
+ self.denied_tools: Set[str] = set(self.config.get("tools", {}).get("deny", []))
125
+
126
+ # Add defaults
127
+ self.denied_tools.update(DEFAULT_DENIED_TOOLS)
128
+
129
+ # Network policies
130
+ self.allowed_domains: Set[str] = set(self.config.get("network", {}).get("allow_domains", []))
131
+ self.denied_domains: Set[str] = set(self.config.get("network", {}).get("deny_domains", []))
132
+
133
+ # File policies
134
+ self.allowed_paths: List[str] = self.config.get("files", {}).get("allow_paths", [])
135
+ self.denied_paths: List[str] = self.config.get("files", {}).get("deny_paths", [])
136
+
137
+ # PII policy
138
+ self.pii_mode: str = self.config.get("pii", {}).get("mode", "allow")
139
+ self.pii_fields: List[str] = self.config.get("pii", {}).get("fields", [])
140
+
141
+ # Data policy
142
+ self.retention_days: Optional[int] = self.config.get("data", {}).get("retention_days")
143
+ self.export_allowed: bool = self.config.get("data", {}).get("export_allowed", True)
144
+
145
+ # Mode-specific settings
146
+ self.modes: Dict[str, Dict[str, Any]] = self.config.get("modes", {})
147
+
148
+ @classmethod
149
+ def load(cls, path: Union[str, Path]) -> "PolicyPack":
150
+ """Load policy pack from file."""
151
+ path = Path(path)
152
+ if not path.exists():
153
+ raise PolicyError(f"Policy file not found: {path}")
154
+
155
+ with open(path) as f:
156
+ if path.suffix in (".yaml", ".yml"):
157
+ config = yaml.safe_load(f)
158
+ else:
159
+ config = json.load(f)
160
+
161
+ name = config.get("name", path.stem)
162
+ return cls(name=name, config=config)
163
+
164
+ def save(self, path: Union[str, Path]):
165
+ """Save policy pack to file."""
166
+ path = Path(path)
167
+
168
+ data = {
169
+ "name": self.name,
170
+ "version": self.config.get("version", "1.0"),
171
+ "description": self.config.get("description", ""),
172
+ "tools": {
173
+ "allow": list(self.allowed_tools),
174
+ "deny": list(self.denied_tools),
175
+ },
176
+ "network": {
177
+ "allow_domains": list(self.allowed_domains),
178
+ "deny_domains": list(self.denied_domains),
179
+ },
180
+ "files": {
181
+ "allow_paths": self.allowed_paths,
182
+ "deny_paths": self.denied_paths,
183
+ },
184
+ "pii": {
185
+ "mode": self.pii_mode,
186
+ "fields": self.pii_fields,
187
+ },
188
+ "data": {
189
+ "retention_days": self.retention_days,
190
+ "export_allowed": self.export_allowed,
191
+ },
192
+ "modes": self.modes,
193
+ }
194
+
195
+ with open(path, "w") as f:
196
+ if path.suffix in (".yaml", ".yml"):
197
+ yaml.dump(data, f, default_flow_style=False)
198
+ else:
199
+ json.dump(data, f, indent=2)
200
+
201
+ def check_tool(self, tool_id: str, mode: str = "dev") -> bool:
202
+ """
203
+ Check if a tool is allowed.
204
+
205
+ Args:
206
+ tool_id: Tool identifier
207
+ mode: Execution mode (dev/prod)
208
+
209
+ Returns:
210
+ True if allowed
211
+
212
+ Raises:
213
+ PolicyDeniedError: If tool is denied
214
+ """
215
+ # Explicit deny always wins
216
+ if tool_id in self.denied_tools:
217
+ raise PolicyDeniedError(f"Tool denied by policy: {tool_id}")
218
+
219
+ # Check mode-specific settings
220
+ mode_config = self.modes.get(mode, {})
221
+ strict = mode_config.get("strict_tool_enforcement", mode == "prod")
222
+
223
+ if strict:
224
+ # In strict mode, tool must be explicitly allowed
225
+ if tool_id not in self.allowed_tools and tool_id not in DEFAULT_ALLOWED_TOOLS:
226
+ raise PolicyDeniedError(f"Tool not in allowlist (strict mode): {tool_id}")
227
+
228
+ return True
229
+
230
+ def check_domain(self, domain: str) -> bool:
231
+ """Check if a network domain is allowed."""
232
+ if domain in self.denied_domains:
233
+ raise PolicyDeniedError(f"Domain denied by policy: {domain}")
234
+
235
+ if self.allowed_domains and domain not in self.allowed_domains:
236
+ raise PolicyDeniedError(f"Domain not in allowlist: {domain}")
237
+
238
+ return True
239
+
240
+ def check_path(self, path: str) -> bool:
241
+ """Check if a file path is allowed."""
242
+ path_obj = Path(path).resolve()
243
+
244
+ for denied in self.denied_paths:
245
+ if str(path_obj).startswith(str(Path(denied).resolve())):
246
+ raise PolicyDeniedError(f"Path denied by policy: {path}")
247
+
248
+ if self.allowed_paths:
249
+ allowed = False
250
+ for allow in self.allowed_paths:
251
+ if str(path_obj).startswith(str(Path(allow).resolve())):
252
+ allowed = True
253
+ break
254
+ if not allowed:
255
+ raise PolicyDeniedError(f"Path not in allowlist: {path}")
256
+
257
+ return True
258
+
259
+ def get_data_policy(self) -> Dict[str, Any]:
260
+ """Get data policy configuration."""
261
+ return {
262
+ "pii": {
263
+ "mode": self.pii_mode,
264
+ "fields": self.pii_fields,
265
+ },
266
+ "retention_days": self.retention_days,
267
+ "export_allowed": self.export_allowed,
268
+ }
269
+
270
+ def get_mode_config(self, mode: str) -> Dict[str, Any]:
271
+ """Get mode-specific configuration."""
272
+ return self.modes.get(mode, {})
273
+
274
+ def merge(self, other: "PolicyPack") -> "PolicyPack":
275
+ """
276
+ Merge another policy pack (other takes precedence).
277
+
278
+ Args:
279
+ other: Policy pack to merge
280
+
281
+ Returns:
282
+ New merged policy pack
283
+ """
284
+ merged_config = {
285
+ "name": f"{self.name}+{other.name}",
286
+ "tools": {
287
+ "allow": list(self.allowed_tools | other.allowed_tools),
288
+ "deny": list(self.denied_tools | other.denied_tools),
289
+ },
290
+ "network": {
291
+ "allow_domains": list(self.allowed_domains | other.allowed_domains),
292
+ "deny_domains": list(self.denied_domains | other.denied_domains),
293
+ },
294
+ "files": {
295
+ "allow_paths": self.allowed_paths + other.allowed_paths,
296
+ "deny_paths": self.denied_paths + other.denied_paths,
297
+ },
298
+ "pii": {
299
+ "mode": other.pii_mode or self.pii_mode,
300
+ "fields": list(set(self.pii_fields + other.pii_fields)),
301
+ },
302
+ "data": {
303
+ "retention_days": other.retention_days or self.retention_days,
304
+ "export_allowed": other.export_allowed and self.export_allowed,
305
+ },
306
+ "modes": {**self.modes, **other.modes},
307
+ }
308
+
309
+ return PolicyPack(name=merged_config["name"], config=merged_config)
310
+
311
+ def to_dict(self) -> Dict[str, Any]:
312
+ """Convert to dictionary."""
313
+ return {
314
+ "name": self.name,
315
+ "tools": {
316
+ "allow": list(self.allowed_tools),
317
+ "deny": list(self.denied_tools),
318
+ },
319
+ "network": {
320
+ "allow_domains": list(self.allowed_domains),
321
+ "deny_domains": list(self.denied_domains),
322
+ },
323
+ "files": {
324
+ "allow_paths": self.allowed_paths,
325
+ "deny_paths": self.denied_paths,
326
+ },
327
+ "pii": {
328
+ "mode": self.pii_mode,
329
+ "fields": self.pii_fields,
330
+ },
331
+ "data": {
332
+ "retention_days": self.retention_days,
333
+ "export_allowed": self.export_allowed,
334
+ },
335
+ "modes": self.modes,
336
+ }
337
+
338
+
339
+ # Default policy packs
340
+ DEFAULT_DEV_POLICY = PolicyPack(
341
+ name="default-dev",
342
+ config={
343
+ "tools": {
344
+ "allow": list(DEFAULT_ALLOWED_TOOLS),
345
+ "deny": list(DEFAULT_DENIED_TOOLS),
346
+ },
347
+ "pii": {"mode": "allow"},
348
+ "modes": {
349
+ "dev": {
350
+ "allow_interactive_prompts": True,
351
+ "strict_tool_enforcement": False,
352
+ },
353
+ },
354
+ },
355
+ )
356
+
357
+ DEFAULT_PROD_POLICY = PolicyPack(
358
+ name="default-prod",
359
+ config={
360
+ "tools": {
361
+ "allow": list(DEFAULT_ALLOWED_TOOLS),
362
+ "deny": list(DEFAULT_DENIED_TOOLS),
363
+ },
364
+ "pii": {"mode": "redact", "fields": ["email", "phone", "ssn"]},
365
+ "modes": {
366
+ "prod": {
367
+ "allow_interactive_prompts": False,
368
+ "strict_tool_enforcement": True,
369
+ "require_auth": True,
370
+ },
371
+ },
372
+ },
373
+ )
374
+
375
+
376
+ def get_default_policy(mode: str = "dev") -> PolicyPack:
377
+ """Get default policy for a mode."""
378
+ if mode == "prod":
379
+ return DEFAULT_PROD_POLICY
380
+ return DEFAULT_DEV_POLICY
381
+
382
+
383
+ def load_policy(
384
+ policy_path: Optional[Union[str, Path]] = None,
385
+ mode: str = "dev",
386
+ ) -> PolicyPack:
387
+ """
388
+ Load policy from file or return default.
389
+
390
+ Args:
391
+ policy_path: Path to policy file (optional)
392
+ mode: Execution mode
393
+
394
+ Returns:
395
+ PolicyPack instance
396
+ """
397
+ if policy_path:
398
+ return PolicyPack.load(policy_path)
399
+ return get_default_policy(mode)
400
+
401
+
402
+ def check_tool_policy(
403
+ tool_id: str,
404
+ policy: Optional[PolicyPack] = None,
405
+ mode: str = "dev",
406
+ ) -> bool:
407
+ """
408
+ Check if a tool is allowed by policy.
409
+
410
+ Args:
411
+ tool_id: Tool identifier
412
+ policy: Policy pack (optional, uses default)
413
+ mode: Execution mode
414
+
415
+ Returns:
416
+ True if allowed
417
+
418
+ Raises:
419
+ PolicyDeniedError: If tool is denied
420
+ """
421
+ policy = policy or get_default_policy(mode)
422
+ return policy.check_tool(tool_id, mode)