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.
- writer/__init__.py +1 -1
- writer/abstract.py +1 -1
- writer/{ai.py → ai/__init__.py} +867 -163
- writer/app_runner.py +596 -241
- writer/app_templates/default/.wf/components-blueprints_blueprint-0-0decp3w5erhvl0nw.jsonl +11 -0
- writer/app_templates/default/.wf/components-blueprints_root.jsonl +1 -0
- writer/app_templates/default/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl +27 -0
- writer/app_templates/default/.wf/components-root.jsonl +1 -0
- writer/app_templates/default/.wf/components-workflows_root.jsonl +1 -0
- writer/app_templates/default/.wf/components-workflows_workflow-0-lfltcky7l1fsm6j2.jsonl +1 -0
- writer/app_templates/default/.wf/metadata.json +3 -0
- writer/app_templates/default/README.md +3 -0
- writer/app_templates/default/main.py +16 -0
- writer/app_templates/default/requirements.txt +1 -0
- writer/app_templates/default/static/README.md +8 -0
- writer/app_templates/default/static/agent_builder_demo.png +0 -0
- writer/app_templates/default/static/favicon.png +0 -0
- writer/app_templates/hello/.wf/components-blueprints_blueprint-0-t84xyhxau9ej3823.jsonl +18 -0
- writer/app_templates/hello/.wf/components-blueprints_root.jsonl +1 -0
- writer/app_templates/hello/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl +15 -0
- writer/app_templates/hello/.wf/components-root.jsonl +1 -0
- writer/app_templates/hello/.wf/metadata.json +3 -0
- writer/app_templates/hello/main.py +16 -0
- writer/app_templates/hello/static/README.md +8 -0
- writer/app_templates/hello/static/favicon.png +0 -0
- writer/app_templates/hello/static/welcome.svg +40 -0
- writer/auth.py +7 -2
- writer/autogen.py +352 -0
- writer/blocks/__init__.py +51 -17
- writer/blocks/addtostatelist.py +10 -9
- writer/blocks/apitrigger.py +45 -0
- writer/blocks/base_block.py +332 -21
- writer/blocks/base_trigger.py +14 -0
- writer/blocks/calleventhandler.py +39 -35
- writer/blocks/changepage.py +48 -0
- writer/blocks/code.py +102 -0
- writer/blocks/crontrigger.py +49 -0
- writer/blocks/foreach.py +70 -53
- writer/blocks/httprequest.py +112 -99
- writer/blocks/ifelse.py +71 -0
- writer/blocks/logmessage.py +34 -39
- writer/blocks/parsejson.py +30 -29
- writer/blocks/returnvalue.py +7 -7
- writer/blocks/runblueprint.py +63 -0
- writer/blocks/setstate.py +43 -33
- writer/blocks/sharedblueprint.py +86 -0
- writer/blocks/uieventtrigger.py +49 -0
- writer/blocks/writeraddchatmessage.py +50 -12
- writer/blocks/writeraddtokg.py +38 -11
- writer/blocks/writeraskkg.py +123 -0
- writer/blocks/writerchat.py +80 -61
- writer/blocks/writerchatreply.py +279 -0
- writer/blocks/writerchatreplywithtoolconfig.py +393 -0
- writer/blocks/writerclassification.py +78 -39
- writer/blocks/writercompletion.py +49 -44
- writer/blocks/writerfileapi.py +85 -0
- writer/blocks/writerinitchat.py +24 -12
- writer/blocks/writerkeyvaluestorage.py +106 -0
- writer/blocks/writernocodeapp.py +35 -37
- writer/blocks/writerparsepdf.py +73 -0
- writer/blocks/writerstructuredoutput.py +105 -0
- writer/blocks/writertoolcalling.py +251 -0
- writer/blocks/writervision.py +141 -0
- writer/blocks/writerwebsearch.py +175 -0
- writer/blueprints.py +839 -0
- writer/command_line.py +52 -16
- writer/core.py +562 -290
- writer/core_ui.py +6 -2
- writer/evaluator.py +98 -46
- writer/journal.py +227 -0
- writer/keyvalue_storage.py +93 -0
- writer/logs.py +277 -0
- writer/serve.py +625 -327
- writer/ss_types.py +101 -12
- writer/static/assets/Arrow.dom-GBJpMYQS.js +1 -0
- writer/static/assets/BaseMarkdown-Wrvby5J8.js +1 -0
- writer/static/assets/BlueprintToolbar-BuXNRxWT.js +1 -0
- writer/static/assets/BlueprintToolbar-wpfX0jo_.css +1 -0
- writer/static/assets/BuilderApp-PTOI76jZ.js +8 -0
- writer/static/assets/BuilderApp-WimUfNZr.css +1 -0
- writer/static/assets/BuilderApplicationSelect-DXzy4e_h.js +7 -0
- writer/static/assets/BuilderApplicationSelect-XaM1D5fv.css +1 -0
- writer/static/assets/BuilderBlueprintLibraryPanel-Ckrhknlh.css +1 -0
- writer/static/assets/BuilderBlueprintLibraryPanel-DBDzhTlc.js +1 -0
- writer/static/assets/BuilderEmbeddedCodeEditor-B0bcjlhk.css +1 -0
- writer/static/assets/BuilderEmbeddedCodeEditor-Dn7eDICN.js +726 -0
- writer/static/assets/BuilderGraphSelect-C-LRsO8W.js +7 -0
- writer/static/assets/BuilderGraphSelect-D7B61d5s.css +1 -0
- writer/static/assets/BuilderInsertionLabel-BhyL9wgn.js +1 -0
- writer/static/assets/BuilderInsertionLabel-_YS5WPfq.css +1 -0
- writer/static/assets/BuilderInsertionOverlay-D2XS0ij9.css +1 -0
- writer/static/assets/BuilderInsertionOverlay-MkAIVruY.js +1 -0
- writer/static/assets/BuilderJournal-A0LcEwGI.js +7 -0
- writer/static/assets/BuilderJournal-DHv3Pvvm.css +1 -0
- writer/static/assets/BuilderModelSelect-CdSo_sih.js +7 -0
- writer/static/assets/BuilderModelSelect-Dc4IPLp2.css +1 -0
- writer/static/assets/BuilderSettings-BDwZBveu.js +16 -0
- writer/static/assets/BuilderSettings-lZkOXEYw.css +1 -0
- writer/static/assets/BuilderSettingsArtifactAPITriggerDetails-3O6jKBXD.js +4 -0
- writer/static/assets/BuilderSettingsArtifactAPITriggerDetails-DnX66iRg.css +1 -0
- writer/static/assets/BuilderSettingsDeploySharedBlueprint-BR_3ptsd.js +1 -0
- writer/static/assets/BuilderSettingsDeploySharedBlueprint-KJTl8gxP.css +1 -0
- writer/static/assets/BuilderSettingsHandlers-CBtEQFSo.js +1 -0
- writer/static/assets/BuilderSettingsHandlers-DJPeASfz.css +1 -0
- writer/static/assets/BuilderSidebarComponentTree-DLltgas5.js +1 -0
- writer/static/assets/BuilderSidebarComponentTree-DYu1F793.css +1 -0
- writer/static/assets/BuilderSidebarToolkit-CApZNTAq.js +7 -0
- writer/static/assets/BuilderSidebarToolkit-CwqbjRv8.css +1 -0
- writer/static/assets/BuilderTemplateEditor-CYSDeWgV.css +1 -0
- writer/static/assets/BuilderTemplateEditor-DnRDRcA0.js +87 -0
- writer/static/assets/BuilderVault-2vGoV0sx.js +1 -0
- writer/static/assets/BuilderVault-Cx6oQSES.css +1 -0
- writer/static/assets/ComponentRenderer-72hqvEvI.css +1 -0
- writer/static/assets/ComponentRenderer-D4Pj1i3s.js +1 -0
- writer/static/assets/SharedCopyClipboardButton-BipJKGtz.css +1 -0
- writer/static/assets/SharedCopyClipboardButton-DNI9kLe6.js +1 -0
- writer/static/assets/WdsCheckbox-DKvpPA4D.css +1 -0
- writer/static/assets/WdsCheckbox-edQcn1cf.js +1 -0
- writer/static/assets/WdsDropdownMenu-CzzPN9Wg.css +1 -0
- writer/static/assets/WdsDropdownMenu-DQnrRBNV.js +1 -0
- writer/static/assets/WdsFieldWrapper-Cmufx5Nj.js +1 -0
- writer/static/assets/WdsFieldWrapper-CsemOh8D.css +1 -0
- writer/static/assets/WdsTabs-DKj7BqI0.css +1 -0
- writer/static/assets/WdsTabs-DcfY_zn5.js +1 -0
- writer/static/assets/abap-D8nrxEjS.js +6 -0
- writer/static/assets/apex-BrXDlLUW.js +6 -0
- writer/static/assets/art-paper-D70v1WMA.svg +180 -0
- writer/static/assets/azcli-CElzELwZ.js +6 -0
- writer/static/assets/bat-CUsyEhik.js +6 -0
- writer/static/assets/bicep-BtxyJn6H.js +7 -0
- writer/static/assets/cameligo-ClBCoF8h.js +6 -0
- writer/static/assets/clojure-B9TqLHAk.js +6 -0
- writer/static/assets/codicon-BA2IlpFX.ttf +0 -0
- writer/static/assets/coffee-DYsfeylR.js +6 -0
- writer/static/assets/cpp-VVGvvgir.js +6 -0
- writer/static/assets/csharp-Z6z2stHy.js +6 -0
- writer/static/assets/csp-DgZoLDI1.js +6 -0
- writer/static/assets/css-KqQ96-gC.js +8 -0
- writer/static/assets/css.worker-DvNUQFd1.js +84 -0
- writer/static/assets/cssMode-BYq4oZGq.js +9 -0
- writer/static/assets/cypher-CYoSlgTu.js +6 -0
- writer/static/assets/dart-BGDl7St1.js +6 -0
- writer/static/assets/dockerfile-CuCtxA7T.js +6 -0
- writer/static/assets/ecl-BCTFAUpS.js +6 -0
- writer/static/assets/editor.worker-BVwmgLrR.js +11 -0
- writer/static/assets/elixir-C7hRTYZ9.js +6 -0
- writer/static/assets/flow9-Bi_qi707.js +6 -0
- writer/static/assets/freemarker2-CnNourkO.js +8 -0
- writer/static/assets/fsharp-CxaaEKKi.js +6 -0
- writer/static/assets/go-DUImKuGY.js +6 -0
- writer/static/assets/graphql-D5sGVkLV.js +6 -0
- writer/static/assets/handlebars-Bm22yapJ.js +6 -0
- writer/static/assets/hcl-zD_CCkZ1.js +6 -0
- writer/static/assets/html-CAKAfoZF.js +6 -0
- writer/static/assets/html.worker-BJMlcbMU.js +458 -0
- writer/static/assets/htmlMode-BGZ97n-V.js +9 -0
- writer/static/assets/index-5u5REPT4.js +16 -0
- writer/static/assets/index-BKNuk68o.css +1 -0
- writer/static/assets/index-BQNXU3IR.js +17 -0
- writer/static/assets/index-BQr1pfrb.js +1 -0
- writer/static/assets/index-DHXAd5Yn.js +4 -0
- writer/static/assets/index-Zki-pfO-.js +8525 -0
- writer/static/assets/index.esm-B1ZQtduY.js +17 -0
- writer/static/assets/ini-8kKHd4ZL.js +6 -0
- writer/static/assets/java-De1axCfe.js +6 -0
- writer/static/assets/javascript-X1f02eyK.js +6 -0
- writer/static/assets/json.worker-BwvX8PuZ.js +42 -0
- writer/static/assets/jsonMode-hT0bNgT8.js +11 -0
- writer/static/assets/julia-D3ApGBxz.js +6 -0
- writer/static/assets/kotlin-GbSrCElU.js +6 -0
- writer/static/assets/less-DNUaDNdz.js +7 -0
- writer/static/assets/lexon-Bg9QKxBu.js +6 -0
- writer/static/assets/liquid-KmCCiJw2.js +6 -0
- writer/static/assets/lua-Crkvc3mc.js +6 -0
- writer/static/assets/m3-DsrzVyM1.js +6 -0
- writer/static/assets/mapbox-gl-C0cyFYYW.js +2329 -0
- writer/static/assets/markdown-CY5IOZuu.js +6 -0
- writer/static/assets/marked.esm-273vDTCT.js +45 -0
- writer/static/assets/mdx-DtRFauUw.js +6 -0
- writer/static/assets/mips-BE8RsGBA.js +6 -0
- writer/static/assets/msdax-N5ajIiFQ.js +6 -0
- writer/static/assets/mysql-DRxbB97D.js +6 -0
- writer/static/assets/objective-c-BHUZy23s.js +6 -0
- writer/static/assets/pascal-BemVzBTY.js +6 -0
- writer/static/assets/pascaligo-BACCcnx_.js +6 -0
- writer/static/assets/pdf-B6-yWJ-Y.js +12 -0
- writer/static/assets/pdf.worker.min-CyUfim15.mjs +21 -0
- writer/static/assets/perl-CuU66Ptk.js +6 -0
- writer/static/assets/pgsql-CQ6TMH2r.js +6 -0
- writer/static/assets/php-BvyzZa65.js +6 -0
- writer/static/assets/pla-DrIuu9u1.js +6 -0
- writer/static/assets/plotly.min-DutuuatZ.js +4030 -0
- writer/static/assets/poppins-latin-300-italic-4WBEAciR.woff +0 -0
- writer/static/assets/poppins-latin-300-italic-EWCPeN2Y.woff2 +0 -0
- writer/static/assets/poppins-latin-300-normal-DCNuMXUj.woff +0 -0
- writer/static/assets/poppins-latin-300-normal-Dku2WoCh.woff2 +0 -0
- writer/static/assets/poppins-latin-400-italic-B4GYq972.woff2 +0 -0
- writer/static/assets/poppins-latin-400-italic-BPejoDS-.woff +0 -0
- writer/static/assets/poppins-latin-400-normal-BOb3E3N0.woff +0 -0
- writer/static/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
- writer/static/assets/poppins-latin-500-italic-Ce_qjtl5.woff +0 -0
- writer/static/assets/poppins-latin-500-italic-o28Otv0U.woff2 +0 -0
- writer/static/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
- writer/static/assets/poppins-latin-500-normal-DGXqpDMm.woff +0 -0
- writer/static/assets/poppins-latin-600-italic-BhOZippK.woff +0 -0
- writer/static/assets/poppins-latin-600-italic-CZ4wqKBi.woff2 +0 -0
- writer/static/assets/poppins-latin-600-normal-BJdTmd5m.woff +0 -0
- writer/static/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
- writer/static/assets/poppins-latin-700-italic-CW91C-LJ.woff +0 -0
- writer/static/assets/poppins-latin-700-italic-RKf6esGj.woff2 +0 -0
- writer/static/assets/poppins-latin-700-normal-BVuQR_eA.woff +0 -0
- writer/static/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-300-italic-CBzyU4Pf.woff +0 -0
- writer/static/assets/poppins-latin-ext-300-italic-DdDvTq5-.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-300-normal-7Zg2msWE.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-300-normal-C9p7gvmA.woff +0 -0
- writer/static/assets/poppins-latin-ext-400-italic-BiCGV3eO.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-400-italic-gsPYOGqV.woff +0 -0
- writer/static/assets/poppins-latin-ext-400-normal-CIpeJEZw.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-400-normal-Ce_uWq1Z.woff +0 -0
- writer/static/assets/poppins-latin-ext-500-italic-CwrTHwbn.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-500-italic-jdc8Bv4M.woff +0 -0
- writer/static/assets/poppins-latin-ext-500-normal-Bl1-S02S.woff +0 -0
- writer/static/assets/poppins-latin-ext-500-normal-H4Q0z8D2.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-600-italic-BqeDa496.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-600-italic-C7MQPb_A.woff +0 -0
- writer/static/assets/poppins-latin-ext-600-normal-Cn4C8475.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-600-normal-DB6FJURc.woff +0 -0
- writer/static/assets/poppins-latin-ext-700-italic-BAdhB_WS.woff2 +0 -0
- writer/static/assets/poppins-latin-ext-700-italic-WKTwQMp8.woff +0 -0
- writer/static/assets/poppins-latin-ext-700-normal-CE2WFKmF.woff +0 -0
- writer/static/assets/poppins-latin-ext-700-normal-DDaViAzG.woff2 +0 -0
- writer/static/assets/postiats-BR_hrfni.js +6 -0
- writer/static/assets/powerquery-CKDUeRmd.js +6 -0
- writer/static/assets/powershell-Dsa4rhA_.js +6 -0
- writer/static/assets/protobuf-CGsvhooB.js +7 -0
- writer/static/assets/pug-D2p3uOX2.js +6 -0
- writer/static/assets/python-DVhxg746.js +6 -0
- writer/static/assets/qsharp-B7F3HtPF.js +6 -0
- writer/static/assets/r-3aLoi2fs.js +6 -0
- writer/static/assets/razor-DR5Ns_BC.js +6 -0
- writer/static/assets/redis-jqFeRM5s.js +6 -0
- writer/static/assets/redshift-BriwQgXR.js +6 -0
- writer/static/assets/restructuredtext-hbBFZ0w9.js +6 -0
- writer/static/assets/ruby-ByThyB2Q.js +6 -0
- writer/static/assets/rust-DIEZMp5R.js +6 -0
- writer/static/assets/sb-C6Gjjw_x.js +6 -0
- writer/static/assets/scala-DZNw3jJB.js +6 -0
- writer/static/assets/scheme-55eqh71t.js +6 -0
- writer/static/assets/scss-D-OVkc4F.js +8 -0
- writer/static/assets/serialization-DJC7NP0N.js +20 -0
- writer/static/assets/shell-DSpi8_qN.js +6 -0
- writer/static/assets/solidity-BHddiNFS.js +6 -0
- writer/static/assets/sophia-D6taVZFb.js +6 -0
- writer/static/assets/sparql-LA0C7mUc.js +6 -0
- writer/static/assets/sql-C3-3IcFM.js +6 -0
- writer/static/assets/st-C4g7059C.js +6 -0
- writer/static/assets/swift-DNI1vH3h.js +8 -0
- writer/static/assets/systemverilog-DL_FVbcQ.js +6 -0
- writer/static/assets/tcl-DVJXmIwd.js +6 -0
- writer/static/assets/ts.worker-CwG1rUES.js +37021 -0
- writer/static/assets/tsMode-BNUEZzir.js +16 -0
- writer/static/assets/twig-BVWDLtw5.js +6 -0
- writer/static/assets/typescript-CRVt7Hx0.js +6 -0
- writer/static/assets/useBlueprintRun-C00bCxh-.js +1 -0
- writer/static/assets/useKeyValueEditor-nDmI7cTJ.js +1 -0
- writer/static/assets/useListResources-DLkZhRSJ.js +1 -0
- writer/static/assets/vb-Btz91-7U.js +6 -0
- writer/static/assets/vega-embed.module-SNP5iNdJ.js +201 -0
- writer/static/assets/wgsl-D8V_buCG.js +303 -0
- writer/static/assets/xml-C_6-t1tb.js +6 -0
- writer/static/assets/yaml-DIw8G7jk.js +6 -0
- writer/static/components/annotatedtext.svg +4 -0
- writer/static/components/avatar.svg +4 -0
- writer/static/components/blueprints_addtostatelist.svg +4 -0
- writer/static/components/blueprints_apitrigger.svg +4 -0
- writer/static/components/blueprints_calleventhandler.svg +9 -0
- writer/static/components/blueprints_category_Logic.svg +4 -0
- writer/static/components/blueprints_category_Other.svg +4 -0
- writer/static/components/blueprints_category_Triggers.svg +4 -0
- writer/static/components/blueprints_category_Writer.svg +25 -0
- writer/static/components/blueprints_code.svg +9 -0
- writer/static/components/blueprints_crontrigger.svg +6 -0
- writer/static/components/blueprints_foreach.svg +4 -0
- writer/static/components/blueprints_httprequest.svg +11 -0
- writer/static/components/blueprints_logmessage.svg +11 -0
- writer/static/components/blueprints_parsejson.svg +4 -0
- writer/static/components/blueprints_returnvalue.svg +4 -0
- writer/static/components/blueprints_runblueprint.svg +4 -0
- writer/static/components/blueprints_setstate.svg +4 -0
- writer/static/components/blueprints_uieventtrigger.svg +4 -0
- writer/static/components/blueprints_writeraddchatmessage.svg +19 -0
- writer/static/components/blueprints_writeraddtokg.svg +19 -0
- writer/static/components/blueprints_writerchat.svg +11 -0
- writer/static/components/blueprints_writerchatreply.svg +19 -0
- writer/static/components/blueprints_writerclassification.svg +24 -0
- writer/static/components/blueprints_writercompletion.svg +14 -0
- writer/static/components/blueprints_writerinitchat.svg +11 -0
- writer/static/components/blueprints_writernocodeapp.svg +14 -0
- writer/static/components/button.svg +4 -0
- writer/static/components/category_Content.svg +4 -0
- writer/static/components/category_Embed.svg +4 -0
- writer/static/components/category_Input.svg +5 -0
- writer/static/components/category_Layout.svg +9 -0
- writer/static/components/category_Other.svg +4 -0
- writer/static/components/chatbot.svg +4 -0
- writer/static/components/checkboxinput.svg +4 -0
- writer/static/components/colorinput.svg +11 -0
- writer/static/components/column.svg +4 -0
- writer/static/components/columns.svg +4 -0
- writer/static/components/dataframe.svg +4 -0
- writer/static/components/dateinput.svg +4 -0
- writer/static/components/dropdowninput.svg +5 -0
- writer/static/components/fileinput.svg +4 -0
- writer/static/components/googlemaps.svg +4 -0
- writer/static/components/header.svg +4 -0
- writer/static/components/heading.svg +9 -0
- writer/static/components/horizontalstack.svg +4 -0
- writer/static/components/html.svg +9 -0
- writer/static/components/icon.svg +4 -0
- writer/static/components/iframe.svg +4 -0
- writer/static/components/image.svg +11 -0
- writer/static/components/jsonviewer.svg +4 -0
- writer/static/components/link.svg +12 -0
- writer/static/components/mapbox.svg +4 -0
- writer/static/components/message.svg +4 -0
- writer/static/components/metric.svg +4 -0
- writer/static/components/multiselectinput.svg +4 -0
- writer/static/components/numberinput.svg +4 -0
- writer/static/components/page.svg +50 -0
- writer/static/components/pagination.svg +4 -0
- writer/static/components/pdf.svg +4 -0
- writer/static/components/plotlygraph.svg +7 -0
- writer/static/components/progressbar.svg +5 -0
- writer/static/components/radioinput.svg +4 -0
- writer/static/components/rangeinput.svg +4 -0
- writer/static/components/ratinginput.svg +4 -0
- writer/static/components/repeater.svg +4 -0
- writer/static/components/reuse.svg +4 -0
- writer/static/components/section.svg +4 -0
- writer/static/components/selectinput.svg +5 -0
- writer/static/components/separator.svg +4 -0
- writer/static/components/sidebar.svg +4 -0
- writer/static/components/sliderinput.svg +4 -0
- writer/static/components/step.svg +4 -0
- writer/static/components/steps.svg +4 -0
- writer/static/components/switchinput.svg +4 -0
- writer/static/components/tab.svg +4 -0
- writer/static/components/tabs.svg +4 -0
- writer/static/components/tags.svg +11 -0
- writer/static/components/text.svg +4 -0
- writer/static/components/textareainput.svg +11 -0
- writer/static/components/textinput.svg +4 -0
- writer/static/components/timeinput.svg +4 -0
- writer/static/components/timer.svg +4 -0
- writer/static/components/vegalitechart.svg +7 -0
- writer/static/components/videoplayer.svg +11 -0
- writer/static/components/webcamcapture.svg +4 -0
- writer/static/favicon.png +0 -0
- writer/static/index.html +84 -0
- writer/static/status/cancelled.svg +5 -0
- writer/static/status/error.svg +5 -0
- writer/static/status/skipped.svg +4 -0
- writer/static/status/stopped.svg +4 -0
- writer/static/status/success.svg +4 -0
- writer/sync.py +431 -0
- writer/ui.py +2268 -0
- writer/vault.py +48 -0
- writer/wf_project.py +90 -66
- writer-1.25.1rc1.dist-info/METADATA +92 -0
- writer-1.25.1rc1.dist-info/RECORD +382 -0
- {writer-0.8.3rc4.dist-info → writer-1.25.1rc1.dist-info}/WHEEL +1 -1
- writer/blocks/runworkflow.py +0 -59
- writer/workflows.py +0 -183
- writer-0.8.3rc4.dist-info/METADATA +0 -117
- writer-0.8.3rc4.dist-info/RECORD +0 -44
- {writer-0.8.3rc4.dist-info → writer-1.25.1rc1.dist-info}/entry_points.txt +0 -0
- {writer-0.8.3rc4.dist-info → writer-1.25.1rc1.dist-info/licenses}/LICENSE.txt +0 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import textwrap
|
|
2
|
+
from datetime import date
|
|
3
|
+
|
|
4
|
+
from writer.abstract import register_abstract_template
|
|
5
|
+
from writer.blocks.base_block import WriterBlock
|
|
6
|
+
from writer.ss_types import AbstractTemplate
|
|
7
|
+
|
|
8
|
+
DEFAULT_MODEL = "palmyra-x5"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WriterToolCalling(WriterBlock):
|
|
12
|
+
@classmethod
|
|
13
|
+
def register(cls, type: str):
|
|
14
|
+
super(WriterToolCalling, cls).register(type)
|
|
15
|
+
register_abstract_template(
|
|
16
|
+
type,
|
|
17
|
+
AbstractTemplate(
|
|
18
|
+
baseType="blueprints_node",
|
|
19
|
+
writer={
|
|
20
|
+
"name": "Tool calling",
|
|
21
|
+
"description": "Connects the Agent to external tools to complete tasks it cannot handle directly.",
|
|
22
|
+
"category": "Writer",
|
|
23
|
+
"fields": {
|
|
24
|
+
"prompt": {
|
|
25
|
+
"name": "Prompt",
|
|
26
|
+
"type": "Text",
|
|
27
|
+
"control": "Textarea",
|
|
28
|
+
"desc": "The task that needs to be carried out.",
|
|
29
|
+
},
|
|
30
|
+
"modelId": {"name": "Model", "type": "Model Id", "default": DEFAULT_MODEL},
|
|
31
|
+
"maxIterations": {
|
|
32
|
+
"name": "Max iterations",
|
|
33
|
+
"type": "Number",
|
|
34
|
+
"default": 10,
|
|
35
|
+
},
|
|
36
|
+
"tools": {
|
|
37
|
+
"name": "Tools",
|
|
38
|
+
"type": "Tools",
|
|
39
|
+
"default": "{}",
|
|
40
|
+
"init": "",
|
|
41
|
+
"category": "Tools",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
"outs": {
|
|
45
|
+
"tools": {
|
|
46
|
+
"name": "Tools",
|
|
47
|
+
"field": "tools",
|
|
48
|
+
"description": "Run associated tools.",
|
|
49
|
+
"style": "dynamic",
|
|
50
|
+
},
|
|
51
|
+
"success": {
|
|
52
|
+
"name": "Success",
|
|
53
|
+
"description": "The task was completed successfully.",
|
|
54
|
+
"style": "success",
|
|
55
|
+
},
|
|
56
|
+
"error": {
|
|
57
|
+
"name": "Error",
|
|
58
|
+
"description": "There was an error completing the task.",
|
|
59
|
+
"style": "error",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def _make_callable(self, tool_name: str):
|
|
67
|
+
import time
|
|
68
|
+
|
|
69
|
+
def callable(**args):
|
|
70
|
+
expanded_execution_environment = self.execution_environment | args
|
|
71
|
+
raw_return_value = self.runner.run_branch(
|
|
72
|
+
self.component.id,
|
|
73
|
+
f"tools_{tool_name}",
|
|
74
|
+
expanded_execution_environment,
|
|
75
|
+
f"Blueprint branch execution (tool {tool_name})",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if raw_return_value is None:
|
|
79
|
+
self.outcome = "error"
|
|
80
|
+
raise ValueError(
|
|
81
|
+
f'No value has been returned for the outcome branch "{tool_name}". Use the block "Return value" to specify one.'
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
transformed_result = self._project_common_tools_result(raw_return_value)
|
|
85
|
+
if transformed_result is None:
|
|
86
|
+
# Fallback avoids returning the literal string "None"
|
|
87
|
+
transformed_result = raw_return_value
|
|
88
|
+
return_value = repr(transformed_result)
|
|
89
|
+
|
|
90
|
+
trace = self.execution_environment.get("trace")
|
|
91
|
+
if trace is not None:
|
|
92
|
+
trace.append(
|
|
93
|
+
{
|
|
94
|
+
"type": "functionCall",
|
|
95
|
+
"time": time.time(),
|
|
96
|
+
"name": tool_name,
|
|
97
|
+
"parameters": args,
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
return return_value
|
|
101
|
+
|
|
102
|
+
return callable
|
|
103
|
+
|
|
104
|
+
def _get_tools(self):
|
|
105
|
+
import writer.ai
|
|
106
|
+
|
|
107
|
+
tools_raw = self._get_field("tools", True)
|
|
108
|
+
tools = []
|
|
109
|
+
|
|
110
|
+
for tool_name, tool_raw in tools_raw.items():
|
|
111
|
+
tool_type = tool_raw.get("type")
|
|
112
|
+
tool = None
|
|
113
|
+
if tool_type == "function":
|
|
114
|
+
tool = writer.ai.FunctionTool(
|
|
115
|
+
type="function",
|
|
116
|
+
name=tool_name,
|
|
117
|
+
description=tool_raw.get("description"),
|
|
118
|
+
callable=self._make_callable(tool_name),
|
|
119
|
+
parameters=tool_raw.get("parameters"),
|
|
120
|
+
)
|
|
121
|
+
elif tool_type == "graph":
|
|
122
|
+
tool = writer.ai.GraphTool(
|
|
123
|
+
type="graph",
|
|
124
|
+
graph_ids=tool_raw.get("graph_ids"),
|
|
125
|
+
subqueries=False,
|
|
126
|
+
description=tool_name,
|
|
127
|
+
)
|
|
128
|
+
else:
|
|
129
|
+
continue
|
|
130
|
+
tools.append(tool)
|
|
131
|
+
|
|
132
|
+
def reasoning_callable(**kwargs):
|
|
133
|
+
import time
|
|
134
|
+
|
|
135
|
+
thought = kwargs.get("thought")
|
|
136
|
+
action = kwargs.get("action")
|
|
137
|
+
status = kwargs.get("status")
|
|
138
|
+
|
|
139
|
+
trace = self.execution_environment.get("trace")
|
|
140
|
+
if trace is not None:
|
|
141
|
+
trace.append(
|
|
142
|
+
{"type": "reasoning", "time": time.time(), "thought": thought, "action": action}
|
|
143
|
+
)
|
|
144
|
+
if status == "DONE":
|
|
145
|
+
self.is_complete = True
|
|
146
|
+
|
|
147
|
+
reasoning_tool = {
|
|
148
|
+
"type": "function",
|
|
149
|
+
"name": "disclose_reasoning",
|
|
150
|
+
"description": "Use this only to briefly summarize your reasoning and to signal completion. Call this when you're ready to finalize your answer.",
|
|
151
|
+
"callable": reasoning_callable,
|
|
152
|
+
"parameters": {
|
|
153
|
+
"thought": {
|
|
154
|
+
"type": "string",
|
|
155
|
+
"description": "A brief summary of your reasoning process.",
|
|
156
|
+
},
|
|
157
|
+
"action": {
|
|
158
|
+
"type": "string",
|
|
159
|
+
"description": "When status is DONE, always set this to 'finalize_and_answer'. Otherwise, summarize the actions you took and why.",
|
|
160
|
+
},
|
|
161
|
+
"status": {
|
|
162
|
+
"type": "string",
|
|
163
|
+
"description": "Set to DONE if you consider the task complete and are ready to provide the final answer. Set to INCOMPLETE if you wish to keep iterating.",
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
tools.append(reasoning_tool)
|
|
169
|
+
|
|
170
|
+
return tools
|
|
171
|
+
|
|
172
|
+
def _get_react_prompt(self, base_prompt: str):
|
|
173
|
+
return textwrap.dedent(f"""
|
|
174
|
+
You're a ReAct agent. Your knowledge cut-off date is 2024, but today is {str(date.today())}.
|
|
175
|
+
|
|
176
|
+
Task: {base_prompt.strip()}
|
|
177
|
+
|
|
178
|
+
## Available Tools
|
|
179
|
+
You have access to various tools to help complete the task. Use them as needed to gather information.
|
|
180
|
+
- `disclose_reasoning` - Use this only to briefly summarize your reasoning and to signal completion
|
|
181
|
+
|
|
182
|
+
## Finalization Protocol (CRITICAL)
|
|
183
|
+
When your analysis is complete, follow these steps EXACTLY:
|
|
184
|
+
|
|
185
|
+
1. Make one final function call to `disclose_reasoning` with:
|
|
186
|
+
```json
|
|
187
|
+
{{
|
|
188
|
+
"thought": "<brief reasoning summary>",
|
|
189
|
+
"action": "finalize_and_answer",
|
|
190
|
+
"status": "DONE"
|
|
191
|
+
}}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
2. **IMMEDIATELY AFTER** that tool call, output a normal assistant message (no further tool calls) containing your complete, final answer to the user.
|
|
195
|
+
|
|
196
|
+
3. **DO NOT** end with a null/None action. Always provide the full answer in your final assistant message.
|
|
197
|
+
|
|
198
|
+
If more information is still needed, call `disclose_reasoning` with `"status": "INCOMPLETE"` and continue gathering information.
|
|
199
|
+
|
|
200
|
+
## Important Notes
|
|
201
|
+
- Use tools to gather all necessary information before finalizing
|
|
202
|
+
- The `action` field in `disclose_reasoning` should always be set to "finalize_and_answer" when status is "DONE"
|
|
203
|
+
- Your final assistant message (after the final `disclose_reasoning` call) should contain the complete response to the user
|
|
204
|
+
""").strip()
|
|
205
|
+
|
|
206
|
+
def _project_common_tools_result(self, tool_result):
|
|
207
|
+
# Handle common HTTP-like shapes safely; pass through other types.
|
|
208
|
+
if isinstance(tool_result, dict):
|
|
209
|
+
if tool_result.get("request") and "body" in tool_result:
|
|
210
|
+
return tool_result["body"]
|
|
211
|
+
return tool_result
|
|
212
|
+
|
|
213
|
+
def run(self):
|
|
214
|
+
import writer.ai
|
|
215
|
+
|
|
216
|
+
self.is_complete = False
|
|
217
|
+
self.result = None
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
prompt = self._get_field("prompt")
|
|
221
|
+
model_id = self._get_field("modelId", False, default_field_value=DEFAULT_MODEL)
|
|
222
|
+
max_iterations = max(1, int(self._get_field("maxIterations", False, "10")))
|
|
223
|
+
conversation = writer.ai.Conversation()
|
|
224
|
+
tools = self._get_tools()
|
|
225
|
+
|
|
226
|
+
conversation += {"role": "user", "content": self._get_react_prompt(prompt)}
|
|
227
|
+
|
|
228
|
+
for i in range(max_iterations):
|
|
229
|
+
config = {"model": model_id, "temperature": 0.1}
|
|
230
|
+
msg = conversation.complete(tools=tools, config=config)
|
|
231
|
+
conversation += msg
|
|
232
|
+
if self.is_complete:
|
|
233
|
+
# According to the protocol, after disclose_reasoning with status="DONE",
|
|
234
|
+
# the agent should output a final assistant message with the complete answer.
|
|
235
|
+
# Check if this message has content (the final answer)
|
|
236
|
+
if msg.get("content"):
|
|
237
|
+
self.result = msg.get("content")
|
|
238
|
+
break
|
|
239
|
+
# If no content yet, allow one more iteration to get the final message
|
|
240
|
+
# (the tool call processing might need another round)
|
|
241
|
+
if i < max_iterations - 1:
|
|
242
|
+
continue
|
|
243
|
+
break
|
|
244
|
+
|
|
245
|
+
# If we didn't capture the result yet, try to get it from the last message
|
|
246
|
+
if not self.result:
|
|
247
|
+
self.result = msg.get("content", "")
|
|
248
|
+
self.outcome = "success"
|
|
249
|
+
except BaseException as e:
|
|
250
|
+
self.outcome = "error"
|
|
251
|
+
raise e
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from writer.abstract import register_abstract_template
|
|
4
|
+
from writer.blocks.base_block import WriterBlock
|
|
5
|
+
from writer.ss_types import AbstractTemplate
|
|
6
|
+
|
|
7
|
+
DEFAULT_MODEL = "palmyra-vision"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class WriterVision(WriterBlock):
|
|
11
|
+
@classmethod
|
|
12
|
+
def register(cls, type: str):
|
|
13
|
+
super(WriterVision, cls).register(type)
|
|
14
|
+
register_abstract_template(
|
|
15
|
+
type,
|
|
16
|
+
AbstractTemplate(
|
|
17
|
+
baseType="blueprints_node",
|
|
18
|
+
writer={
|
|
19
|
+
"name": "Analyze images",
|
|
20
|
+
"description": "Submit images and a prompt to the Writer Vision model to analyze the images and generate a response.",
|
|
21
|
+
"category": "Writer",
|
|
22
|
+
"fields": {
|
|
23
|
+
"prompt": {"name": "Prompt", "type": "Text", "control": "Textarea", "desc": "The prompt to use for the image analysis."},
|
|
24
|
+
|
|
25
|
+
# Keep this commented out for now,
|
|
26
|
+
# as `palmyra-vision` is the only model available
|
|
27
|
+
# for image analysis at the moment.
|
|
28
|
+
# Uncomment when more models are available.
|
|
29
|
+
|
|
30
|
+
# "modelId": {
|
|
31
|
+
# "name": "Model",
|
|
32
|
+
# "type": "Model Id",
|
|
33
|
+
# "default": DEFAULT_MODEL,
|
|
34
|
+
# "desc": "The model to use for image analysis."
|
|
35
|
+
# },
|
|
36
|
+
"images": {
|
|
37
|
+
"name": "Images",
|
|
38
|
+
"type": "Object",
|
|
39
|
+
"default": "[]",
|
|
40
|
+
"validator": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"properties": {
|
|
45
|
+
"name": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "The name of the image file.",
|
|
48
|
+
},
|
|
49
|
+
"file_id": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"description": "The ID of the image file in Writer cloud.",
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"outs": {
|
|
59
|
+
"success": {
|
|
60
|
+
"name": "Success",
|
|
61
|
+
"description": "The image was analyzed successfully.",
|
|
62
|
+
"style": "success",
|
|
63
|
+
},
|
|
64
|
+
"error": {
|
|
65
|
+
"name": "Error",
|
|
66
|
+
"description": "There was an error analyzing the image.",
|
|
67
|
+
"style": "error",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
"featureFlags": [
|
|
71
|
+
"vision_block"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def run(self):
|
|
78
|
+
try:
|
|
79
|
+
prompt = self._get_field("prompt")
|
|
80
|
+
if not prompt:
|
|
81
|
+
raise ValueError("Prompt cannot be empty. Please provide a valid prompt for image analysis.")
|
|
82
|
+
if "{{" not in prompt or "}}" not in prompt:
|
|
83
|
+
raise ValueError(
|
|
84
|
+
"Prompt must include image names in the format {{image_name}}. "
|
|
85
|
+
"Please ensure the prompt contains placeholders for the images."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Currently, only 'palmyra-vision' is supported.
|
|
89
|
+
model_id = DEFAULT_MODEL
|
|
90
|
+
# model_id = self._get_field("modelId", False, default_field_value=DEFAULT_MODEL)
|
|
91
|
+
|
|
92
|
+
images = self._get_field("images", as_json=True, required=True)
|
|
93
|
+
|
|
94
|
+
# Validate images input
|
|
95
|
+
if not isinstance(images, list):
|
|
96
|
+
raise ValueError(
|
|
97
|
+
f"Images must be a list: received {type(images)}."
|
|
98
|
+
)
|
|
99
|
+
if not images:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
"Images list cannot be empty. Please provide "
|
|
102
|
+
"at least one image."
|
|
103
|
+
)
|
|
104
|
+
placeholders = set(re.findall(r"\{\{(\w+)\}\}", prompt))
|
|
105
|
+
for image in images:
|
|
106
|
+
if not isinstance(image, dict):
|
|
107
|
+
raise ValueError(
|
|
108
|
+
"Image definitions must be dictionaries and contain "
|
|
109
|
+
f"`name` and `file_id` attributes: received {type(image)}."
|
|
110
|
+
)
|
|
111
|
+
if "name" not in image or "file_id" not in image:
|
|
112
|
+
raise ValueError(
|
|
113
|
+
f"Invalid image definition: {image}. "
|
|
114
|
+
"An image specified as a dictionary must contain "
|
|
115
|
+
"`name` and `file_id` attributes."
|
|
116
|
+
)
|
|
117
|
+
if image["name"] not in placeholders:
|
|
118
|
+
raise ValueError(
|
|
119
|
+
f"Image name '{image['name']}' not found in the prompt. "
|
|
120
|
+
"Please ensure the prompt includes the image name in the format {{image_name}}."
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
client = self.writer_sdk_client
|
|
124
|
+
response = client.vision.analyze(
|
|
125
|
+
prompt=prompt,
|
|
126
|
+
model=model_id,
|
|
127
|
+
variables=images
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if not response:
|
|
131
|
+
self.outcome = "error"
|
|
132
|
+
raise RuntimeError(
|
|
133
|
+
"No response returned from the model. "
|
|
134
|
+
"Please validate the prompt and model configuration."
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
self.result = response.data
|
|
138
|
+
self.outcome = "success"
|
|
139
|
+
except BaseException as e:
|
|
140
|
+
self.outcome = "error"
|
|
141
|
+
raise e
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from urllib.parse import urlparse
|
|
2
|
+
|
|
3
|
+
from writer.abstract import register_abstract_template
|
|
4
|
+
from writer.blocks.base_block import WriterBlock
|
|
5
|
+
from writer.ss_types import AbstractTemplate
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class WriterWebSearch(WriterBlock):
|
|
9
|
+
@classmethod
|
|
10
|
+
def register(cls, type: str):
|
|
11
|
+
super(WriterWebSearch, cls).register(type)
|
|
12
|
+
register_abstract_template(
|
|
13
|
+
type,
|
|
14
|
+
AbstractTemplate(
|
|
15
|
+
baseType="blueprints_node",
|
|
16
|
+
writer={
|
|
17
|
+
"name": "Web search",
|
|
18
|
+
"description": "Search the web for information and return relevant results with source URLs.",
|
|
19
|
+
"category": "Writer",
|
|
20
|
+
"featureFlags": ["web_search_block"],
|
|
21
|
+
"fields": {
|
|
22
|
+
"query": {
|
|
23
|
+
"name": "Query",
|
|
24
|
+
"type": "Text",
|
|
25
|
+
"control": "Textarea",
|
|
26
|
+
"desc": "The search query to find information on the web.",
|
|
27
|
+
"validator": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"minLength": 1,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
"includeDomains": {
|
|
33
|
+
"name": "Include domains",
|
|
34
|
+
"type": "Object",
|
|
35
|
+
"default": "[]",
|
|
36
|
+
"desc": "List of domains to specifically search within (e.g., ['wikipedia.org', 'docs.python.org']).",
|
|
37
|
+
"validator": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"items": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
"excludeDomains": {
|
|
45
|
+
"name": "Exclude domains",
|
|
46
|
+
"type": "Object",
|
|
47
|
+
"default": "[]",
|
|
48
|
+
"desc": "List of domains to exclude from search results.",
|
|
49
|
+
"validator": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"items": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
"includeRawContent": {
|
|
57
|
+
"name": "Include raw content",
|
|
58
|
+
"type": "Boolean",
|
|
59
|
+
"default": "no",
|
|
60
|
+
"desc": "Include the raw content of web pages in the response.",
|
|
61
|
+
"validator": {
|
|
62
|
+
"type": "boolean",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
"outs": {
|
|
67
|
+
"success": {
|
|
68
|
+
"name": "Success",
|
|
69
|
+
"description": "The web search completed successfully.",
|
|
70
|
+
"style": "success",
|
|
71
|
+
},
|
|
72
|
+
"error": {
|
|
73
|
+
"name": "Error",
|
|
74
|
+
"description": "There was an error performing the search.",
|
|
75
|
+
"style": "error",
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def _normalize_domains(self, domains):
|
|
83
|
+
"""Normalize and validate domain list."""
|
|
84
|
+
if not isinstance(domains, list):
|
|
85
|
+
raise ValueError("Domains must be a list.")
|
|
86
|
+
|
|
87
|
+
normalized = []
|
|
88
|
+
seen = set()
|
|
89
|
+
|
|
90
|
+
for domain in domains:
|
|
91
|
+
if not isinstance(domain, str):
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
# Normalize: lowercase, strip whitespace
|
|
95
|
+
normalized_domain = domain.lower().strip()
|
|
96
|
+
|
|
97
|
+
# Skip empty strings
|
|
98
|
+
if not normalized_domain:
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
# Extract hostname (drop protocol, path, query, and port; trim leading www.)
|
|
102
|
+
parsed = urlparse(normalized_domain if '://' in normalized_domain else f'http://{normalized_domain}')
|
|
103
|
+
host = parsed.netloc or parsed.path.split('/', 1)[0]
|
|
104
|
+
|
|
105
|
+
# Skip if we couldn't extract a valid hostname
|
|
106
|
+
if not host:
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
host = host.split(':', 1)[0] # drop port if any
|
|
110
|
+
if host.startswith('www.'):
|
|
111
|
+
host = host[len('www.'):]
|
|
112
|
+
normalized_domain = host.rstrip('.')
|
|
113
|
+
|
|
114
|
+
# Skip if normalization resulted in empty domain
|
|
115
|
+
if not normalized_domain:
|
|
116
|
+
continue
|
|
117
|
+
|
|
118
|
+
# Add to list if not duplicate
|
|
119
|
+
if normalized_domain not in seen:
|
|
120
|
+
seen.add(normalized_domain)
|
|
121
|
+
normalized.append(normalized_domain)
|
|
122
|
+
|
|
123
|
+
return normalized
|
|
124
|
+
|
|
125
|
+
def run(self):
|
|
126
|
+
try:
|
|
127
|
+
query = self._get_field("query", required=True)
|
|
128
|
+
include_domains = self._get_field("includeDomains", as_json=True, default_field_value="[]")
|
|
129
|
+
exclude_domains = self._get_field("excludeDomains", as_json=True, default_field_value="[]")
|
|
130
|
+
include_raw_content = self._get_field("includeRawContent", False, "no") == "yes"
|
|
131
|
+
|
|
132
|
+
# Normalize domain lists
|
|
133
|
+
include_domains = self._normalize_domains(include_domains)
|
|
134
|
+
exclude_domains = self._normalize_domains(exclude_domains)
|
|
135
|
+
|
|
136
|
+
client = self.writer_sdk_client
|
|
137
|
+
|
|
138
|
+
# Build the request parameters
|
|
139
|
+
params = {
|
|
140
|
+
"query": query,
|
|
141
|
+
"include_raw_content": include_raw_content,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if include_domains:
|
|
145
|
+
params["include_domains"] = include_domains
|
|
146
|
+
|
|
147
|
+
if exclude_domains:
|
|
148
|
+
params["exclude_domains"] = exclude_domains
|
|
149
|
+
|
|
150
|
+
response = client.tools.web_search(**params)
|
|
151
|
+
|
|
152
|
+
# Extract the answer and sources from the response
|
|
153
|
+
result = {
|
|
154
|
+
"answer": response.answer if hasattr(response, 'answer') else "",
|
|
155
|
+
"sources": []
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# Process sources if available
|
|
159
|
+
if hasattr(response, 'sources'):
|
|
160
|
+
for source in response.sources:
|
|
161
|
+
source_data = {
|
|
162
|
+
"url": source.url if hasattr(source, 'url') else "",
|
|
163
|
+
"title": source.title if hasattr(source, 'title') else "",
|
|
164
|
+
"snippet": source.snippet if hasattr(source, 'snippet') else "",
|
|
165
|
+
}
|
|
166
|
+
if include_raw_content and hasattr(source, 'raw_content'):
|
|
167
|
+
source_data["raw_content"] = source.raw_content
|
|
168
|
+
result["sources"].append(source_data)
|
|
169
|
+
|
|
170
|
+
self.result = result
|
|
171
|
+
self.outcome = "success"
|
|
172
|
+
|
|
173
|
+
except BaseException as e:
|
|
174
|
+
self.outcome = "error"
|
|
175
|
+
raise e
|