writer 0.8.3rc4__py3-none-any.whl → 1.25.1rc1__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 (378) hide show
  1. writer/__init__.py +1 -1
  2. writer/abstract.py +1 -1
  3. writer/{ai.py → ai/__init__.py} +867 -163
  4. writer/app_runner.py +596 -241
  5. writer/app_templates/default/.wf/components-blueprints_blueprint-0-0decp3w5erhvl0nw.jsonl +11 -0
  6. writer/app_templates/default/.wf/components-blueprints_root.jsonl +1 -0
  7. writer/app_templates/default/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl +27 -0
  8. writer/app_templates/default/.wf/components-root.jsonl +1 -0
  9. writer/app_templates/default/.wf/components-workflows_root.jsonl +1 -0
  10. writer/app_templates/default/.wf/components-workflows_workflow-0-lfltcky7l1fsm6j2.jsonl +1 -0
  11. writer/app_templates/default/.wf/metadata.json +3 -0
  12. writer/app_templates/default/README.md +3 -0
  13. writer/app_templates/default/main.py +16 -0
  14. writer/app_templates/default/requirements.txt +1 -0
  15. writer/app_templates/default/static/README.md +8 -0
  16. writer/app_templates/default/static/agent_builder_demo.png +0 -0
  17. writer/app_templates/default/static/favicon.png +0 -0
  18. writer/app_templates/hello/.wf/components-blueprints_blueprint-0-t84xyhxau9ej3823.jsonl +18 -0
  19. writer/app_templates/hello/.wf/components-blueprints_root.jsonl +1 -0
  20. writer/app_templates/hello/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl +15 -0
  21. writer/app_templates/hello/.wf/components-root.jsonl +1 -0
  22. writer/app_templates/hello/.wf/metadata.json +3 -0
  23. writer/app_templates/hello/main.py +16 -0
  24. writer/app_templates/hello/static/README.md +8 -0
  25. writer/app_templates/hello/static/favicon.png +0 -0
  26. writer/app_templates/hello/static/welcome.svg +40 -0
  27. writer/auth.py +7 -2
  28. writer/autogen.py +352 -0
  29. writer/blocks/__init__.py +51 -17
  30. writer/blocks/addtostatelist.py +10 -9
  31. writer/blocks/apitrigger.py +45 -0
  32. writer/blocks/base_block.py +332 -21
  33. writer/blocks/base_trigger.py +14 -0
  34. writer/blocks/calleventhandler.py +39 -35
  35. writer/blocks/changepage.py +48 -0
  36. writer/blocks/code.py +102 -0
  37. writer/blocks/crontrigger.py +49 -0
  38. writer/blocks/foreach.py +70 -53
  39. writer/blocks/httprequest.py +112 -99
  40. writer/blocks/ifelse.py +71 -0
  41. writer/blocks/logmessage.py +34 -39
  42. writer/blocks/parsejson.py +30 -29
  43. writer/blocks/returnvalue.py +7 -7
  44. writer/blocks/runblueprint.py +63 -0
  45. writer/blocks/setstate.py +43 -33
  46. writer/blocks/sharedblueprint.py +86 -0
  47. writer/blocks/uieventtrigger.py +49 -0
  48. writer/blocks/writeraddchatmessage.py +50 -12
  49. writer/blocks/writeraddtokg.py +38 -11
  50. writer/blocks/writeraskkg.py +123 -0
  51. writer/blocks/writerchat.py +80 -61
  52. writer/blocks/writerchatreply.py +279 -0
  53. writer/blocks/writerchatreplywithtoolconfig.py +393 -0
  54. writer/blocks/writerclassification.py +78 -39
  55. writer/blocks/writercompletion.py +49 -44
  56. writer/blocks/writerfileapi.py +85 -0
  57. writer/blocks/writerinitchat.py +24 -12
  58. writer/blocks/writerkeyvaluestorage.py +106 -0
  59. writer/blocks/writernocodeapp.py +35 -37
  60. writer/blocks/writerparsepdf.py +73 -0
  61. writer/blocks/writerstructuredoutput.py +105 -0
  62. writer/blocks/writertoolcalling.py +251 -0
  63. writer/blocks/writervision.py +141 -0
  64. writer/blocks/writerwebsearch.py +175 -0
  65. writer/blueprints.py +839 -0
  66. writer/command_line.py +52 -16
  67. writer/core.py +562 -290
  68. writer/core_ui.py +6 -2
  69. writer/evaluator.py +98 -46
  70. writer/journal.py +227 -0
  71. writer/keyvalue_storage.py +93 -0
  72. writer/logs.py +277 -0
  73. writer/serve.py +625 -327
  74. writer/ss_types.py +101 -12
  75. writer/static/assets/Arrow.dom-GBJpMYQS.js +1 -0
  76. writer/static/assets/BaseMarkdown-Wrvby5J8.js +1 -0
  77. writer/static/assets/BlueprintToolbar-BuXNRxWT.js +1 -0
  78. writer/static/assets/BlueprintToolbar-wpfX0jo_.css +1 -0
  79. writer/static/assets/BuilderApp-PTOI76jZ.js +8 -0
  80. writer/static/assets/BuilderApp-WimUfNZr.css +1 -0
  81. writer/static/assets/BuilderApplicationSelect-DXzy4e_h.js +7 -0
  82. writer/static/assets/BuilderApplicationSelect-XaM1D5fv.css +1 -0
  83. writer/static/assets/BuilderBlueprintLibraryPanel-Ckrhknlh.css +1 -0
  84. writer/static/assets/BuilderBlueprintLibraryPanel-DBDzhTlc.js +1 -0
  85. writer/static/assets/BuilderEmbeddedCodeEditor-B0bcjlhk.css +1 -0
  86. writer/static/assets/BuilderEmbeddedCodeEditor-Dn7eDICN.js +726 -0
  87. writer/static/assets/BuilderGraphSelect-C-LRsO8W.js +7 -0
  88. writer/static/assets/BuilderGraphSelect-D7B61d5s.css +1 -0
  89. writer/static/assets/BuilderInsertionLabel-BhyL9wgn.js +1 -0
  90. writer/static/assets/BuilderInsertionLabel-_YS5WPfq.css +1 -0
  91. writer/static/assets/BuilderInsertionOverlay-D2XS0ij9.css +1 -0
  92. writer/static/assets/BuilderInsertionOverlay-MkAIVruY.js +1 -0
  93. writer/static/assets/BuilderJournal-A0LcEwGI.js +7 -0
  94. writer/static/assets/BuilderJournal-DHv3Pvvm.css +1 -0
  95. writer/static/assets/BuilderModelSelect-CdSo_sih.js +7 -0
  96. writer/static/assets/BuilderModelSelect-Dc4IPLp2.css +1 -0
  97. writer/static/assets/BuilderSettings-BDwZBveu.js +16 -0
  98. writer/static/assets/BuilderSettings-lZkOXEYw.css +1 -0
  99. writer/static/assets/BuilderSettingsArtifactAPITriggerDetails-3O6jKBXD.js +4 -0
  100. writer/static/assets/BuilderSettingsArtifactAPITriggerDetails-DnX66iRg.css +1 -0
  101. writer/static/assets/BuilderSettingsDeploySharedBlueprint-BR_3ptsd.js +1 -0
  102. writer/static/assets/BuilderSettingsDeploySharedBlueprint-KJTl8gxP.css +1 -0
  103. writer/static/assets/BuilderSettingsHandlers-CBtEQFSo.js +1 -0
  104. writer/static/assets/BuilderSettingsHandlers-DJPeASfz.css +1 -0
  105. writer/static/assets/BuilderSidebarComponentTree-DLltgas5.js +1 -0
  106. writer/static/assets/BuilderSidebarComponentTree-DYu1F793.css +1 -0
  107. writer/static/assets/BuilderSidebarToolkit-CApZNTAq.js +7 -0
  108. writer/static/assets/BuilderSidebarToolkit-CwqbjRv8.css +1 -0
  109. writer/static/assets/BuilderTemplateEditor-CYSDeWgV.css +1 -0
  110. writer/static/assets/BuilderTemplateEditor-DnRDRcA0.js +87 -0
  111. writer/static/assets/BuilderVault-2vGoV0sx.js +1 -0
  112. writer/static/assets/BuilderVault-Cx6oQSES.css +1 -0
  113. writer/static/assets/ComponentRenderer-72hqvEvI.css +1 -0
  114. writer/static/assets/ComponentRenderer-D4Pj1i3s.js +1 -0
  115. writer/static/assets/SharedCopyClipboardButton-BipJKGtz.css +1 -0
  116. writer/static/assets/SharedCopyClipboardButton-DNI9kLe6.js +1 -0
  117. writer/static/assets/WdsCheckbox-DKvpPA4D.css +1 -0
  118. writer/static/assets/WdsCheckbox-edQcn1cf.js +1 -0
  119. writer/static/assets/WdsDropdownMenu-CzzPN9Wg.css +1 -0
  120. writer/static/assets/WdsDropdownMenu-DQnrRBNV.js +1 -0
  121. writer/static/assets/WdsFieldWrapper-Cmufx5Nj.js +1 -0
  122. writer/static/assets/WdsFieldWrapper-CsemOh8D.css +1 -0
  123. writer/static/assets/WdsTabs-DKj7BqI0.css +1 -0
  124. writer/static/assets/WdsTabs-DcfY_zn5.js +1 -0
  125. writer/static/assets/abap-D8nrxEjS.js +6 -0
  126. writer/static/assets/apex-BrXDlLUW.js +6 -0
  127. writer/static/assets/art-paper-D70v1WMA.svg +180 -0
  128. writer/static/assets/azcli-CElzELwZ.js +6 -0
  129. writer/static/assets/bat-CUsyEhik.js +6 -0
  130. writer/static/assets/bicep-BtxyJn6H.js +7 -0
  131. writer/static/assets/cameligo-ClBCoF8h.js +6 -0
  132. writer/static/assets/clojure-B9TqLHAk.js +6 -0
  133. writer/static/assets/codicon-BA2IlpFX.ttf +0 -0
  134. writer/static/assets/coffee-DYsfeylR.js +6 -0
  135. writer/static/assets/cpp-VVGvvgir.js +6 -0
  136. writer/static/assets/csharp-Z6z2stHy.js +6 -0
  137. writer/static/assets/csp-DgZoLDI1.js +6 -0
  138. writer/static/assets/css-KqQ96-gC.js +8 -0
  139. writer/static/assets/css.worker-DvNUQFd1.js +84 -0
  140. writer/static/assets/cssMode-BYq4oZGq.js +9 -0
  141. writer/static/assets/cypher-CYoSlgTu.js +6 -0
  142. writer/static/assets/dart-BGDl7St1.js +6 -0
  143. writer/static/assets/dockerfile-CuCtxA7T.js +6 -0
  144. writer/static/assets/ecl-BCTFAUpS.js +6 -0
  145. writer/static/assets/editor.worker-BVwmgLrR.js +11 -0
  146. writer/static/assets/elixir-C7hRTYZ9.js +6 -0
  147. writer/static/assets/flow9-Bi_qi707.js +6 -0
  148. writer/static/assets/freemarker2-CnNourkO.js +8 -0
  149. writer/static/assets/fsharp-CxaaEKKi.js +6 -0
  150. writer/static/assets/go-DUImKuGY.js +6 -0
  151. writer/static/assets/graphql-D5sGVkLV.js +6 -0
  152. writer/static/assets/handlebars-Bm22yapJ.js +6 -0
  153. writer/static/assets/hcl-zD_CCkZ1.js +6 -0
  154. writer/static/assets/html-CAKAfoZF.js +6 -0
  155. writer/static/assets/html.worker-BJMlcbMU.js +458 -0
  156. writer/static/assets/htmlMode-BGZ97n-V.js +9 -0
  157. writer/static/assets/index-5u5REPT4.js +16 -0
  158. writer/static/assets/index-BKNuk68o.css +1 -0
  159. writer/static/assets/index-BQNXU3IR.js +17 -0
  160. writer/static/assets/index-BQr1pfrb.js +1 -0
  161. writer/static/assets/index-DHXAd5Yn.js +4 -0
  162. writer/static/assets/index-Zki-pfO-.js +8525 -0
  163. writer/static/assets/index.esm-B1ZQtduY.js +17 -0
  164. writer/static/assets/ini-8kKHd4ZL.js +6 -0
  165. writer/static/assets/java-De1axCfe.js +6 -0
  166. writer/static/assets/javascript-X1f02eyK.js +6 -0
  167. writer/static/assets/json.worker-BwvX8PuZ.js +42 -0
  168. writer/static/assets/jsonMode-hT0bNgT8.js +11 -0
  169. writer/static/assets/julia-D3ApGBxz.js +6 -0
  170. writer/static/assets/kotlin-GbSrCElU.js +6 -0
  171. writer/static/assets/less-DNUaDNdz.js +7 -0
  172. writer/static/assets/lexon-Bg9QKxBu.js +6 -0
  173. writer/static/assets/liquid-KmCCiJw2.js +6 -0
  174. writer/static/assets/lua-Crkvc3mc.js +6 -0
  175. writer/static/assets/m3-DsrzVyM1.js +6 -0
  176. writer/static/assets/mapbox-gl-C0cyFYYW.js +2329 -0
  177. writer/static/assets/markdown-CY5IOZuu.js +6 -0
  178. writer/static/assets/marked.esm-273vDTCT.js +45 -0
  179. writer/static/assets/mdx-DtRFauUw.js +6 -0
  180. writer/static/assets/mips-BE8RsGBA.js +6 -0
  181. writer/static/assets/msdax-N5ajIiFQ.js +6 -0
  182. writer/static/assets/mysql-DRxbB97D.js +6 -0
  183. writer/static/assets/objective-c-BHUZy23s.js +6 -0
  184. writer/static/assets/pascal-BemVzBTY.js +6 -0
  185. writer/static/assets/pascaligo-BACCcnx_.js +6 -0
  186. writer/static/assets/pdf-B6-yWJ-Y.js +12 -0
  187. writer/static/assets/pdf.worker.min-CyUfim15.mjs +21 -0
  188. writer/static/assets/perl-CuU66Ptk.js +6 -0
  189. writer/static/assets/pgsql-CQ6TMH2r.js +6 -0
  190. writer/static/assets/php-BvyzZa65.js +6 -0
  191. writer/static/assets/pla-DrIuu9u1.js +6 -0
  192. writer/static/assets/plotly.min-DutuuatZ.js +4030 -0
  193. writer/static/assets/poppins-latin-300-italic-4WBEAciR.woff +0 -0
  194. writer/static/assets/poppins-latin-300-italic-EWCPeN2Y.woff2 +0 -0
  195. writer/static/assets/poppins-latin-300-normal-DCNuMXUj.woff +0 -0
  196. writer/static/assets/poppins-latin-300-normal-Dku2WoCh.woff2 +0 -0
  197. writer/static/assets/poppins-latin-400-italic-B4GYq972.woff2 +0 -0
  198. writer/static/assets/poppins-latin-400-italic-BPejoDS-.woff +0 -0
  199. writer/static/assets/poppins-latin-400-normal-BOb3E3N0.woff +0 -0
  200. writer/static/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
  201. writer/static/assets/poppins-latin-500-italic-Ce_qjtl5.woff +0 -0
  202. writer/static/assets/poppins-latin-500-italic-o28Otv0U.woff2 +0 -0
  203. writer/static/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
  204. writer/static/assets/poppins-latin-500-normal-DGXqpDMm.woff +0 -0
  205. writer/static/assets/poppins-latin-600-italic-BhOZippK.woff +0 -0
  206. writer/static/assets/poppins-latin-600-italic-CZ4wqKBi.woff2 +0 -0
  207. writer/static/assets/poppins-latin-600-normal-BJdTmd5m.woff +0 -0
  208. writer/static/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
  209. writer/static/assets/poppins-latin-700-italic-CW91C-LJ.woff +0 -0
  210. writer/static/assets/poppins-latin-700-italic-RKf6esGj.woff2 +0 -0
  211. writer/static/assets/poppins-latin-700-normal-BVuQR_eA.woff +0 -0
  212. writer/static/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
  213. writer/static/assets/poppins-latin-ext-300-italic-CBzyU4Pf.woff +0 -0
  214. writer/static/assets/poppins-latin-ext-300-italic-DdDvTq5-.woff2 +0 -0
  215. writer/static/assets/poppins-latin-ext-300-normal-7Zg2msWE.woff2 +0 -0
  216. writer/static/assets/poppins-latin-ext-300-normal-C9p7gvmA.woff +0 -0
  217. writer/static/assets/poppins-latin-ext-400-italic-BiCGV3eO.woff2 +0 -0
  218. writer/static/assets/poppins-latin-ext-400-italic-gsPYOGqV.woff +0 -0
  219. writer/static/assets/poppins-latin-ext-400-normal-CIpeJEZw.woff2 +0 -0
  220. writer/static/assets/poppins-latin-ext-400-normal-Ce_uWq1Z.woff +0 -0
  221. writer/static/assets/poppins-latin-ext-500-italic-CwrTHwbn.woff2 +0 -0
  222. writer/static/assets/poppins-latin-ext-500-italic-jdc8Bv4M.woff +0 -0
  223. writer/static/assets/poppins-latin-ext-500-normal-Bl1-S02S.woff +0 -0
  224. writer/static/assets/poppins-latin-ext-500-normal-H4Q0z8D2.woff2 +0 -0
  225. writer/static/assets/poppins-latin-ext-600-italic-BqeDa496.woff2 +0 -0
  226. writer/static/assets/poppins-latin-ext-600-italic-C7MQPb_A.woff +0 -0
  227. writer/static/assets/poppins-latin-ext-600-normal-Cn4C8475.woff2 +0 -0
  228. writer/static/assets/poppins-latin-ext-600-normal-DB6FJURc.woff +0 -0
  229. writer/static/assets/poppins-latin-ext-700-italic-BAdhB_WS.woff2 +0 -0
  230. writer/static/assets/poppins-latin-ext-700-italic-WKTwQMp8.woff +0 -0
  231. writer/static/assets/poppins-latin-ext-700-normal-CE2WFKmF.woff +0 -0
  232. writer/static/assets/poppins-latin-ext-700-normal-DDaViAzG.woff2 +0 -0
  233. writer/static/assets/postiats-BR_hrfni.js +6 -0
  234. writer/static/assets/powerquery-CKDUeRmd.js +6 -0
  235. writer/static/assets/powershell-Dsa4rhA_.js +6 -0
  236. writer/static/assets/protobuf-CGsvhooB.js +7 -0
  237. writer/static/assets/pug-D2p3uOX2.js +6 -0
  238. writer/static/assets/python-DVhxg746.js +6 -0
  239. writer/static/assets/qsharp-B7F3HtPF.js +6 -0
  240. writer/static/assets/r-3aLoi2fs.js +6 -0
  241. writer/static/assets/razor-DR5Ns_BC.js +6 -0
  242. writer/static/assets/redis-jqFeRM5s.js +6 -0
  243. writer/static/assets/redshift-BriwQgXR.js +6 -0
  244. writer/static/assets/restructuredtext-hbBFZ0w9.js +6 -0
  245. writer/static/assets/ruby-ByThyB2Q.js +6 -0
  246. writer/static/assets/rust-DIEZMp5R.js +6 -0
  247. writer/static/assets/sb-C6Gjjw_x.js +6 -0
  248. writer/static/assets/scala-DZNw3jJB.js +6 -0
  249. writer/static/assets/scheme-55eqh71t.js +6 -0
  250. writer/static/assets/scss-D-OVkc4F.js +8 -0
  251. writer/static/assets/serialization-DJC7NP0N.js +20 -0
  252. writer/static/assets/shell-DSpi8_qN.js +6 -0
  253. writer/static/assets/solidity-BHddiNFS.js +6 -0
  254. writer/static/assets/sophia-D6taVZFb.js +6 -0
  255. writer/static/assets/sparql-LA0C7mUc.js +6 -0
  256. writer/static/assets/sql-C3-3IcFM.js +6 -0
  257. writer/static/assets/st-C4g7059C.js +6 -0
  258. writer/static/assets/swift-DNI1vH3h.js +8 -0
  259. writer/static/assets/systemverilog-DL_FVbcQ.js +6 -0
  260. writer/static/assets/tcl-DVJXmIwd.js +6 -0
  261. writer/static/assets/ts.worker-CwG1rUES.js +37021 -0
  262. writer/static/assets/tsMode-BNUEZzir.js +16 -0
  263. writer/static/assets/twig-BVWDLtw5.js +6 -0
  264. writer/static/assets/typescript-CRVt7Hx0.js +6 -0
  265. writer/static/assets/useBlueprintRun-C00bCxh-.js +1 -0
  266. writer/static/assets/useKeyValueEditor-nDmI7cTJ.js +1 -0
  267. writer/static/assets/useListResources-DLkZhRSJ.js +1 -0
  268. writer/static/assets/vb-Btz91-7U.js +6 -0
  269. writer/static/assets/vega-embed.module-SNP5iNdJ.js +201 -0
  270. writer/static/assets/wgsl-D8V_buCG.js +303 -0
  271. writer/static/assets/xml-C_6-t1tb.js +6 -0
  272. writer/static/assets/yaml-DIw8G7jk.js +6 -0
  273. writer/static/components/annotatedtext.svg +4 -0
  274. writer/static/components/avatar.svg +4 -0
  275. writer/static/components/blueprints_addtostatelist.svg +4 -0
  276. writer/static/components/blueprints_apitrigger.svg +4 -0
  277. writer/static/components/blueprints_calleventhandler.svg +9 -0
  278. writer/static/components/blueprints_category_Logic.svg +4 -0
  279. writer/static/components/blueprints_category_Other.svg +4 -0
  280. writer/static/components/blueprints_category_Triggers.svg +4 -0
  281. writer/static/components/blueprints_category_Writer.svg +25 -0
  282. writer/static/components/blueprints_code.svg +9 -0
  283. writer/static/components/blueprints_crontrigger.svg +6 -0
  284. writer/static/components/blueprints_foreach.svg +4 -0
  285. writer/static/components/blueprints_httprequest.svg +11 -0
  286. writer/static/components/blueprints_logmessage.svg +11 -0
  287. writer/static/components/blueprints_parsejson.svg +4 -0
  288. writer/static/components/blueprints_returnvalue.svg +4 -0
  289. writer/static/components/blueprints_runblueprint.svg +4 -0
  290. writer/static/components/blueprints_setstate.svg +4 -0
  291. writer/static/components/blueprints_uieventtrigger.svg +4 -0
  292. writer/static/components/blueprints_writeraddchatmessage.svg +19 -0
  293. writer/static/components/blueprints_writeraddtokg.svg +19 -0
  294. writer/static/components/blueprints_writerchat.svg +11 -0
  295. writer/static/components/blueprints_writerchatreply.svg +19 -0
  296. writer/static/components/blueprints_writerclassification.svg +24 -0
  297. writer/static/components/blueprints_writercompletion.svg +14 -0
  298. writer/static/components/blueprints_writerinitchat.svg +11 -0
  299. writer/static/components/blueprints_writernocodeapp.svg +14 -0
  300. writer/static/components/button.svg +4 -0
  301. writer/static/components/category_Content.svg +4 -0
  302. writer/static/components/category_Embed.svg +4 -0
  303. writer/static/components/category_Input.svg +5 -0
  304. writer/static/components/category_Layout.svg +9 -0
  305. writer/static/components/category_Other.svg +4 -0
  306. writer/static/components/chatbot.svg +4 -0
  307. writer/static/components/checkboxinput.svg +4 -0
  308. writer/static/components/colorinput.svg +11 -0
  309. writer/static/components/column.svg +4 -0
  310. writer/static/components/columns.svg +4 -0
  311. writer/static/components/dataframe.svg +4 -0
  312. writer/static/components/dateinput.svg +4 -0
  313. writer/static/components/dropdowninput.svg +5 -0
  314. writer/static/components/fileinput.svg +4 -0
  315. writer/static/components/googlemaps.svg +4 -0
  316. writer/static/components/header.svg +4 -0
  317. writer/static/components/heading.svg +9 -0
  318. writer/static/components/horizontalstack.svg +4 -0
  319. writer/static/components/html.svg +9 -0
  320. writer/static/components/icon.svg +4 -0
  321. writer/static/components/iframe.svg +4 -0
  322. writer/static/components/image.svg +11 -0
  323. writer/static/components/jsonviewer.svg +4 -0
  324. writer/static/components/link.svg +12 -0
  325. writer/static/components/mapbox.svg +4 -0
  326. writer/static/components/message.svg +4 -0
  327. writer/static/components/metric.svg +4 -0
  328. writer/static/components/multiselectinput.svg +4 -0
  329. writer/static/components/numberinput.svg +4 -0
  330. writer/static/components/page.svg +50 -0
  331. writer/static/components/pagination.svg +4 -0
  332. writer/static/components/pdf.svg +4 -0
  333. writer/static/components/plotlygraph.svg +7 -0
  334. writer/static/components/progressbar.svg +5 -0
  335. writer/static/components/radioinput.svg +4 -0
  336. writer/static/components/rangeinput.svg +4 -0
  337. writer/static/components/ratinginput.svg +4 -0
  338. writer/static/components/repeater.svg +4 -0
  339. writer/static/components/reuse.svg +4 -0
  340. writer/static/components/section.svg +4 -0
  341. writer/static/components/selectinput.svg +5 -0
  342. writer/static/components/separator.svg +4 -0
  343. writer/static/components/sidebar.svg +4 -0
  344. writer/static/components/sliderinput.svg +4 -0
  345. writer/static/components/step.svg +4 -0
  346. writer/static/components/steps.svg +4 -0
  347. writer/static/components/switchinput.svg +4 -0
  348. writer/static/components/tab.svg +4 -0
  349. writer/static/components/tabs.svg +4 -0
  350. writer/static/components/tags.svg +11 -0
  351. writer/static/components/text.svg +4 -0
  352. writer/static/components/textareainput.svg +11 -0
  353. writer/static/components/textinput.svg +4 -0
  354. writer/static/components/timeinput.svg +4 -0
  355. writer/static/components/timer.svg +4 -0
  356. writer/static/components/vegalitechart.svg +7 -0
  357. writer/static/components/videoplayer.svg +11 -0
  358. writer/static/components/webcamcapture.svg +4 -0
  359. writer/static/favicon.png +0 -0
  360. writer/static/index.html +84 -0
  361. writer/static/status/cancelled.svg +5 -0
  362. writer/static/status/error.svg +5 -0
  363. writer/static/status/skipped.svg +4 -0
  364. writer/static/status/stopped.svg +4 -0
  365. writer/static/status/success.svg +4 -0
  366. writer/sync.py +431 -0
  367. writer/ui.py +2268 -0
  368. writer/vault.py +48 -0
  369. writer/wf_project.py +90 -66
  370. writer-1.25.1rc1.dist-info/METADATA +92 -0
  371. writer-1.25.1rc1.dist-info/RECORD +382 -0
  372. {writer-0.8.3rc4.dist-info → writer-1.25.1rc1.dist-info}/WHEEL +1 -1
  373. writer/blocks/runworkflow.py +0 -59
  374. writer/workflows.py +0 -183
  375. writer-0.8.3rc4.dist-info/METADATA +0 -117
  376. writer-0.8.3rc4.dist-info/RECORD +0 -44
  377. {writer-0.8.3rc4.dist-info → writer-1.25.1rc1.dist-info}/entry_points.txt +0 -0
  378. {writer-0.8.3rc4.dist-info → writer-1.25.1rc1.dist-info/licenses}/LICENSE.txt +0 -0
