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
@@ -1,5 +1,6 @@
1
1
  <!doctype html>
2
2
  <html lang="en">
3
+
3
4
  <head>
4
5
  <meta charset="utf-8">
5
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -9,6 +10,7 @@
9
10
  <title>Zrb</title>
10
11
  <link rel="stylesheet" href="/static/common.css">
11
12
  </head>
13
+
12
14
  <body>
13
15
  <header class="container">
14
16
  <hgroup>
@@ -26,9 +28,12 @@
26
28
  </hgroup>
27
29
  </header>
28
30
  <main class="container">
31
+ <article>
29
32
  <h2>{error_status_code}</h2>
30
33
  <p>{error_message}</p>
34
+ </article>
31
35
  </main>
32
36
  </body>
33
37
  <script src="/refresh-token.js"></script>
38
+
34
39
  </html>
@@ -0,0 +1,51 @@
1
+ import os
2
+ from typing import TYPE_CHECKING
3
+
4
+ from zrb.group.any_group import AnyGroup
5
+ from zrb.runner.web_config.config import WebConfig
6
+ from zrb.runner.web_util.html import (
7
+ get_html_auth_link,
8
+ get_html_subgroup_info,
9
+ get_html_subtask_info,
10
+ )
11
+ from zrb.runner.web_util.user import get_user_from_request
12
+ from zrb.util.file import read_file
13
+ from zrb.util.string.format import fstring_format
14
+
15
+ if TYPE_CHECKING:
16
+ # We want fastapi to only be loaded when necessary to decrease footprint
17
+ from fastapi import FastAPI
18
+
19
+
20
+ def serve_home_page(
21
+ app: "FastAPI",
22
+ root_group: AnyGroup,
23
+ web_config: WebConfig,
24
+ ) -> None:
25
+ from fastapi import Request
26
+ from fastapi.responses import HTMLResponse
27
+
28
+ # Serve homepage
29
+ @app.get("/", response_class=HTMLResponse, include_in_schema=False)
30
+ @app.get("/ui", response_class=HTMLResponse, include_in_schema=False)
31
+ @app.get("/ui/", response_class=HTMLResponse, include_in_schema=False)
32
+ async def home_page_ui(request: Request) -> HTMLResponse:
33
+
34
+ _DIR = os.path.dirname(__file__)
35
+ _VIEW_TEMPLATE = read_file(os.path.join(_DIR, "view.html"))
36
+ user = await get_user_from_request(web_config, request)
37
+ group_info = get_html_subgroup_info(user, "/ui/", root_group)
38
+ task_info = get_html_subtask_info(user, "/ui/", root_group)
39
+ auth_link = get_html_auth_link(user)
40
+ return HTMLResponse(
41
+ fstring_format(
42
+ _VIEW_TEMPLATE,
43
+ {
44
+ "group_info": group_info,
45
+ "task_info": task_info,
46
+ "name": root_group.name,
47
+ "description": root_group.description,
48
+ "auth_link": auth_link,
49
+ },
50
+ )
51
+ )
@@ -0,0 +1,31 @@
1
+ from typing import TYPE_CHECKING, Annotated
2
+
3
+ from zrb.runner.web_config.config import WebConfig
4
+ from zrb.runner.web_util.cookie import set_auth_cookie
5
+ from zrb.runner.web_util.token import generate_tokens_by_credentials
6
+
7
+ if TYPE_CHECKING:
8
+ # We want fastapi to only be loaded when necessary to decrease footprint
9
+ from fastapi import FastAPI
10
+
11
+
12
+ def serve_login_api(app: "FastAPI", web_config: WebConfig) -> None:
13
+ from fastapi import Depends, Response
14
+ from fastapi.responses import JSONResponse
15
+ from fastapi.security import OAuth2PasswordRequestForm
16
+
17
+ @app.post("/api/v1/login")
18
+ async def login_api(
19
+ response: Response, form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
20
+ ):
21
+ token = generate_tokens_by_credentials(
22
+ web_config=web_config,
23
+ username=form_data.username,
24
+ password=form_data.password,
25
+ )
26
+ if token is None:
27
+ return JSONResponse(
28
+ content={"detail": "Incorrect username or password"}, status_code=400
29
+ )
30
+ set_auth_cookie(web_config, response, token)
31
+ return token
@@ -0,0 +1,39 @@
1
+ import os
2
+ from typing import TYPE_CHECKING
3
+
4
+ from zrb.group.any_group import AnyGroup
5
+ from zrb.runner.web_config.config import WebConfig
6
+ from zrb.runner.web_util.html import get_html_auth_link
7
+ from zrb.runner.web_util.user import get_user_from_request
8
+ from zrb.util.file import read_file
9
+ from zrb.util.string.format import fstring_format
10
+
11
+ if TYPE_CHECKING:
12
+ # We want fastapi to only be loaded when necessary to decrease footprint
13
+ from fastapi import FastAPI
14
+
15
+
16
+ def serve_login_page(
17
+ app: "FastAPI",
18
+ root_group: AnyGroup,
19
+ web_config: WebConfig,
20
+ ) -> None:
21
+ from fastapi import Request
22
+ from fastapi.responses import HTMLResponse
23
+
24
+ @app.get("/login", response_class=HTMLResponse, include_in_schema=False)
25
+ async def login(request: Request) -> HTMLResponse:
26
+ _DIR = os.path.dirname(__file__)
27
+ _VIEW_TEMPLATE = read_file(os.path.join(_DIR, "view.html"))
28
+ user = await get_user_from_request(web_config, request)
29
+ auth_link = get_html_auth_link(user)
30
+ return HTMLResponse(
31
+ fstring_format(
32
+ _VIEW_TEMPLATE,
33
+ {
34
+ "name": root_group.name,
35
+ "description": root_group.description,
36
+ "auth_link": auth_link,
37
+ },
38
+ )
39
+ )
@@ -0,0 +1,18 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from zrb.runner.web_config.config import WebConfig
4
+
5
+ if TYPE_CHECKING:
6
+ # We want fastapi to only be loaded when necessary to decrease footprint
7
+ from fastapi import FastAPI
8
+
9
+
10
+ def serve_logout_api(app: "FastAPI", web_config: WebConfig) -> None:
11
+ from fastapi import Response
12
+
13
+ @app.get("/api/v1/logout")
14
+ @app.post("/api/v1/logout")
15
+ async def logout_api(response: Response):
16
+ response.delete_cookie(web_config.access_token_cookie_name)
17
+ response.delete_cookie(web_config.refresh_token_cookie_name)
18
+ return {"message": "Logout successful"}
@@ -0,0 +1,40 @@
1
+ import os
2
+ from typing import TYPE_CHECKING
3
+
4
+ from zrb.group.any_group import AnyGroup
5
+ from zrb.runner.web_config.config import WebConfig
6
+ from zrb.runner.web_util.html import get_html_auth_link
7
+ from zrb.runner.web_util.user import get_user_from_request
8
+ from zrb.util.file import read_file
9
+ from zrb.util.string.format import fstring_format
10
+
11
+ if TYPE_CHECKING:
12
+ # We want fastapi to only be loaded when necessary to decrease footprint
13
+ from fastapi import FastAPI
14
+
15
+
16
+ def serve_logout_page(
17
+ app: "FastAPI",
18
+ root_group: AnyGroup,
19
+ web_config: WebConfig,
20
+ ) -> None:
21
+ from fastapi import Request
22
+ from fastapi.responses import HTMLResponse
23
+
24
+ @app.get("/logout", response_class=HTMLResponse, include_in_schema=False)
25
+ async def logout(request: Request) -> HTMLResponse:
26
+ _DIR = os.path.dirname(__file__)
27
+ _VIEW_TEMPLATE = read_file(os.path.join(_DIR, "view.html"))
28
+ user = await get_user_from_request(web_config, request)
29
+ auth_link = get_html_auth_link(user)
30
+ return HTMLResponse(
31
+ fstring_format(
32
+ _VIEW_TEMPLATE,
33
+ {
34
+ "name": root_group.name,
35
+ "description": root_group.description,
36
+ "auth_link": auth_link,
37
+ "user": user,
38
+ },
39
+ )
40
+ )
@@ -1,8 +1,8 @@
1
1
  import os
