Skip to content

feat(workflow-generator): enhance the AI auto-creation flow end-to-end#38175

Merged
crazywoola merged 18 commits into
mainfrom
feat/enhance-dsl-generation
Jul 1, 2026
Merged

feat(workflow-generator): enhance the AI auto-creation flow end-to-end#38175
crazywoola merged 18 commits into
mainfrom
feat/enhance-dsl-generation

Conversation

@crazywoola

@crazywoola crazywoola commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary

Enhances the AI auto-creation flow — the ⌘K/create and /refine workflow/chatflow generator (behind ENABLE_FEATURE_PREVIEW) — end-to-end, implementing the stage 1–5 program tracked in #38174. Also folds in the two concrete refinements that started this work: dropping the low-value "Ideal output" field and replacing the static example chips with AI-generated, workspace-grounded suggestions.

Closes #38174 (item 3.1 intentionally dropped; see Deferred below).

Osmo.2026-06-30T12-53-31Z.mp4

What changed

Backend (api/)

  • POST /workflow-generate/suggestions — returns a few short, buildable example instructions for the generator's "ideas" chips, grounded in the tenant's real knowledge bases + installed tools. Runs on the tenant default model (works before the user picks one) and soft-fails to { "suggestions": [] } so the UI silently falls back.
  • POST /workflow-generate/stream (SSE) — plan-first generation: emits a plan event the moment the planner finishes, then a result event after the builder + validation. Reuses the existing planner/builder/validate stages through one shared generator, so the streamed result provably equals the blocking /workflow-generate return (parity test included).
  • mode: "auto" on both generate endpoints — a tiny classifier resolves Workflow vs Chatflow before planning; the concrete mode is echoed back as mode and never leaks "auto".
  • The existing /workflow-generate is unchanged except its response now also carries mode.

Frontend (web/)

Stage 1 — entry & input

  • Remove the "Ideal output" field (optional backend param; the shared component stays for the prompt generator).
  • AI suggestion chips replace the static list — fetched on open (session-cached per mode), with a ↻ refresh and a silent static fallback when generation is unavailable.
  • ⌘/Ctrl+Enter to generate and autofocus on the instruction box.
  • Palette inline capture: /create workflow summarize a URL pre-fills the modal; "Auto" submenu option opens auto-mode.

Stage 2 — generation

  • Plan-first streaming view: "Planning…" → the real node outline → the graph, replacing the guessed phase timer. Uses an isolated sseGeneratorPost consumer that reuses the cookie-auth/CSRF/abort setup without touching the shared handleStream. Falls back to the single-shot endpoint if the stream can't start.

Stage 3 — review (3.1 dropped)

  • 3.2 planner metadata header (icon + app name).
  • 3.4 / 3.5 an actionable error panel: localized message + affected node, with Regenerate and (for UNKNOWN_TOOL) Install tools.

Stage 4 — apply

  • 4.1 /refine diff summary (added / removed / changed) computed client-side from the base vs. generated graph.
  • 4.2 post-apply nudge toward ⌘K → /refine.

Stage 5 — history

  • 5.1 last-instruction resume across opens (persisted), so reopening isn't a blank box.

i18n

New keys added across all 23 locales (workflow.json + app.json); en-US authoritative, zh-Hans/zh-Hant translated, others English pending the translate bot.

Tests

  • Backend: 112 generator unit tests pass (suggestions method + route, streaming event sequence + parity, auto-mode resolution).
  • Frontend: 53 pass — new coverage for the suggestions component (fetch → fallback → refresh → select), the graph-diff util, and the updated /create command (inline capture + auto option + threading).
  • type-check clean; eslint --quiet (CI posture) reports no new errors.

