zrb 1.0.0a21__py3-none-any.whl → 1.0.0b3__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 (195) 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 +5 -3
  6. zrb/builtin/llm/tool/cli.py +1 -1
  7. zrb/builtin/llm/tool/rag.py +108 -145
  8. zrb/builtin/llm/tool/web.py +1 -1
  9. zrb/builtin/project/add/fastapp/fastapp_task.py +2 -0
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +5 -2
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +80 -20
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +150 -42
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +16 -6
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/client_method.py +57 -0
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +74 -0
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +1 -1
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +13 -0
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +23 -0
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +42 -0
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +7 -0
  26. 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
  27. 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
  28. 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
  29. 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
  30. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +11 -11
  31. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +2 -2
  32. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +8 -8
  33. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/util.py +47 -20
  34. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app_factory.py +29 -0
  35. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_db_repository.py +230 -102
  36. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +236 -0
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{db_engine.py → db_engine_factory.py} +1 -1
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/error.py +12 -0
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/logger_factory.py +10 -0
  40. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/parser_factory.py +7 -0
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/app.py +47 -0
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +105 -0
  43. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/user_agent.py +58 -0
  44. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/view.py +37 -0
  45. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +37 -1
  46. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +1 -1
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_api_client.py +16 -0
  48. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client.py +169 -0
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client_factory.py +9 -0
  50. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_direct_client.py +15 -0
  51. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +160 -0
  52. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py +18 -1
  53. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +7 -3
  54. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service.py +117 -0
  55. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service_factory.py +11 -0
  56. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_db_repository.py +26 -0
  57. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository.py +61 -0
  58. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository_factory.py +13 -0
  59. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +89 -0
  60. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository.py +67 -0
  61. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository_factory.py +13 -0
  62. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +137 -0
  63. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service_factory.py +7 -0
  64. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +179 -12
  65. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +67 -17
  66. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +2 -2
  67. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +127 -0
  68. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +7 -0
  69. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +43 -14
  70. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +200 -30
  71. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +74 -0
  72. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/error.html +6 -0
  73. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/homepage.html +6 -0
  74. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-192x192.png +0 -0
  75. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-512x512.png +0 -0
  76. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/favicon-32x32.png +0 -0
  77. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.amber.min.css +4 -0
  78. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.blue.min.css +4 -0
  79. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.cyan.min.css +4 -0
  80. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.fuchsia.min.css +4 -0
  81. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.green.min.css +4 -0
  82. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.grey.min.css +4 -0
  83. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.indigo.min.css +4 -0
  84. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.jade.min.css +4 -0
  85. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.lime.min.css +4 -0
  86. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.min.css +4 -0
  87. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.orange.min.css +4 -0
  88. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pink.min.css +4 -0
  89. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pumpkin.min.css +4 -0
  90. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.purple.min.css +4 -0
  91. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.red.min.css +4 -0
  92. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.sand.min.css +4 -0
  93. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.slate.min.css +4 -0
  94. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.violet.min.css +4 -0
  95. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.yellow.min.css +4 -0
  96. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.zinc.min.css +4 -0
  97. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html +34 -0
  98. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -0
  99. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +17 -5
  100. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +78 -4
  101. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/session.py +48 -0
  102. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +69 -5
  103. zrb/builtin/python.py +1 -1
  104. zrb/builtin/random.py +61 -0
  105. zrb/cmd/cmd_val.py +6 -5
  106. zrb/config.py +14 -1
  107. zrb/content_transformer/any_content_transformer.py +7 -0
  108. zrb/content_transformer/content_transformer.py +6 -0
  109. zrb/runner/cli.py +14 -7
  110. zrb/runner/web_app.py +28 -280
  111. zrb/runner/web_config/config.py +91 -0
  112. zrb/runner/web_config/config_factory.py +26 -0
  113. zrb/runner/web_route/docs_route.py +17 -0
  114. zrb/runner/web_route/error_page/serve_default_404.py +28 -0
  115. zrb/runner/{web_controller/error_page/controller.py → web_route/error_page/show_error_page.py} +4 -3
  116. zrb/runner/{web_controller → web_route}/error_page/view.html +5 -0
  117. zrb/runner/web_route/home_page/home_page_route.py +51 -0
  118. zrb/runner/web_route/login_api_route.py +31 -0
  119. zrb/runner/web_route/login_page/login_page_route.py +39 -0
  120. zrb/runner/web_route/logout_api_route.py +18 -0
  121. zrb/runner/web_route/logout_page/logout_page_route.py +40 -0
  122. zrb/runner/{web_controller/group_info_page/controller.py → web_route/node_page/group/show_group_page.py} +3 -3
  123. zrb/runner/web_route/node_page/node_page_route.py +50 -0
  124. zrb/runner/{web_controller/session_page/controller.py → web_route/node_page/task/show_task_page.py} +3 -3
  125. zrb/runner/web_route/refresh_token_api_route.py +38 -0
  126. zrb/runner/{web_controller/static → web_route/static/resources}/session/current-session.js +5 -2
  127. zrb/runner/{web_controller/static → web_route/static/resources}/session/event.js +5 -2
  128. zrb/runner/web_route/static/static_route.py +44 -0
  129. zrb/runner/web_route/task_input_api_route.py +47 -0
  130. zrb/runner/web_route/task_session_api_route.py +147 -0
  131. zrb/runner/web_schema/session.py +5 -0
  132. zrb/runner/web_schema/token.py +11 -0
  133. zrb/runner/web_schema/user.py +32 -0
  134. zrb/runner/web_util/cookie.py +29 -0
  135. zrb/runner/{web_util.py → web_util/html.py} +1 -23
  136. zrb/runner/web_util/token.py +72 -0
  137. zrb/runner/web_util/user.py +63 -0
  138. zrb/session/session.py +6 -4
  139. zrb/session_state_logger/{default_session_state_logger.py → session_state_logger_factory.py} +1 -1
  140. zrb/task/base_task.py +56 -8
  141. zrb/task/base_trigger.py +2 -0
  142. zrb/task/cmd_task.py +9 -5
  143. zrb/task/http_check.py +2 -0
  144. zrb/task/llm_task.py +184 -71
  145. zrb/task/make_task.py +2 -0
  146. zrb/task/rsync_task.py +2 -0
  147. zrb/task/scaffolder.py +8 -5
  148. zrb/task/scheduler.py +2 -0
  149. zrb/task/tcp_check.py +2 -0
  150. zrb/task_status/task_status.py +4 -3
  151. zrb/util/cmd/command.py +1 -0
  152. zrb/util/file.py +7 -1
  153. zrb/util/llm/tool.py +3 -7
  154. {zrb-1.0.0a21.dist-info → zrb-1.0.0b3.dist-info}/METADATA +2 -1
  155. zrb-1.0.0b3.dist-info/RECORD +307 -0
  156. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +0 -27
  157. 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
  158. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +0 -6
  159. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +0 -6
  160. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +0 -9
  161. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app.py +0 -20
  162. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_usecase.py +0 -245
  163. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/any_client.py +0 -33
  164. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +0 -7
  165. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +0 -6
  166. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +0 -9
  167. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
  168. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase.py +0 -53
  169. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +0 -6
  170. zrb/runner/web_config.py +0 -274
  171. zrb/runner/web_controller/home_page/controller.py +0 -33
  172. zrb/runner/web_controller/login_page/controller.py +0 -25
  173. zrb/runner/web_controller/logout_page/controller.py +0 -26
  174. zrb-1.0.0a21.dist-info/RECORD +0 -244
  175. /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/{create_column_task.py → add_column_task.py} +0 -0
  176. /zrb/{runner/web_controller → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission}/__init__.py +0 -0
  177. /zrb/{runner/web_controller/group_info_page → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role}/__init__.py +0 -0
  178. /zrb/runner/{web_controller/home_page → web_route}/__init__.py +0 -0
  179. /zrb/runner/{web_controller/session_page → web_route/home_page}/__init__.py +0 -0
  180. /zrb/runner/{web_controller → web_route}/home_page/view.html +0 -0
  181. /zrb/runner/{web_controller → web_route}/login_page/view.html +0 -0
  182. /zrb/runner/{web_controller → web_route}/logout_page/view.html +0 -0
  183. /zrb/runner/{web_controller/group_info_page → web_route/node_page/group}/view.html +0 -0
  184. /zrb/runner/{web_controller/session_page → web_route/node_page/task}/partial/input.html +0 -0
  185. /zrb/runner/{web_controller/session_page → web_route/node_page/task}/view.html +0 -0
  186. /zrb/runner/{refresh-token.template.js → web_route/static/refresh-token.template.js} +0 -0
  187. /zrb/runner/{web_controller/static → web_route/static/resources}/common.css +0 -0
  188. /zrb/runner/{web_controller/static → web_route/static/resources}/favicon-32x32.png +0 -0
  189. /zrb/runner/{web_controller/static → web_route/static/resources}/login/event.js +0 -0
  190. /zrb/runner/{web_controller/static → web_route/static/resources}/logout/event.js +0 -0
  191. /zrb/runner/{web_controller/static → web_route/static/resources}/pico.min.css +0 -0
  192. /zrb/runner/{web_controller/static → web_route/static/resources}/session/common-util.js +0 -0
  193. /zrb/runner/{web_controller/static → web_route/static/resources}/session/past-session.js +0 -0
  194. {zrb-1.0.0a21.dist-info → zrb-1.0.0b3.dist-info}/WHEEL +0 -0
  195. {zrb-1.0.0a21.dist-info → zrb-1.0.0b3.dist-info}/entry_points.txt +0 -0