2
2
 
3
3
  from zrb.group.any_group import AnyGroup
4
- from zrb.runner.web_config import User
5
- from zrb.runner.web_util import (
4
+ from zrb.runner.web_schema.user import User
5
+ from zrb.runner.web_util.html import (
6
6
  get_html_auth_link,
7
7
  get_html_subgroup_info,
8
8
  get_html_subtask_info,
@@ -11,7 +11,7 @@ from zrb.util.file import read_file
11
11
  from zrb.util.string.format import fstring_format
12
12
 
13
13
 
14
- def show_group_info_page(user: User, root_group: AnyGroup, group: AnyGroup, url: str):
14
+ def show_group_page(user: User, root_group: AnyGroup, group: AnyGroup, url: str):
15
15
  from fastapi.responses import HTMLResponse
16
16
 
17
17
  _DIR = os.path.dirname(__file__)
@@ -0,0 +1,50 @@
1
+ import os
2
+ from typing import TYPE_CHECKING
3
+
4
+ from zrb.context.shared_context import SharedContext
5
+ from zrb.group.any_group import AnyGroup
6
+ from zrb.runner.web_config.config import WebConfig
7
+ from zrb.runner.web_route.error_page.show_error_page import show_error_page
8
+ from zrb.runner.web_route.node_page.group.show_group_page import show_group_page
9
+ from zrb.runner.web_route.node_page.task.show_task_page import show_task_page
10
+ from zrb.runner.web_util.user import get_user_from_request
11
+ from zrb.session.session import Session
12
+ from zrb.task.any_task import AnyTask
13
+ from zrb.util.group import NodeNotFoundError, extract_node_from_args
14
+
15
+ if TYPE_CHECKING:
16
+ # We want fastapi to only be loaded when necessary to decrease footprint
17
+ from fastapi import FastAPI
18
+
19
+
20
+ def serve_node_page(
21
+ app: "FastAPI",
22
+ root_group: AnyGroup,
23
+ web_config: WebConfig,
24
+ ) -> None:
25
+ from fastapi import Request
26
+ from fastapi.responses import HTMLResponse
27
+
28
+ @app.get("/ui/{path:path}", response_class=HTMLResponse, include_in_schema=False)
29
+ async def ui_page(path: str, request: Request) -> HTMLResponse:
30
+ user = await get_user_from_request(web_config, request)
31
+ # Avoid capturing '/ui' itself
32
+ if not path:
33
+ return show_error_page(user, root_group, 422, "Undefined path")
34
+ args = path.strip("/").split("/")
35
+ try:
36
+ node, node_path, residual_args = extract_node_from_args(root_group, args)
37
+ except NodeNotFoundError as e:
38
+ return show_error_page(user, root_group, 404, str(e))
39
+ url = f"/ui/{'/'.join(node_path)}/"
40
+ if isinstance(node, AnyTask):
41
+ if not user.can_access_task(node):
42
+ return show_error_page(user, root_group, 403, "Forbidden")
43
+ shared_ctx = SharedContext(env=dict(os.environ))
44
+ session = Session(shared_ctx=shared_ctx, root_group=root_group)
45
+ return show_task_page(user, root_group, node, session, url, residual_args)
46
+ elif isinstance(node, AnyGroup):
47
+ if not user.can_access_group(node):
48
+ return show_error_page(user, root_group, 403, "Forbidden")
49
+ return show_group_page(user, root_group, node, url)
50
+ return show_error_page(user, root_group, 404, "Not found")
@@ -2,15 +2,15 @@ import json
2
2
  import os
3
3
 
4
4
  from zrb.group.any_group import AnyGroup
5
- from zrb.runner.web_config import User
6
- from zrb.runner.web_util import get_html_auth_link
5
+ from zrb.runner.web_schema.user import User
6
+ from zrb.runner.web_util.html import get_html_auth_link
7
7
  from zrb.session.any_session import AnySession
8
8
  from zrb.task.any_task import AnyTask
9
9
  from zrb.util.file import read_file
10
10
  from zrb.util.string.format import fstring_format
11
11
 
12
12
 
13
- def show_session_page(
13
+ def show_task_page(
14
14
  user: User,
15
15
  root_group: AnyGroup,
16
16
  task: AnyTask,
@@ -0,0 +1,38 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from zrb.runner.web_config.config import WebConfig
4
+ from zrb.runner.web_schema.token import RefreshTokenRequest
5
+ from zrb.runner.web_util.cookie import set_auth_cookie
6
+ from zrb.runner.web_util.token import regenerate_tokens
7
+
8
+ if TYPE_CHECKING:
9
+ # We want fastapi to only be loaded when necessary to decrease footprint
10
+ from fastapi import FastAPI
11
+
12
+
13
+ def serve_refresh_token_api(app: "FastAPI", web_config: WebConfig) -> None:
14
+ from fastapi import Cookie, Response
15
+ from fastapi.responses import JSONResponse
16
+
17
+ @app.post("/api/v1/refresh-token")
18
+ async def refresh_token_api(
19
+ response: Response,
20
+ body: RefreshTokenRequest = None,
21
+ refresh_token_cookie: str = Cookie(
22
+ None, alias=web_config.refresh_token_cookie_name
23
+ ),
24
+ ):
25
+ # Try to get the refresh token from the request body first
26
+ refresh_token = body.refresh_token if body else None
27
+ # If not in the body, try to get it from the cookie
28
+ if not refresh_token:
29
+ refresh_token = refresh_token_cookie
30
+ # If we still don't have a refresh token, raise an exception
31
+ if not refresh_token:
32
+ return JSONResponse(
33
+ content={"detail": "Refresh token not provided"}, status_code=400
34
+ )
35
+ # Get token
36
+ new_token = regenerate_tokens(web_config, refresh_token)
37
+ set_auth_cookie(web_config, response, new_token)
38
+ return new_token
@@ -13,14 +13,16 @@ const CURRENT_SESSION = {
13
13
  for (const inputName in dataInputs) {
14
14
  const inputValue = dataInputs[inputName];
15
15
  const input = submitTaskForm.querySelector(`[name="${inputName}"]`);
16
- input.value = inputValue;
16
+ if (input) {
17
+ input.value = inputValue;
18
+ }
17
19
  }
18
20
  resultLineCount = data.final_result.split("\n").length;
19
21
  resultTextarea.rows = resultLineCount <= 5 ? resultLineCount : 5;
20
22
  // update text areas
21
23
  resultTextarea.value = data.final_result;
22
24
  logTextarea.value = data.log.join("\n");
23
- logTextarea.scrollTop = logTextarea.scrollHeight;
25
+ // logTextarea.scrollTop = logTextarea.scrollHeight;
24
26
  // visualize history
25
27
  this.showCurrentSession(data.task_status, data.finished);
26
28
  if (data.finished) {
@@ -49,6 +51,7 @@ const CURRENT_SESSION = {
49
51
  "Content-Type": "application/json"
50
52
  },
51
53
  });
54
+ console.log("RESPONSE", response);
52
55
  return await response.json();
53
56
  } catch (error) {
54
57
  console.error("Error:", error);
@@ -20,9 +20,9 @@ window.addEventListener("load", async function () {
20
20
 
21
21
 
22
22
  const submitTaskForm = document.getElementById("submit-task-form");
23
- submitTaskForm.addEventListener("input", async function(event) {
23
+ submitTaskForm.addEventListener("change", async function(event) {
24
24
  const currentInput = event.target;
25
- const inputs = Array.from(submitTaskForm.querySelectorAll("input[name]"));
25
+ const inputs = Array.from(submitTaskForm.querySelectorAll("input[name], textarea[name]"));
26
26
  const inputMap = {};
27
27
  const fixedInputNames = [];
28
28
  for (const input of inputs) {
@@ -53,6 +53,9 @@ submitTaskForm.addEventListener("input", async function(event) {
53
53
  return;
54
54
  }
55
55
  const input = submitTaskForm.querySelector(`[name="${key}"]`);
56
+ if (input === currentInput) {
57
+ return;
58
+ }
56
59
  input.value = value;
57
60
  });
58
61
  } else {
@@ -0,0 +1,44 @@
1
+ import os
2
+ from typing import TYPE_CHECKING
3
+
4
+ from zrb.runner.web_config.config import WebConfig
5
+ from zrb.util.file import read_file
6
+
7
+ if TYPE_CHECKING:
8
+ # We want fastapi to only be loaded when necessary to decrease footprint
9
+ from fastapi import FastAPI
10
+
11
+
12
+ def serve_static_resources(app: "FastAPI", web_config: WebConfig) -> None:
13
+ from fastapi import HTTPException
14
+ from fastapi.responses import FileResponse, PlainTextResponse
15
+ from fastapi.staticfiles import StaticFiles
16
+
17
+ _STATIC_DIR = os.path.join(os.path.dirname(__file__), "resources")
18
+
19
+ app.mount("/static", StaticFiles(directory=_STATIC_DIR), name="static")
20
+
21
+ # Serve static files
22
+ @app.get("/static/{file_path:path}", include_in_schema=False)
23
+ async def static_files(file_path: str):
24
+ full_path = os.path.join(_STATIC_DIR, file_path)
25
+ if os.path.isfile(full_path):
26
+ return FileResponse(full_path)
27
+ raise HTTPException(status_code=404, detail="File not found")
28
+
29
+ @app.get("/refresh-token.js", include_in_schema=False)
30
+ async def refresh_token_js():
31
+ return PlainTextResponse(
32
+ content=_get_refresh_token_js(
33
+ 60 * web_config.refresh_token_expire_minutes / 3
34
+ ),
35
+ media_type="application/javascript",
36
+ )
37
+
38
+
39
+ def _get_refresh_token_js(refresh_interval_seconds: int):
40
+ _DIR = os.path.dirname(__file__)
41
+ return read_file(
42
+ os.path.join(_DIR, "refresh-token.template.js"),
43
+ {"refreshIntervalSeconds": f"{refresh_interval_seconds}"},
44
+ )
@@ -0,0 +1,47 @@
1
+ import json
2
+ from typing import TYPE_CHECKING
3
+
4
+ from zrb.group.any_group import AnyGroup
5
+ from zrb.runner.common_util import get_run_kwargs
6
+ from zrb.runner.web_config.config import WebConfig
7
+ from zrb.runner.web_util.user import get_user_from_request
8
+ from zrb.task.any_task import AnyTask
9
+ from zrb.util.group import NodeNotFoundError, extract_node_from_args
10
+
11
+ if TYPE_CHECKING:
12
+ # We want fastapi to only be loaded when necessary to decrease footprint
13
+ from fastapi import FastAPI
14
+
15
+
16
+ def serve_task_input_api(
17
+ app: "FastAPI",
18
+ root_group: AnyGroup,
19
+ web_config: WebConfig,
20
+ ) -> None:
21
+ from fastapi import Query, Request
22
+ from fastapi.responses import JSONResponse
23
+
24
+ @app.get("/api/v1/task-inputs/{path:path}", response_model=dict[str, str])
25
+ async def get_default_inputs_api(
26
+ path: str,
27
+ request: Request,
28
+ query: str = Query("{}", description="JSON encoded inputs"),
29
+ ) -> dict[str, str]:
30
+ """
31
+ Getting input completion for path
32
+ """
33
+ user = await get_user_from_request(web_config, request)
34
+ args = path.strip("/").split("/")
35
+ try:
36
+ task, _, _ = extract_node_from_args(root_group, args)
37
+ except NodeNotFoundError:
38
+ return JSONResponse(content={"detail": "Not found"}, status_code=404)
39
+ if isinstance(task, AnyTask):
40
+ if not user.can_access_task(task):
41
+ return JSONResponse(content={"detail": "Forbidden"}, status_code=403)
42
+ query_dict = json.loads(query)
43
+ run_kwargs = get_run_kwargs(
44
+ task=task, args=[], kwargs=query_dict, prompt=False
45
+ )
46
+ return run_kwargs
47
+ return JSONResponse(content={"detail": "Not found"}, status_code=404)
@@ -0,0 +1,147 @@
1
+ import asyncio
2
+ import os
3
+ from datetime import datetime, timedelta
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from zrb.context.shared_context import SharedContext
7
+ from zrb.group.any_group import AnyGroup
8
+ from zrb.runner.web_config.config import WebConfig
9
+ from zrb.runner.web_schema.session import NewSessionResponse
10
+ from zrb.runner.web_util.user import get_user_from_request
11
+ from zrb.session.session import Session
12
+ from zrb.session_state_log.session_state_log import SessionStateLog, SessionStateLogList
13
+ from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
14
+ from zrb.task.any_task import AnyTask
15
+ from zrb.util.group import NodeNotFoundError, extract_node_from_args, get_node_path
16
+
17
+ if TYPE_CHECKING:
18
+ # We want fastapi to only be loaded when necessary to decrease footprint
19
+
20
+ from fastapi import FastAPI
21
+
22
+
23
+ def serve_task_session_api(
24
+ app: "FastAPI",
25
+ root_group: AnyGroup,
26
+ web_config: WebConfig,
27
+ session_state_logger: AnySessionStateLogger,
28
+ coroutines: list,
29
+ ) -> None:
30
+ from fastapi import Query, Request
31
+ from fastapi.responses import JSONResponse
32
+
33
+ @app.post("/api/v1/task-sessions/{path:path}")
34
+ async def create_new_task_session_api(
35
+ path: str,
36
+ request: Request,
37
+ inputs: dict[str, Any],
38
+ ) -> NewSessionResponse:
39
+ """
40
+ Creating new session
41
+ """
42
+ user = await get_user_from_request(web_config, request)
43
+ args = path.strip("/").split("/")
44
+ try:
45
+ task, _, residual_args = extract_node_from_args(root_group, args)
46
+ except NodeNotFoundError:
47
+ return JSONResponse(content={"detail": "Not found"}, status_code=404)
48
+ if isinstance(task, AnyTask):
49
+ if not user.can_access_task(task):
50
+ return JSONResponse(content={"detail": "Forbidden"}, status_code=403)
51
+ session_name = residual_args[0] if residual_args else None
52
+ if not session_name:
53
+ shared_ctx = SharedContext(env=dict(os.environ))
54
+ session = Session(shared_ctx=shared_ctx, root_group=root_group)
55
+ coro = asyncio.create_task(task.async_run(session, str_kwargs=inputs))
56
+ coroutines.append(coro)
57
+ coro.add_done_callback(lambda coro: coroutines.remove(coro))
58
+ return NewSessionResponse(session_name=session.name)
59
+ return JSONResponse(content={"detail": "Not found"}, status_code=404)
60
+
61
+ @app.get(
62
+ "/api/v1/task-sessions/{path:path}",
63
+ response_model=SessionStateLog | SessionStateLogList,
64
+ )
65
+ async def get_task_session_api(
66
+ path: str,
67
+ request: Request,
68
+ min_start_query: str = Query(default=None, alias="from"),
69
+ max_start_query: str = Query(default=None, alias="to"),
70
+ page: int = Query(default=0, alias="page"),
71
+ limit: int = Query(default=10, alias="limit"),
72
+ ) -> SessionStateLog | SessionStateLogList:
73
+ """
74
+ Getting existing session or sessions
75
+ """
76
+ user = await get_user_from_request(web_config, request)
77
+ args = path.strip("/").split("/")
78
+ try:
79
+ task, _, residual_args = extract_node_from_args(root_group, args)
80
+ except NodeNotFoundError:
81
+ return JSONResponse(content={"detail": "Not found"}, status_code=404)
82
+ if isinstance(task, AnyTask) and residual_args:
83
+ if not user.can_access_task(task):
84
+ return JSONResponse(content={"detail": "Forbidden"}, status_code=403)
85
+ if residual_args[0] == "list":
86
+ task_path = get_node_path(root_group, task)
87
+ max_start_time = (
88
+ datetime.now()
89
+ if max_start_query is None
90
+ else datetime.strptime(max_start_query, "%Y-%m-%d %H:%M:%S")
91
+ )
92
+ min_start_time = (
93
+ max_start_time - timedelta(hours=1)
94
+ if min_start_query is None
95
+ else datetime.strptime(min_start_query, "%Y-%m-%d %H:%M:%S")
96
+ )
97
+ return sanitize_session_state_log_list(
98
+ task,
99
+ session_state_logger.list(
100
+ task_path, min_start_time, max_start_time, page, limit
101
+ ),
102
+ )
103
+ else:
104
+ return sanitize_session_state_log(
105
+ task, session_state_logger.read(residual_args[0])
106
+ )
107
+ return JSONResponse(content={"detail": "Not found"}, status_code=404)
108
+
109
+
110
+ def sanitize_session_state_log_list(
111
+ task: AnyTask, session_state_log_list: SessionStateLogList
112
+ ) -> SessionStateLogList:
113
+ return SessionStateLogList(
114
+ total=session_state_log_list.total,
115
+ data=[
116
+ sanitize_session_state_log(task, data)
117
+ for data in session_state_log_list.data
118
+ ],
119
+ )
120
+
121
+
122
+ def sanitize_session_state_log(
123
+ task: AnyTask, session_state_log: SessionStateLog
124
+ ) -> SessionStateLog:
125
+ """
126
+ In session, we create snake_case aliases of inputs.
127
+ The purpose was to increase ergonomics, so that user can use `input.system_prompt`
128
+ instead of `input["system-prompt"]`
129
+ However, when we serve the session through HTTP API,
130
+ we only want to show the original input names.
131
+ """
132
+ enhanced_inputs = session_state_log.input
133
+ real_inputs = {}
134
+ for real_input in task.inputs:
135
+ real_input_name = real_input.name
136
+ real_inputs[real_input_name] = enhanced_inputs[real_input_name]
137
+ return SessionStateLog(
138
+ name=session_state_log.name,
139
+ start_time=session_state_log.start_time,
140
+ main_task_name=session_state_log.main_task_name,
141
+ path=session_state_log.path,
142
+ input=real_inputs,
143
+ final_result=session_state_log.final_result,
144
+ finished=session_state_log.finished,
145
+ log=session_state_log.log,
146
+ task_status=session_state_log.task_status,
147
+ )
@@ -0,0 +1,5 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class NewSessionResponse(BaseModel):
5
+ session_name: str
@@ -0,0 +1,11 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class RefreshTokenRequest(BaseModel):
5
+ refresh_token: str
6
+
7
+
8
+ class Token(BaseModel):
9
+ access_token: str
10
+ refresh_token: str
11
+ token_type: str