zrb 1.0.0a21__py3-none-any.whl → 1.0.0b5__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 (207) hide show
  1. zrb/__init__.py +2 -1
  2. zrb/__main__.py +3 -3
  3. zrb/builtin/__init__.py +3 -0
  4. zrb/builtin/group.py +1 -0
  5. zrb/builtin/llm/llm_chat.py +87 -7
  6. zrb/builtin/llm/previous-session.js +21 -0
  7. zrb/builtin/llm/tool/api.py +29 -0
  8. zrb/builtin/llm/tool/cli.py +1 -1
  9. zrb/builtin/llm/tool/rag.py +108 -145
  10. zrb/builtin/llm/tool/web.py +1 -1
  11. zrb/builtin/project/add/fastapp/fastapp_task.py +2 -0
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +5 -2
  13. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +80 -20
  14. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +150 -42
  15. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_service.py +113 -0
  16. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_service_factory.py +9 -0
  17. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/my_entity_db_repository.py +0 -10
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/my_entity_repository.py +37 -16
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/{factory.py → my_entity_repository_factory.py} +2 -2
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +16 -6
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/client_method.py +57 -0
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +74 -0
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +1 -1
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +13 -0
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +23 -0
  26. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +42 -0
  27. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +7 -0
  28. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_api_client.py +6 -0
  29. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/{any_client.py → my_module_client.py} +1 -1
  30. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_client_factory.py +11 -0
  31. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_direct_client.py +5 -0
  32. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +11 -11
  33. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +2 -2
  34. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +8 -8
  35. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/util.py +47 -20
  36. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app_factory.py +29 -0
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_db_repository.py +230 -102
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +236 -0
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{db_engine.py → db_engine_factory.py} +1 -1
  40. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/error.py +12 -0
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/logger_factory.py +10 -0
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/parser_factory.py +7 -0
  43. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/app.py +47 -0
  44. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +105 -0
  45. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/user_agent.py +58 -0
  46. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/view.py +37 -0
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +37 -1
  48. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +1 -1
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_api_client.py +16 -0
  50. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client.py +169 -0
  51. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client_factory.py +9 -0
  52. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_direct_client.py +15 -0
  53. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +160 -0
  54. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py +18 -1
  55. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +7 -3
  56. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service.py +117 -0
  57. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service_factory.py +11 -0
  58. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_db_repository.py +26 -0
  59. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository.py +61 -0
  60. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository_factory.py +13 -0
  61. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +89 -0
  62. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository.py +67 -0
  63. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository_factory.py +13 -0
  64. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +137 -0
  65. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service_factory.py +7 -0
  66. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +179 -12
  67. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +67 -17
  68. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +2 -2
  69. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +127 -0
  70. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +7 -0
  71. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +43 -14
  72. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +200 -30
  73. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +74 -0
  74. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/error.html +6 -0
  75. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/homepage.html +6 -0
  76. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-192x192.png +0 -0
  77. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-512x512.png +0 -0
  78. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/favicon-32x32.png +0 -0
  79. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.amber.min.css +4 -0
  80. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.blue.min.css +4 -0
  81. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.cyan.min.css +4 -0
  82. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.fuchsia.min.css +4 -0
  83. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.green.min.css +4 -0
  84. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.grey.min.css +4 -0
  85. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.indigo.min.css +4 -0
  86. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.jade.min.css +4 -0
  87. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.lime.min.css +4 -0
  88. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.min.css +4 -0
  89. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.orange.min.css +4 -0
  90. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pink.min.css +4 -0
  91. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pumpkin.min.css +4 -0
  92. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.purple.min.css +4 -0
  93. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.red.min.css +4 -0
  94. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.sand.min.css +4 -0
  95. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.slate.min.css +4 -0
  96. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.violet.min.css +4 -0
  97. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.yellow.min.css +4 -0
  98. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.zinc.min.css +4 -0
  99. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html +34 -0
  100. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -0
  101. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +17 -5
  102. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +78 -4
  103. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/session.py +48 -0
  104. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +69 -5
  105. zrb/builtin/python.py +1 -1
  106. zrb/builtin/random.py +61 -0
  107. zrb/builtin/todo.py +1 -0
  108. zrb/cmd/cmd_val.py +6 -5
  109. zrb/config.py +15 -4
  110. zrb/content_transformer/any_content_transformer.py +7 -0
  111. zrb/content_transformer/content_transformer.py +6 -0
  112. zrb/input/any_input.py +5 -0
  113. zrb/input/base_input.py +6 -0
  114. zrb/input/bool_input.py +2 -0
  115. zrb/input/float_input.py +2 -0
  116. zrb/input/int_input.py +2 -0
  117. zrb/input/option_input.py +2 -0
  118. zrb/input/password_input.py +2 -0
  119. zrb/input/text_input.py +2 -0
  120. zrb/runner/cli.py +14 -7
  121. zrb/runner/common_util.py +1 -1
  122. zrb/runner/web_app.py +28 -280
  123. zrb/runner/web_config/config.py +91 -0
  124. zrb/runner/web_config/config_factory.py +26 -0
  125. zrb/runner/web_route/docs_route.py +17 -0
  126. zrb/runner/web_route/error_page/serve_default_404.py +28 -0
  127. zrb/runner/{web_controller/error_page/controller.py → web_route/error_page/show_error_page.py} +4 -3
  128. zrb/runner/{web_controller → web_route}/error_page/view.html +5 -0
  129. zrb/runner/web_route/home_page/home_page_route.py +51 -0
  130. zrb/runner/web_route/login_api_route.py +31 -0
  131. zrb/runner/web_route/login_page/login_page_route.py +39 -0
  132. zrb/runner/web_route/logout_api_route.py +18 -0
  133. zrb/runner/web_route/logout_page/logout_page_route.py +40 -0
  134. zrb/runner/{web_controller/group_info_page/controller.py → web_route/node_page/group/show_group_page.py} +3 -3
  135. zrb/runner/web_route/node_page/node_page_route.py +50 -0
  136. zrb/runner/{web_controller/session_page/controller.py → web_route/node_page/task/show_task_page.py} +3 -3
  137. zrb/runner/{web_controller/session_page → web_route/node_page/task}/view.html +1 -1
  138. zrb/runner/web_route/refresh_token_api_route.py +38 -0
  139. zrb/runner/{web_controller/static → web_route/static/resources}/session/current-session.js +12 -6
  140. zrb/runner/{web_controller/static → web_route/static/resources}/session/event.js +17 -2
  141. zrb/runner/web_route/static/static_route.py +44 -0
  142. zrb/runner/web_route/task_input_api_route.py +47 -0
  143. zrb/runner/web_route/task_session_api_route.py +147 -0
  144. zrb/runner/web_schema/session.py +5 -0
  145. zrb/runner/web_schema/token.py +11 -0
  146. zrb/runner/web_schema/user.py +32 -0
  147. zrb/runner/web_util/cookie.py +29 -0
  148. zrb/runner/{web_util.py → web_util/html.py} +1 -23
  149. zrb/runner/web_util/token.py +72 -0
  150. zrb/runner/web_util/user.py +63 -0
  151. zrb/session/session.py +6 -4
  152. zrb/session_state_logger/{default_session_state_logger.py → session_state_logger_factory.py} +1 -1
  153. zrb/task/base_task.py +56 -8
  154. zrb/task/base_trigger.py +2 -0
  155. zrb/task/cmd_task.py +9 -5
  156. zrb/task/http_check.py +2 -0
  157. zrb/task/llm_task.py +93 -110
  158. zrb/task/make_task.py +2 -0
  159. zrb/task/rsync_task.py +2 -0
  160. zrb/task/scaffolder.py +8 -5
  161. zrb/task/scheduler.py +2 -0
  162. zrb/task/tcp_check.py +2 -0
  163. zrb/task_status/task_status.py +4 -3
  164. zrb/util/cmd/command.py +1 -0
  165. zrb/util/file.py +7 -1
  166. zrb/util/llm/tool.py +36 -12
  167. {zrb-1.0.0a21.dist-info → zrb-1.0.0b5.dist-info}/METADATA +3 -2
  168. zrb-1.0.0b5.dist-info/RECORD +309 -0
  169. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +0 -27
  170. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_usecase.py +0 -65
  171. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +0 -6
  172. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +0 -6
  173. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +0 -9
  174. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app.py +0 -20
  175. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_usecase.py +0 -245
  176. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/any_client.py +0 -33
  177. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +0 -7
  178. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +0 -6
  179. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +0 -9
  180. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
  181. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase.py +0 -53
  182. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +0 -6
  183. zrb/runner/web_config.py +0 -274
  184. zrb/runner/web_controller/home_page/controller.py +0 -33
  185. zrb/runner/web_controller/login_page/controller.py +0 -25
  186. zrb/runner/web_controller/logout_page/controller.py +0 -26
  187. zrb-1.0.0a21.dist-info/RECORD +0 -244
  188. /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/{create_column_task.py → add_column_task.py} +0 -0
  189. /zrb/{runner/web_controller → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission}/__init__.py +0 -0
  190. /zrb/{runner/web_controller/group_info_page → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role}/__init__.py +0 -0
  191. /zrb/runner/{web_controller/home_page → web_route}/__init__.py +0 -0
  192. /zrb/runner/{web_controller/session_page → web_route/home_page}/__init__.py +0 -0
  193. /zrb/runner/{web_controller → web_route}/home_page/view.html +0 -0
  194. /zrb/runner/{web_controller → web_route}/login_page/view.html +0 -0
  195. /zrb/runner/{web_controller → web_route}/logout_page/view.html +0 -0
  196. /zrb/runner/{web_controller/group_info_page → web_route/node_page/group}/view.html +0 -0
  197. /zrb/runner/{web_controller/session_page → web_route/node_page/task}/partial/input.html +0 -0
  198. /zrb/runner/{refresh-token.template.js → web_route/static/refresh-token.template.js} +0 -0
  199. /zrb/runner/{web_controller/static → web_route/static/resources}/common.css +0 -0
  200. /zrb/runner/{web_controller/static → web_route/static/resources}/favicon-32x32.png +0 -0
  201. /zrb/runner/{web_controller/static → web_route/static/resources}/login/event.js +0 -0
  202. /zrb/runner/{web_controller/static → web_route/static/resources}/logout/event.js +0 -0
  203. /zrb/runner/{web_controller/static → web_route/static/resources}/pico.min.css +0 -0
  204. /zrb/runner/{web_controller/static → web_route/static/resources}/session/common-util.js +0 -0
  205. /zrb/runner/{web_controller/static → web_route/static/resources}/session/past-session.js +0 -0
  206. {zrb-1.0.0a21.dist-info → zrb-1.0.0b5.dist-info}/WHEEL +0 -0
  207. {zrb-1.0.0a21.dist-info → zrb-1.0.0b5.dist-info}/entry_points.txt +0 -0