zrb/task/llm_task.py CHANGED
@@ -17,6 +17,7 @@ from zrb.util.attr import get_str_attr
17
17
  from zrb.util.cli.style import stylize_faint
18
18
  from zrb.util.file import read_file, write_file
19
19
  from zrb.util.llm.tool import callable_to_tool_schema
20
+ from zrb.util.run import run_async
20
21
 
21
22
  ListOfDict = list[dict[str, Any]]
22
23
 
@@ -24,7 +25,6 @@ ListOfDict = list[dict[str, Any]]
24
25
  class AdditionalTool(BaseModel):
25
26
  fn: Callable
26
27
  name: str | None
27
- description: str | None
28
28
 
29
29
 
30
30
  def scratchpad(thought: str) -> str:
@@ -32,6 +32,11 @@ def scratchpad(thought: str) -> str:
32
32
  return thought
33
33
 
34
34
 
35
+ def end_conversation(final_answer: str) -> str:
36
+ """End conversation with a final answer containing all necessary information"""
37
+ return final_answer
38
+
39
+
35
40
  class LLMTask(BaseTask):
36
41
  def __init__(
37
42
  self,
@@ -47,9 +52,7 @@ class LLMTask(BaseTask):
47
52
  system_prompt: StrAttr | None = LLM_SYSTEM_PROMPT,
48
53
  render_system_prompt: bool = True,
49
54
  message: StrAttr | None = None,
50
- tools: (
51
- dict[str, Callable] | Callable[[AnySharedContext], dict[str, Callable]]
52
- ) = {},
55
+ tools: list[Callable] | Callable[[AnySharedContext], list[Callable]] = [],
53
56
  history: ListOfDict | Callable[[AnySharedContext], ListOfDict] = [],
54
57
  history_file: StrAttr | None = None,
55
58
  render_history_file: bool = True,
@@ -67,6 +70,7 @@ class LLMTask(BaseTask):
67
70
  monitor_readiness: bool = False,
68
71
  upstream: list[AnyTask] | AnyTask | None = None,
69
72
  fallback: list[AnyTask] | AnyTask | None = None,
73
+ successor: list[AnyTask] | AnyTask | None = None,
70
74
  ):