Deferred (follow-ups, tracked in #38174)

  • 3.1 inspectable per-node preview — dropped per request.
  • 1.1 "✨ Generate with AI" entry in the Create-App dialog — while the feature is behind ENABLE_FEATURE_PREVIEW the cmd+k entry suffices; lands with GA.
  • 5.1 full "recent generations" gallery — shipped as last-instruction resume for now.

Notes

  • The suggestions endpoint is one cheap default-model call per session per mode (cached); ↻ is the only extra call. No default model → empty → static fallback (no regression).
  • Streaming can't be exercised against a live model in CI; correctness rests on the shared-stage parity test plus the non-streaming fallback.

🤖 Generated with Claude Code

Implements the stage 1–5 program from #38174 (3.1 dropped per request).

Backend (api/)
- New POST /workflow-generate/suggestions: short, workspace-grounded example
  instructions generated on the tenant default model; soft-fails to {suggestions: []}.
- New POST /workflow-generate/stream: SSE plan-first generation that emits the
  planner result (plan) then the built graph (result), reusing the existing
  planner/builder/validate stages — the streamed result provably equals the
  blocking /workflow-generate return.
- mode:"auto" on both generate endpoints; a lightweight classifier resolves the
  concrete mode before planning and it is echoed back as `mode`.

Frontend (web/)
- Remove the low-value "Ideal output" field from the modal.
- Replace the static example chips with AI-generated, workspace-grounded
  suggestions (cached per session per mode, ↻ refresh, silent static fallback).
- Plan-first streaming: show the planner outline as it lands, then the graph
  (replaces the guessed phase timer) via an isolated SSE consumer that reuses
  the existing cookie-auth/CSRF/abort setup without touching handleStream.
- Review stage: planner metadata header (icon + name), an actionable error panel
  (Regenerate / Install tools / affected node), a /refine diff summary, and a
  post-apply nudge toward cmd+k /refine.
- Entry & input: ⌘/Ctrl+Enter to generate, autofocus, palette inline capture
  (`/create workflow <text>`), an "Auto" submenu option, and last-instruction
  resume across opens.

i18n keys added across all 23 locales. New tests cover the suggestions component
(fetch → fallback → refresh), the graph diff util, and the updated /create command.

Refs #38174

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jun 29, 2026
@github-actions github-actions Bot added the web This relates to changes on the web. label Jun 29, 2026
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Pyrefly Type Coverage

Metric Base PR Delta
Type coverage 51.58% 51.59% +0.01%
Strict coverage 51.10% 51.11% +0.02%
Typed symbols 31,008 31,087 +79
Untyped symbols 29,384 29,441 +57
Modules 2935 2938 +3

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-06-30 12:19:09.602412859 +0000
+++ /tmp/pyrefly_pr.txt	2026-06-30 12:18:55.184299325 +0000
@@ -4378,6 +4378,14 @@
    --> tests/unit_tests/core/llm_generator/output_parser/test_structured_output.py:192:16
 ERROR `in` is not supported between `str` and `None` [not-iterable]
    --> tests/unit_tests/core/llm_generator/output_parser/test_structured_output.py:203:16
+ERROR Class member `MockService.get_draft_workflow` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
+   --> tests/unit_tests/core/llm_generator/test_llm_generator_missing.py:152:17
+ERROR Method `get_draft_workflow` inherited from class `WorkflowServiceInterface` has no implementation and cannot be accessed via `super()` [missing-attribute]
+   --> tests/unit_tests/core/llm_generator/test_llm_generator_missing.py:153:24
+ERROR Class member `MockService.get_node_last_run` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
+   --> tests/unit_tests/core/llm_generator/test_llm_generator_missing.py:155:17
+ERROR Method `get_node_last_run` inherited from class `WorkflowServiceInterface` has no implementation and cannot be accessed via `super()` [missing-attribute]
+   --> tests/unit_tests/core/llm_generator/test_llm_generator_missing.py:156:24
 ERROR Object of class `MockAccount` has no attribute `id` [missing-attribute]
    --> tests/unit_tests/core/logging/test_filters.py:201:9
 ERROR Object of class `MockAccount` has no attribute `current_tenant_id` [missing-attribute]
@@ -5591,8 +5599,20 @@
     --> tests/unit_tests/core/workflow/generator/test_runner.py:2438:16
 ERROR Cannot index into `str` [bad-index]
     --> tests/unit_tests/core/workflow/generator/test_runner.py:2439:16
+ERROR Argument `str` is not assignable to parameter `mode` with type `Literal['advanced-chat', 'workflow']` in function `core.workflow.generator.runner.WorkflowGenerator.generate_workflow_graph_stream` [bad-argument-type]
+    --> tests/unit_tests/core/workflow/generator/test_runner.py:3064:111
+ERROR Argument `str` is not assignable to parameter `mode` with type `Literal['advanced-chat', 'workflow']` in function `core.workflow.generator.runner.WorkflowGenerator.generate_workflow_graph` [bad-argument-type]
+    --> tests/unit_tests/core/workflow/generator/test_runner.py:3066:103
+ERROR Class member `MockGenerator._collect_refs_in_data` overrides parent class `WorkflowGenerator` in an inconsistent manner [bad-override-param-name]
+   --> tests/unit_tests/core/workflow/generator/test_runner_missing.py:112:13
+ERROR Class member `MockGenerator._collect_refs_in_data` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
+   --> tests/unit_tests/core/workflow/generator/test_runner_missing.py:112:13
+ERROR Argument `dict[str, list[dict[str, str]]]` is not assignable to parameter `graph` with type `GraphDict` in function `core.workflow.generator.runner.WorkflowGenerator._collect_edge_cycle_errors` [bad-argument-type]
+   --> tests/unit_tests/core/workflow/generator/test_runner_missing.py:124:65
+ERROR Argument `dict[str, list[dict[str, str | dict[str, str]]] | list[Unknown]]` is not assignable to parameter `graph` with type `GraphDict` in function `core.workflow.generator.runner.WorkflowGenerator._validate_structure` [bad-argument-type]
+   --> tests/unit_tests/core/workflow/generator/test_runner_missing.py:185:58
 ERROR Argument `None` is not assignable to parameter `plugin_id` with type `str` in function `_make_plugin_provider` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/generator/test_tool_catalogue.py:344:55
+   --> tests/unit_tests/core/workflow/generator/test_tool_catalogue.py:352:55
 ERROR Default `str` is not assignable to parameter `node_type` with type `BuiltinNodeTypes` [bad-function-definition]
   --> tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py:48:50
 ERROR Argument `str` is not assignable to parameter `node_type` with type `BuiltinNodeTypes` in function `_build_node` [bad-argument-type]

@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.83754% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.40%. Comparing base (44e85c0) to head (4042de0).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
api/core/llm_generator/llm_generator.py 89.36% 5 Missing and 5 partials ⚠️
web/service/base.ts 86.66% 6 Missing ⚠️
api/controllers/console/app/generator.py 93.22% 2 Missing and 2 partials ⚠️
api/core/workflow/generator/runner.py 93.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #38175      +/-   ##
==========================================
+ Coverage   85.36%   85.40%   +0.04%     
==========================================
  Files        4970     4973       +3     
  Lines      258774   259157     +383     
  Branches    49076    49133      +57     
==========================================
+ Hits       220893   221339     +446     
+ Misses      33576    33515      -61     
+ Partials     4305     4303       -2     
Flag Coverage Δ
api 85.57% <92.19%> (+0.05%) ⬆️
dify-ui 94.93% <ø> (ø)
web 85.08% <96.05%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

autofix-ci Bot and others added 5 commits June 29, 2026 16:38
pyrefly rejected flask.stream_with_context called with a generator
(constrained AnyStr overload — "no-matching-overload"), failing the
Python type-check CI. Switch the streaming endpoint to the repo's
established SSE helper compact_generate_response (which wraps
_stream_with_request_context), so it type-checks and still preserves
request context during iteration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- jsonc/sort-keys (CI TS Common): the new i18n keys were appended at the end;
  re-sort them into ascending order across all locales via eslint --fix.
- knip (CI Web Style): WorkflowGenPlanNode / WorkflowGenPlanInput are only used
  inside debug.ts, so stop exporting them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a render test for GenerationPlan (planning state vs. plan outline +
building state), covering the previously-untested new component and
improving patch coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…38202)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
@crazywoola crazywoola self-assigned this Jun 30, 2026
Copilot AI and others added 11 commits June 30, 2026 16:07
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- web/service/base.spec.ts: replace require() with ESM import, add eslint-disable for no-restricted-imports
- web/service/debug.spec.ts: fix trailing commas, trailing spaces, if-newline, no-explicit-any, and import order
- api/tests/.../test_runner_missing.py: remove invalid node_ids kwarg from _validate_structure call

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…proof