@@ -1,42 +1,76 @@
1
- from typing import TYPE_CHECKING, Any, Dict, Type
1
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Type
2
2
 
3
+ import httpx
4
+ from writerai import DefaultHttpxClient, Writer
5
+
6
+ import writer.core_ui
3
7
  import writer.evaluator
4
8
  from writer.ss_types import WriterConfigurationError
5
9
 
6
10
  if TYPE_CHECKING:
11
+ from writer.blueprints import BlueprintRunner
7
12
  from writer.core_ui import Component
8
13
  from writer.ss_types import InstancePath
9
- from writer.workflows import WorkflowRunner
10
14
 
11
- WorkflowBlock_T = Type["WorkflowBlock"]
12
- block_map:Dict[str, WorkflowBlock_T] = {}
15
+ BlueprintBlock_T = Type["BlueprintBlock"]
16
+ block_map: Dict[str, BlueprintBlock_T] = {}
17
+
18
+
19
+ class BlueprintBlock:
20
+ _parent_client_class = httpx.Client
21
+ _custom_httpx_client: Optional[httpx.Client] = None
22
+ _log_requests: bool = True
13
23
 
14
- class WorkflowBlock:
15
-
16
24
  @classmethod
17
25
  def register(cls, type: str):
18
26
  block_map[type] = cls