zrb/task/cmd_task.py CHANGED
@@ -56,6 +56,7 @@ class CmdTask(BaseTask):
56
56
  monitor_readiness: bool = False,
57
57
  upstream: list[AnyTask] | AnyTask | None = None,
58
58
  fallback: list[AnyTask] | AnyTask | None = None,
59
+ successor: list[AnyTask] | AnyTask | None = None,
59
60
  ):
60
61
  super().__init__(
61
62
  name=name,
@@ -76,6 +77,7 @@ class CmdTask(BaseTask):
76
77
  monitor_readiness=monitor_readiness,
77
78
  upstream=upstream,
78
79
  fallback=fallback,
80
+ successor=successor,
79
81
  )
80
82
  self._shell = shell
81
83
  self._render_shell = render_shell
@@ -233,17 +235,18 @@ class CmdTask(BaseTask):
233
235
 
234
236
  def _render_cmd_val(self, ctx: AnyContext, cmd_val: CmdVal) -> str:
235
237
  if isinstance(cmd_val, list):
238
+ cmd_val_list = [
239
+ self.__render_single_cmd_val(ctx, single_cmd_val)
240
+ for single_cmd_val in cmd_val
241
+ ]
236
242
  return "\n".join(
237
- [
238
- self.__render_single_cmd_val(ctx, single_cmd_val)
239
- for single_cmd_val in cmd_val
240
- ]
243
+ [cmd_val for cmd_val in cmd_val_list if cmd_val is not None]
241
244
  )