The TestBuildToolCatalogue cases patch `isinstance` and route the provider
class checks through `_patched_isinstance`, which compared `cls` by identity
(`is`) against a fresh import of Builtin/PluginToolProviderController. In the
full API unit-test suite (parallel xdist), a sibling test that reloads or stubs
`core.tools.*.provider` via sys.modules hands the catalogue a class object that
differs by identity from a fresh import here — the `is` checks miss, every fake
provider falls through to the real isinstance, and build_tool_catalogue returns
empty. That flaked 6 cases in CI (`assert [] == [...]`) while passing in
isolation.

Match the provider classes by `__name__`, which is immune to reloads. Test-only;
passes in isolation and under a broad core sweep.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Post

Root-cause fix for the API Unit Tests failure: TestBuildSuggestionContext stubbed
`core.workflow.generator.tool_catalogue` in sys.modules and then `del`-ed it
instead of restoring the original. Under xdist that evicted the real module, so a
sibling test (test_tool_catalogue) that imported `build_tool_catalogue` at
collection time diverged from a freshly re-imported module and its @patch targets
stopped applying — 6 catalogue tests came back empty. Reproduced locally
(polluter→victim) and fixed by restoring via monkeypatch.setitem.

Also add a sseGeneratorPost unit test (plan/result streaming, chunk-split
reassembly, non-2xx + rejected-fetch error paths) to cover the SSE consumer,
which was the largest patch-coverage gap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the hand-rolled planner preview markup with existing Dify UI widgets:
- swap the bespoke numbered step badges for the shared workflow BlockIcon so
  each plan step shows the same icon it will have on the canvas
- swap the bare centred "Planning…" spinner for the shared Skeleton primitives,
  shaped like the node list so the pane fills in place instead of jumping

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 1, 2026
@crazywoola crazywoola added this pull request to the merge queue Jul 1, 2026
Merged via the queue into main with commit 8809cc0 Jul 1, 2026
43 checks passed
@crazywoola crazywoola deleted the feat/enhance-dsl-generation branch July 1, 2026 02:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:XXL This PR changes 1000+ lines, ignoring generated files. web This relates to changes on the web.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhance the AI auto-creation (⌘K /create & /refine) flow end-to-end

4 participants