19
27
 
20
- def __init__(self, component_id: str, runner: "WorkflowRunner", execution_environment: Dict):
21
- self.outcome = None
22
- self.message = None
23
- self.component_id = component_id
28
+ def __init_subclass__(
29
+ cls,
30
+ custom_httpx_client: Optional['httpx.Client'] = None,
31
+ log_requests: bool = True,
32
+ **kwargs
33
+ ):
34
+ super().__init_subclass__(**kwargs)
35
+ cls._custom_httpx_client = custom_httpx_client
36
+ cls._log_requests = log_requests
37
+
38
+ def __init__(
39
+ self,
40
+ component: writer.core_ui.Component,
41
+ runner: "BlueprintRunner",
42
+ execution_environment: Dict,
43
+ ):
44
+ self.outcome: Optional[str] = None
45
+ self.message: Optional[str] = None
46
+ self.component = component
24
47
  self.runner = runner
25
48
  self.execution_time_in_seconds = -1.0
49
+ self.started_at = -1.0
50
+ self.captured_stdout = ""
51
+ self.captured_logs = ""
26
52
  self.execution_environment = execution_environment
53
+ # A stable snapshot of the execution environment taken after the block
54
+ # has finished running. Used when generating logs to avoid concurrent
55
+ # mutations while serialising.
56
+ self.execution_environment_snapshot: Optional[Dict] = None
27
57
  self.result = None
