diff --git a/src/ui/src/components/workflows/base/WorkflowNavigator.vue b/src/ui/src/components/workflows/base/WorkflowNavigator.vue index 07fc5e0a7..db4683faa 100644 --- a/src/ui/src/components/workflows/base/WorkflowNavigator.vue +++ b/src/ui/src/components/workflows/base/WorkflowNavigator.vue @@ -159,7 +159,7 @@ watch(zoomLevel, (newZoomLevel) => { }); function handleKeydown(ev: KeyboardEvent) { - if (!isModifierKeyActive) return; + if (isModifierKeyActive(ev) === false) return; let newZoomLevel = zoomLevel.value; if (ev.key == "+" || ev.key == "=") { diff --git a/src/writer/workflows_blocks/httprequest.py b/src/writer/workflows_blocks/httprequest.py index 085575333..aa77f4977 100644 --- a/src/writer/workflows_blocks/httprequest.py +++ b/src/writer/workflows_blocks/httprequest.py @@ -21,13 +21,13 @@ def register(cls, type: str): "name": "Method", "type": "Text", "options": { - "get": "GET", - "post": "POST", - "put": "PUT", - "patch": "PATCH", - "delete": "DELETE" + "GET": "GET", + "POST": "POST", + "PUT": "PUT", + "PATCH": "PATCH", + "DELETE": "DELETE" }, - "default": "get" + "default": "GET" }, "url": { "name": "URL", diff --git a/src/writer/workflows_blocks/writerchat.py b/src/writer/workflows_blocks/writerchat.py index b0c7814ea..02afe9558 100644 --- a/src/writer/workflows_blocks/writerchat.py +++ b/src/writer/workflows_blocks/writerchat.py @@ -21,6 +21,15 @@ def register(cls, type: str): "desc": "Where the conversation will be stored", "type": "Text", }, + "useStreaming": { + "name": "Use streaming", + "type": "Text", + "default": "yes", + "options": { + "yes": "Yes", + "no": "No" + } + }, "tools": { "name": "Tools", "type": "Tools", @@ -78,6 +87,7 @@ def run(self): import writer.ai conversation_state_element = self._get_field("conversationStateElement") + use_streaming = self._get_field("useStreaming", False, "yes") == "yes" tools_raw = self._get_field("tools", True) tools = [] @@ -110,12 +120,17 @@ def run(self): try: msg = "" - for chunk in conversation.stream_complete(tools=tools): - if chunk.get("content") is None: - chunk["content"] = "" - msg += chunk.get("content") - conversation += chunk + if not use_streaming: + msg = conversation.complete(tools=tools) + conversation += msg self.evaluator.set_state(conversation_state_element, self.instance_path, conversation, base_context=self.execution_env) + else: + for chunk in conversation.stream_complete(tools=tools): + if chunk.get("content") is None: + chunk["content"] = "" + msg += chunk.get("content") + conversation += chunk + self.evaluator.set_state(conversation_state_element, self.instance_path, conversation, base_context=self.execution_env) except BaseException: msg = { "role": "assistant", diff --git a/tests/e2e/presets/workflows/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl b/tests/e2e/presets/workflows/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl new file mode 100644 index 000000000..110c00bf7 --- /dev/null +++ b/tests/e2e/presets/workflows/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl @@ -0,0 +1,5 @@ +{"id": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "type": "page", "content": {"pageMode": "compact"}, "handlers": {}, "isCodeManaged": false, "parentId": "root", "position": 0, "visible": {"binding": "", "expression": true, "reversed": false}} +{"id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf", "type": "header", "content": {"text": "Workflows Test App"}, "handlers": {}, "isCodeManaged": false, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "position": 0, "visible": {"binding": "", "expression": true, "reversed": false}} +{"id": "ixxb26ukbvr0sknw", "type": "repeater", "content": {"keyVariable": "itemId", "repeaterObject": "{ \"pl\": { \"object\": \"plant\" }, \"cu\": { \"object\": \"cup\" }}", "valueVariable": "item"}, "handlers": {}, "isCodeManaged": false, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "position": 1} +{"id": "iftqnmjw8ipaknex", "type": "section", "content": {"title": "@{itemId}: @{item.object}"}, "handlers": {}, "isCodeManaged": false, "parentId": "ixxb26ukbvr0sknw", "position": 0} +{"id": "7no34ag7gmwgm1rd", "type": "textinput", "content": {"label": ""}, "handlers": {"wf-change": "$runWorkflow_handle_object"}, "isCodeManaged": false, "parentId": "iftqnmjw8ipaknex", "position": 0} diff --git a/tests/e2e/presets/workflows/.wf/components-page-1-i9io5f734z9esrxs.jsonl b/tests/e2e/presets/workflows/.wf/components-page-1-i9io5f734z9esrxs.jsonl new file mode 100644 index 000000000..5a00a5f42 --- /dev/null +++ b/tests/e2e/presets/workflows/.wf/components-page-1-i9io5f734z9esrxs.jsonl @@ -0,0 +1,2 @@ +{"id": "i9io5f734z9esrxs", "type": "page", "content": {}, "handlers": {}, "isCodeManaged": false, "parentId": "root", "position": 1} +{"id": "16eeo21o6k8tcxf7", "type": "chatbot", "content": {"conversation": "@{convo}"}, "handlers": {"wf-chatbot-message": "$runWorkflow_handle_object"}, "isCodeManaged": false, "parentId": "i9io5f734z9esrxs", "position": 0} diff --git a/tests/e2e/presets/workflows/.wf/components-root.jsonl b/tests/e2e/presets/workflows/.wf/components-root.jsonl new file mode 100644 index 000000000..0621b125d --- /dev/null +++ b/tests/e2e/presets/workflows/.wf/components-root.jsonl @@ -0,0 +1 @@ +{"id": "root", "type": "root", "content": {"appName": "My App"}, "handlers": {}, "isCodeManaged": false, "position": 0, "visible": {"binding": "", "expression": true, "reversed": false}} \ No newline at end of file diff --git a/tests/e2e/presets/workflows/.wf/components-workflows_root.jsonl b/tests/e2e/presets/workflows/.wf/components-workflows_root.jsonl new file mode 100644 index 000000000..e6067e964 --- /dev/null +++ b/tests/e2e/presets/workflows/.wf/components-workflows_root.jsonl @@ -0,0 +1 @@ +{"id": "workflows_root", "type": "workflows_root", "content": {}, "handlers": {}, "isCodeManaged": false, "position": 0, "visible": {"binding": "", "expression": true, "reversed": false}} \ No newline at end of file diff --git a/tests/e2e/presets/workflows/.wf/components-workflows_workflow-0-auxjfi7lssb268ly.jsonl b/tests/e2e/presets/workflows/.wf/components-workflows_workflow-0-auxjfi7lssb268ly.jsonl new file mode 100644 index 000000000..c9267239c --- /dev/null +++ b/tests/e2e/presets/workflows/.wf/components-workflows_workflow-0-auxjfi7lssb268ly.jsonl @@ -0,0 +1,6 @@ +{"id": "auxjfi7lssb268ly", "type": "workflows_workflow", "content": {"key": "handle_object"}, "handlers": {}, "isCodeManaged": false, "parentId": "workflows_root", "position": 0} +{"id": "bgfri5xbo3l5916z", "type": "workflows_writeraddchatmessage", "content": {"conversationStateElement": "convo", "message": "@{payload}"}, "handlers": {}, "isCodeManaged": false, "outs": [{"toNodeId": "36w4ghu0oioub912", "outId": "success"}], "parentId": "auxjfi7lssb268ly", "position": 0, "x": 473, "y": 204} +{"id": "36w4ghu0oioub912", "type": "workflows_writerchat", "content": {"conversationStateElement": "convo", "tools": "{\"get_employee_info\":{\"description\":\"Gets info for an employee, given an employee id\",\"parameters\":{\"id\":{\"type\":\"string\",\"description\":\"Id of the employee\"}},\"type\":\"function\"}}", "useStreaming": "no"}, "handlers": {}, "isCodeManaged": false, "outs": [{"toNodeId": "6ktplk37vue14rog", "outId": "tools_get_employee_info"}], "parentId": "auxjfi7lssb268ly", "position": 1, "x": 889, "y": 173} +{"id": "6ktplk37vue14rog", "type": "workflows_httprequest", "content": {"url": "https://reqres.in/api/users/@{id}"}, "handlers": {}, "isCodeManaged": false, "outs": [{"toNodeId": "8ly2cojv5m77lfpd", "outId": "success"}], "parentId": "auxjfi7lssb268ly", "position": 2, "x": 1382, "y": 152} +{"id": "i183fmlmluglk2tg", "type": "workflows_writerinitchat", "content": {"alias": "", "conversationStateElement": "convo"}, "handlers": {}, "isCodeManaged": false, "outs": [{"toNodeId": "bgfri5xbo3l5916z", "outId": "success"}], "parentId": "auxjfi7lssb268ly", "position": 3, "x": 52, "y": 203} +{"id": "8ly2cojv5m77lfpd", "type": "workflows_returnvalue", "content": {"value": "@{result.body}"}, "handlers": {}, "isCodeManaged": false, "parentId": "auxjfi7lssb268ly", "position": 4, "x": 1744, "y": 170} diff --git a/tests/e2e/presets/workflows/.wf/metadata.json b/tests/e2e/presets/workflows/.wf/metadata.json new file mode 100644 index 000000000..cab48d17b --- /dev/null +++ b/tests/e2e/presets/workflows/.wf/metadata.json @@ -0,0 +1,3 @@ +{ + "writer_version": "0.8.0rc6" +} \ No newline at end of file diff --git a/tests/e2e/presets/workflows/main.py b/tests/e2e/presets/workflows/main.py new file mode 100644 index 000000000..e188817ab --- /dev/null +++ b/tests/e2e/presets/workflows/main.py @@ -0,0 +1,3 @@ +import writer as wf + +wf.Config.feature_flags = ["workflows"] \ No newline at end of file diff --git a/tests/e2e/tests/workflows.spec.ts b/tests/e2e/tests/workflows.spec.ts new file mode 100644 index 000000000..7d4bd980a --- /dev/null +++ b/tests/e2e/tests/workflows.spec.ts @@ -0,0 +1,43 @@ +/* +import { test, expect } from "@playwright/test"; + +const setTextField = async (page, text) => { + await page.locator('div.CoreText.component').click(); + await page + .locator('.BuilderFieldsText[data-automation-key="text"] .templateInput') + .fill(text); +} + +test.describe("state autocompletion", () => { + let url: string; + + test.beforeAll(async ({request}) => { + const response = await request.post(`/preset/workflows`); + expect(response.ok()).toBeTruthy(); + ({url} = await response.json()); + }); + + test.afterAll(async ({request}) => { + await request.delete(url); + }); + + test.beforeEach(async ({ page }) => { + await page.goto(url); + }); + + test.describe("text", () => { + test("completion", async ({ page }) => { + + const instancePaths = ["root:0,c0f99a9e-5004-4e75-a6c6-36f17490b134:0,ixxb26ukbvr0sknw:0,iftqnmjw8ipaknex:0,7no34ag7gmwgm1rd:0", "root:0,c0f99a9e-5004-4e75-a6c6-36f17490b134:0,ixxb26ukbvr0sknw:0,iftqnmjw8ipaknex:0,7no34ag7gmwgm1rd:0"]; + + await setTextField(page, "@{types."); + page.locator('.BuilderFieldsText[data-automation-key="text"] .fieldStateAutocomplete span.prop:text-matches("string")').click(); + await expect(page + .locator('.BuilderFieldsText[data-automation-key="text"] .templateInput')) + .toHaveValue("@{types.string"); + }); + + }); + +}); +*/ \ No newline at end of file