242
245
  return self.__render_single_cmd_val(ctx, cmd_val)
243
246
 
244
247
  def __render_single_cmd_val(
245
248
  self, ctx: AnyContext, single_cmd_val: SingleCmdVal
246
- ) -> str:
249
+ ) -> str | None:
247
250
  if callable(single_cmd_val):
248
251
  return single_cmd_val(ctx)
249
252
  if isinstance(single_cmd_val, str):
@@ -252,6 +255,7 @@ class CmdTask(BaseTask):
252
255
  return single_cmd_val
253
256
  if isinstance(single_cmd_val, AnyCmdVal):
254
257
  return single_cmd_val.to_str(ctx)
258
+ return None
255
259
 
256
260
  def __get_multiline_repr(self, text: str) -> str:
257
261
  lines_repr: list[str] = []
zrb/task/http_check.py CHANGED
@@ -28,6 +28,7 @@ class HttpCheck(BaseTask):
28
28
  execute_condition: bool | str | Callable[[Context], bool] = True,
29
29
  upstream: list[AnyTask] | AnyTask | None = None,
30
30
  fallback: list[AnyTask] | AnyTask | None = None,
31
+ successor: list[AnyTask] | AnyTask | None = None,
31
32
  ):
32
33
  super().__init__(
33
34
  name=name,
@@ -41,6 +42,7 @@ class HttpCheck(BaseTask):
41
42
  retries=0,
42
43
  upstream=upstream,
43
44
  fallback=fallback,
45
+ successor=successor,
44
46
  )
45
47
  self._url = url
46
48
  self._render_url = render_url
zrb/task/llm_task.py CHANGED
@@ -3,7 +3,9 @@ import os
3
3
  from collections.abc import Callable
4
4
  from typing import Any
5
5
 
6
- from pydantic import BaseModel
6
+ from pydantic_ai import Agent, Tool
7
+ from pydantic_ai.messages import ModelMessagesTypeAdapter
8
+ from pydantic_ai.settings import ModelSettings
7
9
 