28
58
  self.return_value = None
29
- self.instance_path: InstancePath = [{"componentId": component_id, "instanceNumber": 0}]
30
- self.evaluator = writer.evaluator.Evaluator(runner.session.session_state, runner.session.session_component_tree)
59
+ self.instance_path: InstancePath = [{"componentId": component.id, "instanceNumber": 0}]
60
+ self.evaluator = writer.evaluator.Evaluator(
61
+ runner.session.session_state, runner.session.session_component_tree
62
+ )
31
63
 
32
64
  def _handle_missing_field(self, field_key):
33
- component_tree = self.runner.session.session_component_tree
34
- component = component_tree.get_component(self.component_id)
35
- field_content = component.content.get(field_key)
65
+ field_content = self.component.content.get(field_key)
36
66
  if field_content:
37
- raise WriterConfigurationError(f'The field `{field_key}` is required. The expression specified, `{field_content}`, resulted in an empty value.')
67
+ raise WriterConfigurationError(
68
+ f"The field `{field_key}` is required. The expression specified, `{field_content}`, resulted in an empty value."
69
+ )
38
70
  else:
39
- raise WriterConfigurationError(f'The field `{field_key}` is required. It was left empty.')
71
+ raise WriterConfigurationError(
72
+ f"The field `{field_key}` is required. It was left empty."
73
+ )
40
74
 