71
75
  super().__init__(
72
76
  name=name,
@@ -87,6 +91,7 @@ class LLMTask(BaseTask):
87
91
  monitor_readiness=monitor_readiness,
88
92
  upstream=upstream,
89
93
  fallback=fallback,
94
+ successor=successor,
90
95
  )
91
96
  self._model = model
92
97
  self._render_model = render_model
@@ -98,81 +103,156 @@ class LLMTask(BaseTask):
98
103
  self._history = history
99
104
  self._history_file = history_file
100
105
  self._render_history_file = render_history_file
101
- self._additional_tools: list[AdditionalTool] = []
102
106
 
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
- )
107
+ def add_tool(self, tool: Callable):
108
+ self._tools.append(tool)
109
109
 
110
110
  async def _exec_action(self, ctx: AnyContext) -> Any:
111
- from litellm import acompletion, supports_function_calling
111
+ import litellm
112
+ from litellm.utils import supports_function_calling
112
113
 
114
+ user_message = {"role": "user", "content": self._get_message(ctx)}
115
+ ctx.print(stylize_faint(f"{user_message}"))
113
116
  model = self._get_model(ctx)
114
117
  try:
115
- allow_function_call = supports_function_calling(model=model)
118
+ is_function_call_supported = supports_function_calling(model=model)
116
119
  except Exception:
117
- allow_function_call = False
118
- model_kwargs = self._get_model_kwargs(ctx)
120
+ is_function_call_supported = False
121
+ litellm.add_function_to_prompt = True
122
+ if not is_function_call_supported:
123
+ ctx.log_warning(f"Model {model} doesn't support function call")
124
+ available_tools = self._get_available_tools(
125
+ ctx, include_end_conversation=not is_function_call_supported
126
+ )
127
+ model_kwargs = self._get_model_kwargs(ctx, available_tools)
119
128
  ctx.log_debug("MODEL KWARGS", model_kwargs)
120
129
  system_prompt = self._get_system_prompt(ctx)
121
130
  ctx.log_debug("SYSTEM PROMPT", system_prompt)
122
131
  history = self._get_history(ctx)
123
132
  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)
133
+ conversations = history + [user_message]
146
134
  history_file = self._get_history_file(ctx)
147
135
  while True:
148
- response = await acompletion(
149
- model=model,
150
- messages=[{"role": "system", "content": system_prompt}] + messages,
151
- **model_kwargs,
136
+ llm_response = await self._get_llm_response(
137
+ model, system_prompt, conversations, model_kwargs
138
+ )
139
+ llm_response_dict = llm_response.to_dict()
140
+ ctx.print(stylize_faint(f"{llm_response_dict}"))
141
+ conversations.append(llm_response_dict)
142
+ ctx.log_debug("RESPONSE MESSAGE", llm_response)
143
+ if is_function_call_supported:
144
+ if not llm_response.tool_calls:
145
+ # No tool call, end conversation
146
+ self._save_conversation(history_file, conversations)
147
+ return llm_response.content
148
+ await self._handle_tool_calls(
149
+ ctx, available_tools, conversations, llm_response
150
+ )
151
+ if not is_function_call_supported:
152
+ try:
153
+ json_payload = json.loads(llm_response.content)
154
+ function_name = _get_fallback_function_name(json_payload)
155
+ function_kwargs = _get_fallback_function_kwargs(json_payload)
156
+ tool_execution_message = (
157
+ await self._create_fallback_tool_exec_message(
158
+ available_tools, function_name, function_kwargs
159
+ )
160
+ )
161
+ ctx.print(stylize_faint(f"{tool_execution_message}"))
162
+ conversations.append(tool_execution_message)
163
+ if function_name == "end_conversation":
164
+ self._save_conversation(history_file, conversations)
165
+ return function_kwargs.get("final_answer", "")
166
+ except Exception as e:
167
+ ctx.log_error(e)
168
+ tool_execution_message = self._create_exec_scratchpad_message(
169
+ f"{e}"
170
+ )
171
+ conversations.append(tool_execution_message)
172
+
173
+ async def _handle_tool_calls(
174
+ self,
175
+ ctx: AnyContext,
176
+ available_tools: dict[str, Callable],
177
+ conversations: list[dict[str, Any]],
178
+ llm_response: Any,
179
+ ):
180
+ # noqa Reference: https://docs.litellm.ai/docs/completion/function_call#full-code---parallel-function-calling-with-gpt-35-turbo-1106
181
+ for tool_call in llm_response.tool_calls:
182
+ tool_execution_message = await self._create_tool_exec_message(
183
+ available_tools, tool_call
152
184
  )
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
185
+ ctx.print(stylize_faint(f"{tool_execution_message}"))
186
+ conversations.append(tool_execution_message)
187
+
188
+ def _save_conversation(self, history_file: str, conversations: list[Any]):
189
+ if history_file != "":
190
+ write_file(history_file, json.dumps(conversations, indent=2))
191
+
192
+ async def _get_llm_response(
193
+ self,
194
+ model: str,
195
+ system_prompt: str,
196
+ conversations: list[Any],
197
+ model_kwargs: dict[str, Any],
198
+ ) -> Any:
199
+ from litellm import acompletion
200
+
201
+ llm_response = await acompletion(
202
+ model=model,
203
+ messages=[{"role": "system", "content": system_prompt}] + conversations,
204
+ **model_kwargs,
205
+ )
206
+ return llm_response.choices[0].message
207
+
208
+ async def _create_tool_exec_message(
209
+ self, available_tools: dict[str, Callable], tool_call: Any
210
+ ) -> dict[str, Any]:
211
+ function_name = tool_call.function.name
212
+ function_kwargs = json.loads(tool_call.function.arguments)
213
+ return {
214
+ "tool_call_id": tool_call.id,
215
+ "role": "tool",
216
+ "name": function_name,
217
+ "content": await self._get_exec_tool_result(
218
+ available_tools, function_name, function_kwargs
219
+ ),
220
+ }
221
+
222
+ async def _create_fallback_tool_exec_message(
223
+ self,
224
+ available_tools: dict[str, Callable],
225
+ function_name: str,
226
+ function_kwargs: dict[str, Any],
227
+ ) -> dict[str, Any]:
228
+ result = await self._get_exec_tool_result(
229
+ available_tools, function_name, function_kwargs
230
+ )
231
+ return self._create_exec_scratchpad_message(
232
+ f"Result of {function_name} call: {result}"
233
+ )
234
+
235
+ def _create_exec_scratchpad_message(self, message: str) -> dict[str, Any]:
236
+ return {
237
+ "role": "assistant",
238
+ "content": json.dumps(
239
+ {"name": "scratchpad", "arguments": {"thought": message}}
240
+ ),
241
+ }
242
+
243
+ async def _get_exec_tool_result(
244
+ self,
245
+ available_tools: dict[str, Callable],
246
+ function_name: str,
247
+ function_kwargs: dict[str, Any],
248
+ ) -> str:
249
+ if function_name not in available_tools:
250
+ return f"[ERROR] Invalid tool: {function_name}"
251
+ function_to_call = available_tools[function_name]
252
+ try:
253
+ return await run_async(function_to_call(**function_kwargs))
254
+ except Exception as e:
255
+ return f"[ERROR] {e}"
176
256
 
177
257
  def _get_model(self, ctx: AnyContext) -> str:
178
258
  return get_str_attr(
@@ -190,15 +270,29 @@ class LLMTask(BaseTask):
190
270
  def _get_message(self, ctx: AnyContext) -> str:
191
271
  return get_str_attr(ctx, self._message, "How are you?", auto_render=True)
192
272
 
193
- def _get_model_kwargs(self, ctx: AnyContext) -> dict[str, Callable]:
273
+ def _get_model_kwargs(
274
+ self, ctx: AnyContext, available_tools: dict[str, Callable]
275
+ ) -> dict[str, Any]:
276
+ model_kwargs = {}
194
277
  if callable(self._model_kwargs):
195
- return self._model_kwargs(ctx)
196
- return {**self._model_kwargs}
278
+ model_kwargs = self._model_kwargs(ctx)
279
+ else:
280
+ model_kwargs = self._model_kwargs
281
+ model_kwargs["tools"] = [
282
+ callable_to_tool_schema(tool) for tool in available_tools.values()
283
+ ]
284
+ return model_kwargs
197
285
 
198
- def _get_tools(self, ctx: AnyContext) -> dict[str, Callable]:
199
- if callable(self._tools):
200
- return self._tools(ctx)
201
- return self._tools
286
+ def _get_available_tools(
287
+ self, ctx: AnyContext, include_end_conversation: bool
288
+ ) -> dict[str, Callable]:
289
+ tools = {"scratchpad": scratchpad}
290
+ if include_end_conversation:
291
+ tools["end_conversation"] = end_conversation
292
+ tool_list = self._tools(ctx) if callable(self._tools) else self._tools
293
+ for tool in tool_list:
294
+ tools[tool.__name__] = tool
295
+ return tools
202
296
 
203
297
  def _get_history(self, ctx: AnyContext) -> ListOfDict:
204
298
  if callable(self._history):
@@ -216,3 +310,22 @@ class LLMTask(BaseTask):
216
310
  return get_str_attr(
217
311
  ctx, self._history_file, "", auto_render=self._render_history_file
218
312
  )
313
+
314
+
315
+ def _get_fallback_function_name(json_payload: dict[str, Any]) -> str:
316
+ for key in ("name",):
317
+ if key in json_payload:
318
+ return json_payload[key]
319
+ raise ValueError("Function name not provided")
320
+
321
+
322
+ def _get_fallback_function_kwargs(json_payload: dict[str, Any]) -> str:
323
+ for key in (
324
+ "arguments",
325
+ "args",
326
+ "parameters",
327
+ "params",
328
+ ):
329
+ if key in json_payload:
330
+ return json_payload[key]
331
+ raise ValueError("Function arguments not provided")
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
@@ -3,22 +3,18 @@ from collections.abc import Callable
3
3
  from typing import Any, 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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zrb
3
- Version: 1.0.0a21
3
+ Version: 1.0.0b3
4
4
  Summary: Your Automation Powerhouse
5
5
  Home-page: https://github.com/state-alchemists/zrb
6
6
  License: AGPL-3.0-or-later
@@ -26,6 +26,7 @@ Requires-Dist: pdfplumber (>=0.11.4,<0.12.0) ; extra == "rag"
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