8
10
  from zrb.attr.type import StrAttr
9
11
  from zrb.config import LLM_MODEL, LLM_SYSTEM_PROMPT
@@ -16,20 +18,10 @@ from zrb.task.base_task import BaseTask
16
18
  from zrb.util.attr import get_str_attr
17
19
  from zrb.util.cli.style import stylize_faint
18
20
  from zrb.util.file import read_file, write_file
19
- from zrb.util.llm.tool import callable_to_tool_schema
21
+ from zrb.util.run import run_async
20
22
 
21
23
  ListOfDict = list[dict[str, Any]]
22
-
23
-
24
- class AdditionalTool(BaseModel):
25
- fn: Callable
26
- name: str | None
27
- description: str | None
28
-
29
-
30
- def scratchpad(thought: str) -> str:
31
- """Use this tool to note your thought and planning"""
32
- return thought
24
+ ToolOrCallable = Tool | Callable
33
25
 
34
26
 
35
27
  class LLMTask(BaseTask):
@@ -43,19 +35,28 @@ class LLMTask(BaseTask):
43
35
  input: list[AnyInput | None] | AnyInput | None = None,
44
36
  env: list[AnyEnv | None] | AnyEnv | None = None,
45
37
  model: StrAttr | None = LLM_MODEL,
38
+ model_settings: (
39
+ ModelSettings | Callable[[AnySharedContext], ModelSettings] | None
40
+ ) = None,
46
41
  render_model: bool = True,
42
+ agent: Agent | Callable[[AnySharedContext], Agent] | None = None,
47
43
  system_prompt: StrAttr | None = LLM_SYSTEM_PROMPT,
48
44
  render_system_prompt: bool = True,
49
45
  message: StrAttr | None = None,
50
46
  tools: (
51
- dict[str, Callable] | Callable[[AnySharedContext], dict[str, Callable]]
52
- ) = {},
53
- history: ListOfDict | Callable[[AnySharedContext], ListOfDict] = [],
54
- history_file: StrAttr | None = None,
47
+ list[ToolOrCallable] | Callable[[AnySharedContext], list[ToolOrCallable]]
48
+ ) = [],
49
+ conversation_history: (
50
+ ListOfDict | Callable[[AnySharedContext], ListOfDict]
51
+ ) = [],
52
+ conversation_history_reader: (
53
+ Callable[[AnySharedContext], ListOfDict] | None
54
+ ) = None,
55
+ conversation_history_writer: (
56
+ Callable[[AnySharedContext, ListOfDict], None] | None
57
+ ) = None,
58
+ conversation_history_file: StrAttr | None = None,
55
59
  render_history_file: bool = True,
56
- model_kwargs: (
57
- dict[str, Any] | Callable[[AnySharedContext], dict[str, Any]]
58
- ) = {},
59
60
  execute_condition: bool | str | Callable[[AnySharedContext], bool] = True,
60
61
  retries: int = 2,
61
62
  retry_period: float = 0,
@@ -65,8 +66,10 @@ class LLMTask(BaseTask):
65
66
  readiness_failure_threshold: int = 1,
66
67
  readiness_timeout: int = 60,
67
68
  monitor_readiness: bool = False,
69
+ max_call_iteration: int = 20,
68
70
  upstream: list[AnyTask] | AnyTask | None = None,
69
71
  fallback: list[AnyTask] | AnyTask | None = None,
72
+ successor: list[AnyTask] | AnyTask | None = None,
70
73
  ):
71
74
  super().__init__(
72
75
  name=name,
@@ -87,92 +90,77 @@ class LLMTask(BaseTask):
87
90
  monitor_readiness=monitor_readiness,
88
91
  upstream=upstream,
89
92
  fallback=fallback,
93
+ successor=successor,
90
94
  )
91
95
  self._model = model
96
+ self._model_settings = (model_settings,)
97
+ self._agent = agent
92
98
  self._render_model = render_model
93
- self._model_kwargs = model_kwargs
94
99
  self._system_prompt = system_prompt
95
100
  self._render_system_prompt = render_system_prompt
96
101
  self._message = message
97
102
  self._tools = tools
98
- self._history = history
99
- self._history_file = history_file
103
+ self._additional_tools: list[ToolOrCallable] = []
104
+ self._conversation_history = conversation_history
105
+ self._conversation_history_reader = conversation_history_reader
106
+ self._conversation_history_writer = conversation_history_writer
107
+ self._conversation_history_file = conversation_history_file
100
108
  self._render_history_file = render_history_file
101
- self._additional_tools: list[AdditionalTool] = []
109
+ self._max_call_iteration = max_call_iteration
102
110
 
103
- def add_tool(
104
- self, tool: Callable, name: str | None = None, description: str | None = None
105
- ):
106
- self._additional_tools.append(
107
- AdditionalTool(fn=tool, name=name, description=description)
108
- )
111
+ def add_tool(self, tool: ToolOrCallable):
112
+ self._additional_tools.append(tool)
109
113
 