41
75
  def _get_field(self, field_key: str, as_json=False, default_field_value=None, required=False):
42
76
  if default_field_value is None:
@@ -44,15 +78,292 @@ class WorkflowBlock:
44
78
  default_field_value = "{}"
45
79
  else:
46
80
  default_field_value = ""
47
- value = self.evaluator.evaluate_field(self.instance_path, field_key, as_json, default_field_value, self.execution_environment)
81
+ value = self.evaluator.evaluate_field(
82
+ self.instance_path, field_key, as_json, default_field_value, self.execution_environment
83
+ )
48
84
 
49
85
  if required and (value is None or value == "" or value == {}):
50
86
  self._handle_missing_field(field_key)
51
-
87
+
52
88
  return value
53
89
 
54
90
  def _set_state(self, expr: str, value: Any):
55
- self.evaluator.set_state(expr, self.instance_path, value, base_context=self.execution_environment)
91
+ self.evaluator.set_state(
92
+ expr, self.instance_path, value, base_context=self.execution_environment
93
+ )
56
94
 
57
95
  def run(self):
58
- pass
96
+ pass
97
+
98
+ def create_httpx_client(self, *args, **kwargs) -> httpx.Client:
99
+ """
100
+ Create a custom HTTPX client with request and response logging.
101
+ """
102
+ logger = self.create_logger() if self._log_requests else None
103
+
104
+ event_hooks = {
105
+ "request": [logger.request_hook] if logger else [],
106
+ "response": [logger.response_hook] if logger else [],
107
+ }
108
+
109
+ def send(self_inner, request, **kw):
110
+ response = self._parent_client_class.send(self_inner, request, **kw)
111
+ log_entry = response.extensions.get("log_entry")
112
+ if log_entry:
113
+ # Store reference to log entry for later update
114
+ response._log_entry_ref = log_entry
115
+
116
+ try:
117
+ # For non-streaming responses, capture content immediately
118
+ if response.is_closed or response.is_stream_consumed:
119
+ log_entry["response"]["content"] = response.text
120
+ else:
121
+ # For streaming responses, we'll update after consumption
122
+ log_entry["response"]["content"] = "<pending stream consumption>"
123
+
124
+ # Wrap the response read/iter methods to capture content after streaming
125
+ original_read = response.read
126
+ original_iter_raw = response.iter_raw
127
+ original_iter_bytes = response.iter_bytes
128
+ original_iter_text = response.iter_text
129
+ original_iter_lines = response.iter_lines
130
+
131
+ def wrapped_read():
132
+ try:
133
+ content = original_read()
134
+ except Exception as e:
135
+ if hasattr(response, '_log_entry_ref'):
136
+ response._log_entry_ref["response"]["content"] = f"<error reading response stream: {e}>"
137
+ raise
138
+ else:
139
+ if hasattr(response, '_log_entry_ref'):
140
+ try:
141
+ response._log_entry_ref["response"]["content"] = content.decode('utf-8', errors='replace')
142
+ except Exception:
143
+ response._log_entry_ref["response"]["content"] = "<binary content>"
144
+ return content
145
+
146
+ def wrapped_iter_raw(*args, **kwargs):
147
+ chunks = []
148
+ try:
149
+ for chunk in original_iter_raw(*args, **kwargs):
150
+ chunks.append(chunk)
151
+ yield chunk
152
+ finally:
153
+ if hasattr(response, '_log_entry_ref'):
154
+ try:
155
+ response._log_entry_ref["response"]["content"] = b"".join(chunks).decode("utf-8", errors="replace")
156
+ except Exception:
157
+ response._log_entry_ref["response"]["content"] = "<binary content>"
158
+
159
+ def wrapped_iter_bytes(*args, **kwargs):
160
+ accumulated_content = []
161
+ try:
162
+ for chunk in original_iter_bytes(*args, **kwargs):
163
+ accumulated_content.append(chunk)
164
+ yield chunk
165
+ finally:
166
+ if hasattr(response, '_log_entry_ref'):
167
+ try:
168
+ full_content = b''.join(accumulated_content)
169
+ response._log_entry_ref["response"]["content"] = full_content.decode('utf-8', errors='replace')
170
+ except Exception:
171
+ response._log_entry_ref["response"]["content"] = "<binary content>"
172
+
173
+ def wrapped_iter_text(*args, **kwargs):
174
+ text_chunks = []
175
+ try:
176
+ for chunk in original_iter_text(*args, **kwargs):
177
+ text_chunks.append(chunk)
178
+ yield chunk
179
+ finally:
180
+ if hasattr(response, '_log_entry_ref'):
181
+ response._log_entry_ref["response"]["content"] = ''.join(text_chunks)
182
+
183
+ def wrapped_iter_lines(*args, **kwargs):
184
+ lines = []
185
+ try:
186
+ for line in original_iter_lines(*args, **kwargs):
187
+ lines.append(line)
188
+ yield line
189
+ finally:
190
+ if hasattr(response, '_log_entry_ref'):
191
+ response._log_entry_ref["response"]["content"] = '\n'.join(lines)
192
+
193
+ response.read = wrapped_read
194
+ response.iter_raw = wrapped_iter_raw
195
+ response.iter_bytes = wrapped_iter_bytes
196
+ response.iter_text = wrapped_iter_text
197
+ response.iter_lines = wrapped_iter_lines
198
+ except Exception as e:
199
+ log_entry["response"]["content"] = f"<error reading response: {e}>"
200
+ return response
201
+
202
+ # Create a new class that inherits from the parent client class
203
+ # and overrides the send method to include logging.
204
+ LoggingHttpxClient = type(
205
+ "LoggingHttpxClient",
206
+ (self._parent_client_class,),
207
+ {"send": send}
208
+ )
209
+
210
+ return LoggingHttpxClient(
211
+ *args,
212
+ event_hooks=kwargs.pop("event_hooks", {}) | event_hooks,
213
+ **kwargs
214
+ )
215
+
216
+ def acquire_httpx_client(self) -> httpx.Client:
217
+ """
218
+ Acquire an HTTPX client for making requests.
219
+ """
220
+ if self._custom_httpx_client:
221
+ return self._custom_httpx_client
222
+
223
+ # Create a new HTTPX client with request and response logging
224
+ return self.create_httpx_client()
225
+
226
+ def create_logger(
227
+ self,
228
+ env_storage_key: Optional[str] = None
229
+ ):
230
+ import uuid
231
+ instance_path = self.instance_path[0].get('componentId', None)
232
+
233
+ class ExecutionEnvironmentLogger:
234
+ """
235
+ This class provides hooks to log requests and responses
236
+ to the execution environment.
237
+ """
238
+ env_storage_key = 'httpx_requests'
239
+
240
+ def __init__(
241
+ self,
242
+ env: Dict,
243
+ env_storage_key: Optional[str] = None
244
+ ):
245
+ self.env = env # Fallback environment
246
+
247
+ if env_storage_key:
248
+ self.env_storage_key = env_storage_key
249
+
250
+ # Create a copy of inherited API calls to avoid shared reference issues
251
+ inherited_calls = self.env.get(self.env_storage_key, [])
252
+ self.env[self.env_storage_key] = inherited_calls.copy()
253
+ self.instance_path = instance_path
254
+
255
+ def _get_current_execution_environment(self) -> Dict:
256
+ """Resolve the currently executing block's environment for logging."""
257
+ try:
258
+ from writer.blueprints import get_current_block
259
+ current_block = get_current_block()
260
+ if current_block and hasattr(current_block, 'execution_environment'):
261
+ return current_block.execution_environment
262
+ except Exception:
263
+ pass
264
+ return self.env
265
+
266
+ def request_hook(self, request: httpx.Request):
267
+ import datetime as dt
268
+ request_id = str(uuid.uuid4())
269
+
270
+ # Get the current block's ID for accurate logging
271
+ current_block_id = self.instance_path # fallback (should be componentId)
272
+ try:
273
+ from writer.blueprints import get_current_block
274
+ current_block = get_current_block()
275
+ if current_block and hasattr(current_block, 'instance_path'):
276
+ # Extract componentId from the current block's instance path
277
+ current_block_id = current_block.instance_path[0].get('componentId', None)
278
+ except Exception:
279
+ pass
280
+
281
+ # Capture request content
282
+ content = None
283
+ if request.content:
284
+ try:
285
+ content = request.content.decode('utf-8', errors='replace')
286
+ except Exception:
287
+ content = "<binary content>"
288
+ elif request.stream:
289
+ # For streaming requests, we can't easily capture the content
290
+ # without consuming the stream
291
+ content = "<streaming request body>"
292
+ else:
293
+ content = None
294
+
295
+ log_entry = {
296
+ 'id': request_id,
297
+ 'created_at': dt.datetime.now(dt.timezone.utc).isoformat(),
298
+ 'created_by': current_block_id,
299
+ 'request': {
300
+ 'method': request.method,
301
+ 'url': str(request.url),
302
+ 'headers': dict(request.headers),
303
+ 'content': content
304
+ },
305
+ 'response': None # Will populate later
306
+ }
307
+
308
+ # Resolve current block's environment for accurate logging
309
+ target_env = self._get_current_execution_environment()
310
+ target_env.setdefault(self.env_storage_key, []).append(log_entry)
311
+ request.extensions['log_entry'] = log_entry
312
+
313
+ def response_hook(self, response: httpx.Response):
314
+ log_entry = response.request.extensions.get('log_entry')
315
+ if not log_entry:
316
+ # Unlikely scenario
317
+ return
318
+
319
+ log_entry['response'] = {
320
+ 'status_code': response.status_code,
321
+ 'url': str(response.url),
322
+ 'headers': dict(response.headers),
323
+ 'content': None # Initially empty
324
+ }
325
+ response.extensions['log_entry'] = log_entry
326
+
327
+ return ExecutionEnvironmentLogger(
328
+ self.execution_environment,
329
+ env_storage_key=env_storage_key
330
+ )
331
+
332
+
333
+ class WriterBlock(BlueprintBlock):
334
+ """
335
+ Base class for all Writer blocks.
336
+ """
337
+ _parent_client_class = DefaultHttpxClient
338
+
339
+ def __init__(
340
+ self,
341
+ component: writer.core_ui.Component,
342
+ runner: "BlueprintRunner",
343
+ execution_environment: Dict,
344
+ ):
345
+ super().__init__(component, runner, execution_environment)
346
+
347
+ # Initialize the SDK client via block property
348
+ # to set the context and enable logging for AI module downstream.
349
+ # This way, the AI module can use the same HTTPX client
350
+ # without explicitly passing it.
351
+ _ = self.writer_sdk_client
352
+
353
+ def _acquire_writer_client(
354
+ self,
355
+ force_new_client: Optional[bool] = False
356
+ ) -> Writer:
357
+ from writer.ai import WriterAIManager
358
+
359
+ return WriterAIManager.acquire_client(
360
+ custom_httpx_client=self.acquire_httpx_client(),
361
+ force_new_client=force_new_client
362
+ )
363
+
364
+ def create_logger(self, env_storage_key: Optional[str] = "api_calls"):
365
+ return super().create_logger(env_storage_key=env_storage_key)
366
+
367
+ @property
368
+ def writer_sdk_client(self) -> Writer:
369
+ return self._acquire_writer_client()
@@ -0,0 +1,14 @@
1
+ from writer.blocks.base_block import BlueprintBlock
2
+ from writer.ss_types import WriterConfigurationError
3
+
4
+
5
+ class BlueprintTrigger(BlueprintBlock):
6
+ def run(self):
7
+ self.result = self.execution_environment.get("payload")
8
+
9
+ if not self.result:
10
+ try:
11
+ self.result = self._get_field("defaultResult", True, None)
12
+ except WriterConfigurationError:
13
+ self.result = self._get_field("defaultResult", False, None)
14
+
@@ -2,49 +2,52 @@ import inspect
2
2
 