110
114
  async def _exec_action(self, ctx: AnyContext) -> Any:
111
- from litellm import acompletion, supports_function_calling
112
-
113
- model = self._get_model(ctx)
114
- try:
115
- allow_function_call = supports_function_calling(model=model)
116
- except Exception:
117
- allow_function_call = False
118
- model_kwargs = self._get_model_kwargs(ctx)
119
- ctx.log_debug("MODEL KWARGS", model_kwargs)
120
- system_prompt = self._get_system_prompt(ctx)
121
- ctx.log_debug("SYSTEM PROMPT", system_prompt)
122
- history = self._get_history(ctx)
123
- ctx.log_debug("HISTORY PROMPT", history)
124
- user_message = {"role": "user", "content": self._get_message(ctx)}
125
- ctx.print(stylize_faint(f"{user_message}"))
126
- messages = history + [user_message]
127
- available_tools = self._get_tools(ctx)
128
- available_tools["scratchpad"] = scratchpad
129
- if allow_function_call:
130
- tool_schema = [
131
- callable_to_tool_schema(tool, name)
132
- for name, tool in available_tools.items()
133
- ]
134
- for additional_tool in self._additional_tools:
135
- fn = additional_tool.fn
136
- tool_name = additional_tool.name or fn.__name__
137
- tool_description = additional_tool.description
138
- available_tools[tool_name] = additional_tool.fn
139
- tool_schema.append(
140
- callable_to_tool_schema(
141
- fn, name=tool_name, description=tool_description
142
- )
143
- )
144
- model_kwargs["tools"] = tool_schema
145
- ctx.log_debug("TOOL SCHEMA", tool_schema)
115
+ history = await self._read_conversation_history(ctx)
116
+ user_prompt = self._get_message(ctx)
117
+ agent = self._get_agent(ctx)
118
+ result = await agent.run(
119
+ user_prompt=user_prompt,
120
+ message_history=ModelMessagesTypeAdapter.validate_python(history),
121
+ )
122
+ new_history = json.loads(result.all_messages_json())
123
+ for history in new_history:
124
+ ctx.print(stylize_faint(json.dumps(history)))
125
+ await self._write_conversation_history(ctx, new_history)
126
+ return result.data
127
+
128
+ async def _write_conversation_history(
129
+ self, ctx: AnyContext, conversations: list[Any]
130
+ ):
131
+ if self._conversation_history_writer is not None:
132
+ await run_async(self._conversation_history_writer(ctx, conversations))
146
133
  history_file = self._get_history_file(ctx)
147
- while True:
148
- response = await acompletion(
149
- model=model,
150
- messages=[{"role": "system", "content": system_prompt}] + messages,
151
- **model_kwargs,
152
- )
153
- response_message = response.choices[0].message
154
- ctx.print(stylize_faint(f"{response_message.to_dict()}"))
155
- messages.append(response_message.to_dict())
156
- tool_calls = response_message.tool_calls
157
- if tool_calls:
158
- # noqa Reference: https://docs.litellm.ai/docs/completion/function_call#full-code---parallel-function-calling-with-gpt-35-turbo-1106
159
- for tool_call in tool_calls:
160
- function_name = tool_call.function.name
161
- function_to_call = available_tools[function_name]
162
- function_kwargs = json.loads(tool_call.function.arguments)
163
- function_response = function_to_call(**function_kwargs)
164
- tool_call_message = {
165
- "tool_call_id": tool_call.id,
166
- "role": "tool",
167
- "name": function_name,
168
- "content": function_response,
169
- }
170
- ctx.print(stylize_faint(f"{tool_call_message}"))
171
- messages.append(tool_call_message)
172
- continue
173
- if history_file != "":
174
- write_file(history_file, json.dumps(messages, indent=2))
175
- return response_message.content
134
+ if history_file != "":
135
+ write_file(history_file, json.dumps(conversations, indent=2))
136
+
137
+ def _get_model_settings(self, ctx: AnyContext) -> ModelSettings | None:
138
+ if isinstance(self._model_settings, ModelSettings):
139
+ return self._model_settings
140
+ if callable(self._model_settings):
141
+ return self._model_settings(ctx)
142
+ return None
143
+
144
+ def _get_agent(self, ctx: AnyContext) -> Agent:
145
+ if isinstance(self._agent, Agent):
146
+ return self._agent
147
+ if callable(self._agent):
148
+ return self._agent(ctx)
149
+ tools_or_callables = list(
150
+ self._tools(ctx) if callable(self._tools) else self._tools
151
+ )
152
+ tools_or_callables.extend(self._additional_tools)
153
+ tools = [
154
+ tool if isinstance(tool, Tool) else Tool(tool, takes_ctx=False)
155
+ for tool in tools_or_callables
156
+ ]
157
+ for tool in tools:
158
+ print("tool", tool)
159
+ return Agent(
160
+ self._get_model(ctx),
161
+ system_prompt=self._get_system_prompt(ctx),
162
+ tools=tools,
163
+ )
176
164
 
177
165
  def _get_model(self, ctx: AnyContext) -> str:
178
166
  return get_str_attr(
@@ -190,29 +178,24 @@ class LLMTask(BaseTask):
190
178
  def _get_message(self, ctx: AnyContext) -> str:
191
179
  return get_str_attr(ctx, self._message, "How are you?", auto_render=True)
192
180
 
193
- def _get_model_kwargs(self, ctx: AnyContext) -> dict[str, Callable]:
194
- if callable(self._model_kwargs):
195
- return self._model_kwargs(ctx)
196
- return {**self._model_kwargs}
197
-
198
- def _get_tools(self, ctx: AnyContext) -> dict[str, Callable]:
199
- if callable(self._tools):
200
- return self._tools(ctx)
201
- return self._tools
202
-
203
- def _get_history(self, ctx: AnyContext) -> ListOfDict:
204
- if callable(self._history):
205
- return self._history(ctx)
181
+ async def _read_conversation_history(self, ctx: AnyContext) -> ListOfDict:
182
+ if self._conversation_history_reader is not None:
183
+ return await run_async(self._conversation_history_reader(ctx))
184
+ if callable(self._conversation_history):
185
+ return self._conversation_history(ctx)
206
186
  history_file = self._get_history_file(ctx)
207
187
  if (
208
- len(self._history) == 0
188
+ len(self._conversation_history) == 0
209
189
  and history_file != ""
210
190
  and os.path.isfile(history_file)
211
191
  ):
212
192
  return json.loads(read_file(history_file))
213
- return self._history
193
+ return self._conversation_history
214
194
 
215
195
  def _get_history_file(self, ctx: AnyContext) -> str:
216
196
  return get_str_attr(
217
- ctx, self._history_file, "", auto_render=self._render_history_file
197
+ ctx,
198
+ self._conversation_history_file,
199
+ "",
200
+ auto_render=self._render_history_file,
218
201
  )
zrb/task/make_task.py CHANGED
@@ -29,6 +29,7 @@ def make_task(
29
29
  monitor_readiness: bool = False,
30
30
  upstream: list[AnyTask] | AnyTask | None = None,
31
31
  fallback: list[AnyTask] | AnyTask | None = None,
32
+ successor: list[AnyTask] | AnyTask | None = None,
32
33
  group: AnyGroup | None = None,
33
34
  alias: str | None = None,
34
35
  ) -> Callable[[Callable[[AnyContext], Any]], AnyTask]:
@@ -53,6 +54,7 @@ def make_task(
53
54
  monitor_readiness=monitor_readiness,
54
55
  upstream=upstream,
55
56
  fallback=fallback,
57
+ successor=successor,
56
58
  )
57
59
  if group is not None:
58
60
  return group.add_task(task, alias=alias)
zrb/task/rsync_task.py CHANGED
@@ -49,6 +49,7 @@ class RsyncTask(CmdTask):
49
49
  readiness_check: list[AnyTask] | AnyTask | None = None,
50
50
  upstream: list[AnyTask] | AnyTask | None = None,
51
51
  fallback: list[AnyTask] | AnyTask | None = None,
52
+ successor: list[AnyTask] | AnyTask | None = None,
52
53
  ):
53
54
  super().__init__(
54
55
  name=name,
@@ -80,6 +81,7 @@ class RsyncTask(CmdTask):
80
81
  readiness_check=readiness_check,
81
82
  upstream=upstream,
82
83
  fallback=fallback,
84
+ successor=successor,
83
85
  )
84
86
  self._remote_source_path = remote_source_path
85
87
  self._render_remote_source_path = render_remote_source_path
zrb/task/scaffolder.py CHANGED
@@ -11,6 +11,7 @@ from zrb.input.any_input import AnyInput
11
11
  from zrb.task.any_task import AnyTask
12
12
  from zrb.task.base_task import BaseTask
13
13
  from zrb.util.attr import get_str_attr
14
+ from zrb.util.cli.style import stylize_faint
14
15
 
15
16
  TransformConfig = dict[str, str] | Callable[[AnyContext, str], str]
16
17
 
@@ -46,6 +47,7 @@ class Scaffolder(BaseTask):
46
47
  monitor_readiness: bool = False,
47
48
  upstream: list[AnyTask] | AnyTask | None = None,
48
49
  fallback: list[AnyTask] | AnyTask | None = None,
50
+ successor: list[AnyTask] | AnyTask | None = None,
49
51
  ):
50
52
  super().__init__(
51
53
  name=name,
@@ -66,6 +68,7 @@ class Scaffolder(BaseTask):
66
68
  monitor_readiness=monitor_readiness,
67
69
  upstream=upstream,
68
70
  fallback=fallback,
71
+ successor=successor,
69
72
  )