3
3
  import writer.core
4
4
  from writer.abstract import register_abstract_template
5
- from writer.blocks.base_block import WorkflowBlock
5
+ from writer.blocks.base_block import BlueprintBlock
6
6
  from writer.ss_types import AbstractTemplate
7
7
 
8
8
 
9
- class CallEventHandler(WorkflowBlock):
10
-
9
+ class CallEventHandler(BlueprintBlock):
11
10
  @classmethod
12
11
  def register(cls, type: str):
13
12
  super(CallEventHandler, cls).register(type)
14
- register_abstract_template(type, AbstractTemplate(
15
- baseType="workflows_node",
16
- writer={
17
- "name": "Call event handler",
18
- "description": "Executes an event handler.",
19
- "category": "Logic",
20
- "fields": {
21
- "name": {
22
- "name": "Name",
23
- "type": "Text",
24
- "desc": "The name of the event handling function."
25
- },
26
- "additionalArgs": {
27
- "name": "Additional arguments",
28
- "init": '{ "my_arg": 2 }',
29
- "type": "Object",
30
- "control": "Textarea",
31
- "default": "{}"
32
- },
33
- },
34
- "outs": {
35
- "success": {
36
- "name": "Success",
37
- "description": "The event handler execution was successful.",
38
- "style": "success",
13
+ register_abstract_template(
14
+ type,
15
+ AbstractTemplate(
16
+ baseType="blueprints_node",
17
+ writer={
18
+ "name": "Call event handler",
19
+ "description": "Executes an event handler.",
20
+ "category": "Logic",
21
+ "deprecated": True,
22
+ "fields": {
23
+ "name": {
24
+ "name": "Name",
25
+ "type": "Handler",
26
+ "desc": "The name of the event handling function.",
27
+ },
28
+ "additionalArgs": {
29
+ "name": "Additional arguments",
30
+ "init": '{ "my_arg": 2 }',
31
+ "type": "Object",
32
+ "control": "Textarea",
33
+ "default": "{}",
34
+ },
39
35
  },
40
- "error": {
41
- "name": "Error",
42
- "description": "The event handler execution wasn't successful.",
43
- "style": "error",
36
+ "outs": {
37
+ "success": {
38
+ "name": "Success",
39
+ "description": "The event handler execution was successful.",
40
+ "style": "success",
41
+ },
42
+ "error": {
43
+ "name": "Error",
44
+ "description": "The event handler execution wasn't successful.",
45
+ "style": "error",
46
+ },
44
47
  },
45
48
  },
46
- }
47
- ))
49
+ ),
50
+ )
48
51
 
49
52
  def run(self):
50
53
  try:
@@ -59,6 +62,7 @@ class CallEventHandler(WorkflowBlock):
59
62
  "state": self.runner.session.session_state,
60
63
  "context": self.execution_environment,
61
64
  "session": writer.core._event_handler_session_info(),
65
+ "ui": writer.core._event_handler_ui_manager(),
62
66
  } | additional_args
63
67
 
64
68
  handler_args = inspect.getfullargspec(callable_handler).args
@@ -70,4 +74,4 @@ class CallEventHandler(WorkflowBlock):
70
74
  self.outcome = "success"
71
75
  except BaseException as e:
72
76
  self.outcome = "error"
73
- raise e
77
+ raise e
@@ -0,0 +1,48 @@
1
+ from writer.abstract import register_abstract_template
2
+ from writer.blocks.base_block import BlueprintBlock
3
+ from writer.ss_types import AbstractTemplate
4
+
5
+
6
+ class ChangePage(BlueprintBlock):
7
+ @classmethod
8
+ def register(cls, type: str):
9
+ super(ChangePage, cls).register(type)
10
+ register_abstract_template(
11
+ type,
12
+ AbstractTemplate(
13
+ baseType="blueprints_node",
14
+ writer={
15
+ "name": "Change page",
16
+ "description": "Navigates the user to another page in the app. Requires a valid page key.",
17
+ "category": "Other",
18
+ "fields": {
19
+ "pageKey": {
20
+ "name": "Page key",
21
+ "type": "Text",
22
+ "desc": "The identifying key of the target page.",
23
+ },
24
+ },
25
+ "outs": {
26
+ "success": {
27
+ "name": "Success",
28
+ "description": "The page change was successful.",
29
+ "style": "success",
30
+ },
31
+ "error": {
32
+ "name": "Error",
33
+ "description": "There was an error changing the page.",
34
+ "style": "error",
35
+ },
36
+ },
37
+ },
38
+ ),
39
+ )
40
+
41
+ def run(self):
42
+ try:
43
+ page_key = self._get_field("pageKey", required=True)
44
+ self.runner.session.session_state.set_page(page_key)
45
+ self.outcome = "success"
46
+ except BaseException as e:
47
+ self.outcome = "error"
48
+ raise e
writer/blocks/code.py ADDED
@@ -0,0 +1,102 @@
1
+ import logging
2
+ import sys
3
+ import traceback
4
+ from typing import Any
5
+
6
+ from writer.abstract import register_abstract_template
7
+ from writer.blocks.base_block import BlueprintBlock
8
+ from writer.logs import use_logging_redirect, use_stdout_redirect
9
+ from writer.ss_types import AbstractTemplate
10
+
11
+ exec_logger = logging.getLogger("exec_logger")
12
+
13
+ INIT_CODE = """
14
+ # State is accessible as a global variable. For example:
15
+ state["counter"] = 10
16
+
17
+ # Other variables from the execution environment are also available. For example:
18
+ result # Result from the execution of the last block
19
+ results # Dictionary with the execution results of each block, with the block id as key
20
+ payload # When executing via API or via an UI event with a payload
21
+ logger # logging.Logger object for capturing logs
22
+
23
+ # To set the output of this block, which will be available via result to the next block:
24
+ set_output("a sample result")
25
+
26
+ """
27
+
28
+
29
+ class CodeBlock(BlueprintBlock):
30
+ @classmethod
31
+ def register(cls, type: str):
32
+ super(CodeBlock, cls).register(type)
33
+ register_abstract_template(
34
+ type,
35
+ AbstractTemplate(
36
+ baseType="blueprints_node",
37
+ writer={
38
+ "name": "Python code",
39
+ "description": "Runs custom Python code. Useful for logic not covered by existing blocks.",
40
+ "category": "Logic",
41
+ "fields": {
42
+ "code": {
43
+ "name": "Code",
44
+ "type": "Code",
45
+ "control": "Textarea",
46
+ "desc": "The code to be executed.",
47
+ "init": INIT_CODE,
48
+ },
49
+ },
50
+ "outs": {
51
+ "success": {
52
+ "name": "Success",
53
+ "description": "The code executed successfully.",
54
+ "style": "success",
55
+ },
56
+ "error": {
57
+ "name": "Error",
58
+ "description": "There was an error executing the code.",
59
+ "style": "error",
60
+ },
61
+ },
62
+ },
63
+ ),
64
+ )
65
+
66
+ def set_output(self, output: Any):
67
+ self.result = output
68
+
69
+ def run(self):
70
+ try:
71
+ code = self._get_field("code")
72
+ self.result = None
73
+
74
+ writeruserapp = sys.modules.get("writeruserapp")
75
+ block_globals = (
76
+ self.execution_environment
77
+ | writeruserapp.__dict__
78
+ | {
79
+ "state": self.runner.session.session_state,
80
+ "set_output": self.set_output,
81
+ "logger": exec_logger,
82
+ }
83
+ )
84
+
85
+ with (
86
+ use_stdout_redirect([
87
+ lambda entry: self.runner.session.session_state.add_log_entry("info", "Captured stdout", entry),
88
+ lambda entry: setattr(self, 'captured_stdout', entry)
89
+ ]),
90
+ use_logging_redirect([
91
+ lambda entry: self.runner.session.session_state.add_log_entry("info", "Captured logs", entry),
92
+ lambda entry: setattr(self, 'captured_logs', entry)
93
+ ]),
94
+ ):
95
+ exec(code, block_globals)
96
+
97
+ self.outcome = "success"
98
+ except BaseException as e:
99
+ self.outcome = "error"
100
+ # Wrap the message as a preformatted block to display as "raw" text in Markdown
101
+ self.message = f"<pre>{traceback.format_exc()}</pre>"
102
+ raise e