70
73
  self._source_path = source_path
71
74
  self._render_source_path = render_source_path
@@ -83,13 +86,12 @@ class Scaffolder(BaseTask):
83
86
  return get_str_attr(ctx, self._destination_path, "", auto_render=True)
84
87
 
85
88
  def _get_content_transformers(self) -> list[AnyContentTransformer]:
86
- if callable(self._content_transformers):
87
- return [
88
- ContentTransformer(match=".*", transform=self._content_transformers)
89
- ]
90
- if isinstance(self._content_transformers, dict):
89
+ if callable(self._content_transformers) or isinstance(
90
+ self._content_transformers, dict
91
+ ):
91
92
  return [
92
93
  ContentTransformer(
94
+ name="default-transform",
93
95
  match=".*",
94
96
  transform=self._content_transformers,
95
97
  auto_render=self._render_content_transformers,
@@ -109,6 +111,7 @@ class Scaffolder(BaseTask):
109
111
  for transformer in transformers:
110
112
  if transformer.match(ctx, file_path):
111
113
  try:
114
+ ctx.print(stylize_faint(f"{transformer.name}: {file_path}"))
112
115
  transformer.transform_file(ctx, file_path)
113
116
  except UnicodeDecodeError:
114
117
  pass
zrb/task/scheduler.py CHANGED
@@ -39,6 +39,7 @@ class Scheduler(BaseTrigger):
39
39
  monitor_readiness: bool = False,
40
40
  upstream: list[AnyTask] | AnyTask | None = None,
41
41
  fallback: list[AnyTask] | AnyTask | None = None,
42
+ successor: list[AnyTask] | AnyTask | None = None,
42
43
  ):
43
44
  super().__init__(
44
45
  name=name,
@@ -61,6 +62,7 @@ class Scheduler(BaseTrigger):
61
62
  monitor_readiness=monitor_readiness,
62
63
  upstream=upstream,
63
64
  fallback=fallback,
65
+ successor=successor,
64
66
  )
65
67
  self._cron_pattern = schedule
66
68
 
zrb/task/tcp_check.py CHANGED
@@ -28,6 +28,7 @@ class TcpCheck(BaseTask):
28
28
  execute_condition: bool | str | Callable[[Context], bool] = True,
29
29
  upstream: list[AnyTask] | AnyTask | None = None,
30
30
  fallback: list[AnyTask] | AnyTask | None = None,
31
+ successor: list[AnyTask] | AnyTask | None = None,
31
32
  ):
32
33
  super().__init__(
33
34
  name=name,
@@ -41,6 +42,7 @@ class TcpCheck(BaseTask):
41
42
  retries=0,
42
43
  upstream=upstream,
43
44
  fallback=fallback,
45
+ successor=successor,
44
46
  )
45
47
  self._host = host
46
48
  self._render_host = render_host
@@ -62,9 +62,10 @@ class TaskStatus:
62
62
  self._history.append((TASK_PERMANENTLY_FAILED, datetime.datetime.now()))
63
63
 
64
64
  def mark_as_terminated(self):
65
- self._is_terminated = True
66
- if not self.is_completed and not self.is_permanently_failed:
67
- self._history.append((TASK_TERMINATED, datetime.datetime.now()))
65
+ if not self._is_terminated:
66
+ self._is_terminated = True
67
+ if not (self.is_skipped or self.is_completed or self.is_permanently_failed):
68
+ self._history.append((TASK_TERMINATED, datetime.datetime.now()))
68
69
 
69
70
  @property
70
71
  def is_started(self) -> bool:
zrb/util/cmd/command.py CHANGED
@@ -62,6 +62,7 @@ async def run_command(
62
62
  log_method(line)
63
63
  return "\n".join(lines)
64
64
 
65
+ cmd_process = None
65
66
  try:
66
67
  if cwd is None:
67
68
  cwd = os.getcwd()
zrb/util/file.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import re
2
3
 
3
4
 
4
5
  def read_file(file_path: str, replace_map: dict[str, str] = {}) -> str:
@@ -14,5 +15,10 @@ def write_file(file_path: str, content: str | list[str]):
14
15
  content = "\n".join([line for line in content if line is not None])
15
16
  dir_path = os.path.dirname(file_path)
16
17
  os.makedirs(dir_path, exist_ok=True)
18
+ content = re.sub(r"\n{3,}$", "\n\n", content)
19
+ # Remove trailing newlines, but keep one if it exists
20
+ content = content.rstrip("\n")
21
+ if content.endswith("\n"):
22
+ content += "\n"
17
23
  with open(file_path, "w") as f:
18
- f.write(content.strip())
24
+ f.write(content)
zrb/util/llm/tool.py CHANGED
@@ -1,34 +1,34 @@
1
1
  import inspect
2
2
  from collections.abc import Callable
3
- from typing import Any, get_type_hints
3
+ from typing import Annotated, Any, Literal, get_type_hints
4
4
 
5
5
 
6
- def callable_to_tool_schema(
7
- callable_obj: Callable, name: str | None = None, description: str | None = None
8
- ) -> dict[str, Any]:
6
+ def callable_to_tool_schema(callable_obj: Callable) -> dict[str, Any]:
9
7
  """
10
8
  Convert a callable into a tool schema dictionary by deriving the parameter schema.
11
9
 
12
10
  :param callable_obj: The callable object (e.g., a function).
13
- :param name: The name to assign to the function in the schema.
14
- :param description: A description of the function.
15
11
  :return: A dictionary representing the tool schema.
16
12
  """
17
13
  if not callable(callable_obj):
18
14
  raise ValueError("Provided object is not callable")
19
15
  # Derive name and description
20
- name = name or callable_obj.__name__
21
- description = description or (callable_obj.__doc__ or "").strip()
16
+ name = callable_obj.__name__
17
+ description = (callable_obj.__doc__ or "").strip()
22
18
  # Get function signature
23
19
  sig = inspect.signature(callable_obj)
24
20
  hints = get_type_hints(callable_obj)
25
21
  # Build parameter schema
26
22
  param_schema = {"type": "object", "properties": {}, "required": []}
27
23
  for param_name, param in sig.parameters.items():
28
- param_type = hints.get(param_name, str) # Default type is string
29
- param_schema["properties"][param_name] = {
30
- "type": _python_type_to_json_type(param_type)
31
- }
24
+ # Get the type hint or default to str
25
+ param_type = hints.get(param_name, str)
26
+
27
+ # Handle annotated types (e.g., Annotated[str, "description"])
28
+ json_type, param_metadata = _process_type_annotation(param_type)
29
+ param_schema["properties"][param_name] = param_metadata
30
+
31
+ # Mark required parameters
32
32
  if param.default is inspect.Parameter.empty:
33
33
  param_schema["required"].append(param_name)
34
34
  return {
@@ -41,6 +41,30 @@ def callable_to_tool_schema(
41
41
  }
42
42
 
43
43
 
44
+ def _process_type_annotation(py_type: Any) -> tuple[str, dict]:
45
+ """
46
+ Process type annotations and return the JSON Schema type and metadata.
47
+
48
+ :param py_type: The type annotation.
49
+ :return: A tuple of (JSON type, parameter metadata).
50
+ """
51
+ if hasattr(py_type, "__origin__") and py_type.__origin__ is Literal:
52
+ # Handle Literal (enum)
53
+ enum_values = list(py_type.__args__)
54
+ return "string", {"type": "string", "enum": enum_values}
55
+
56
+ if hasattr(py_type, "__origin__") and py_type.__origin__ is Annotated:
57
+ # Handle Annotated types
58
+ base_type = py_type.__args__[0]
59
+ description = py_type.__args__[1]
60
+ json_type = _python_type_to_json_type(base_type)
61
+ return json_type, {"type": json_type, "description": description}
62
+
63
+ # Fallback to basic type conversion
64
+ json_type = _python_type_to_json_type(py_type)
65
+ return json_type, {"type": json_type}
66
+
67
+
44
68
  def _python_type_to_json_type(py_type):
45
69
  """
46
70
  Map Python types to JSON Schema types.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zrb
3
- Version: 1.0.0a21
3
+ Version: 1.0.0b5
4
4
  Summary: Your Automation Powerhouse
5
5
  Home-page: https://github.com/state-alchemists/zrb
6
6
  License: AGPL-3.0-or-later
@@ -21,11 +21,12 @@ Requires-Dist: chromadb (>=0.5.20,<0.6.0) ; extra == "rag"
21
21
  Requires-Dist: fastapi[standard] (>=0.115.6,<0.116.0)
22
22
  Requires-Dist: isort (>=5.13.2,<5.14.0)
23
23
  Requires-Dist: libcst (>=1.5.0,<2.0.0)
24
- Requires-Dist: litellm (>=1.52.12,<2.0.0)
25
24
  Requires-Dist: pdfplumber (>=0.11.4,<0.12.0) ; extra == "rag"
25
+ Requires-Dist: pydantic-ai (>=0.0.19,<0.0.20)
26
26
  Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
27
27
  Requires-Dist: python-jose[cryptography] (>=3.3.0,<4.0.0)
28
28
  Requires-Dist: requests (>=2.32.3,<3.0.0)
29
+ Requires-Dist: ulid-py (>=1.1.0,<2.0.0)
29
30
  Project-URL: Documentation, https://github.com/state-alchemists/zrb
30
31
  Project-URL: Repository, https://github.com/state-alchemists/zrb
31
32
  Description-Content-Type: text/markdown