diffusers-workflow 0.7.0__py3-none-any.whl → 0.8.0__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 (90) hide show
  1. {diffusers_workflow-0.7.0.dist-info → diffusers_workflow-0.8.0.dist-info}/METADATA +2 -2
  2. {diffusers_workflow-0.7.0.dist-info → diffusers_workflow-0.8.0.dist-info}/RECORD +88 -77
  3. dw/assets.py +5 -2
  4. dw/docs/ARCHITECTURE.md +23 -1
  5. dw/docs/LORAS.md +66 -0
  6. dw/docs/MCP.md +7 -4
  7. dw/docs/RELEASING.md +137 -2
  8. dw/docs/SECURITY.md +1 -0
  9. dw/docs/SERVER.md +29 -4
  10. dw/docs/WORKFLOW_GUIDE.md +241 -1
  11. dw/docs/WORKSPACES.md +6 -2
  12. dw/events.py +6 -0
  13. dw/introspection.py +5 -0
  14. dw/library.py +25 -3
  15. dw/locations.py +53 -18
  16. dw/lora_catalog.py +134 -0
  17. dw/lora_catalog_schema.json +57 -0
  18. dw/lora_hub.py +237 -0
  19. dw/media.py +11 -5
  20. dw/path_redaction.py +72 -0
  21. dw/run.py +2 -2
  22. dw/security.py +20 -0
  23. dw/server/admission.py +31 -13
  24. dw/server/api_models.py +824 -0
  25. dw/server/app.py +26 -1
  26. dw/server/assess.py +44 -1
  27. dw/server/deps.py +21 -1
  28. dw/server/guides.py +1 -1
  29. dw/server/inline_media.py +131 -0
  30. dw/server/jobs.py +21 -8
  31. dw/server/outputs.py +65 -4
  32. dw/server/routes/__init__.py +2 -1
  33. dw/server/routes/assets.py +24 -4
  34. dw/server/routes/files.py +3 -3
  35. dw/server/routes/gallery.py +28 -38
  36. dw/server/routes/jobs.py +108 -12
  37. dw/server/routes/library.py +132 -36
  38. dw/server/routes/loras.py +275 -0
  39. dw/server/routes/media.py +102 -19
  40. dw/server/routes/system.py +72 -17
  41. dw/server/ui/assets/{cssMode-DQI1FUIr.js → cssMode-C1mrKegs.js} +1 -1
  42. dw/server/ui/assets/{editor.api-a3j9A86u.js → editor.api-EZbUgQvM.js} +1 -1
  43. dw/server/ui/assets/{freemarker2-BcdiHyGC.js → freemarker2-Dth1K2Vy.js} +1 -1
  44. dw/server/ui/assets/{handlebars-DCj-aPE8.js → handlebars-8Sswqnxq.js} +1 -1
  45. dw/server/ui/assets/{html-D8xomw9g.js → html-BYtYo7f1.js} +1 -1
  46. dw/server/ui/assets/{htmlMode-DK_n-eew.js → htmlMode-B_AiWoXc.js} +1 -1
  47. dw/server/ui/assets/index-B6Ujrvuj.js +45 -0
  48. dw/server/ui/assets/index-BChhQc7I.css +1 -0
  49. dw/server/ui/assets/{javascript-SmmG4uTF.js → javascript-E4m083D3.js} +1 -1
  50. dw/server/ui/assets/{jsonMode-BRyslvRu.js → jsonMode--h7ZikWy.js} +1 -1
  51. dw/server/ui/assets/{liquid-CC4C0BTL.js → liquid-BzbKdLRW.js} +1 -1
  52. dw/server/ui/assets/{lspLanguageFeatures-Cmg2_33_.js → lspLanguageFeatures-CRa0bRFV.js} +1 -1
  53. dw/server/ui/assets/{mdx-DTAejllH.js → mdx-BJ4u6XQs.js} +1 -1
  54. dw/server/ui/assets/{monaco-C_Um4bRZ.js → monaco-DwaeaVri.js} +4 -4
  55. dw/server/ui/assets/{python-DKASw3vF.js → python-CoX_gCAL.js} +1 -1
  56. dw/server/ui/assets/{razor-CkEOBTMa.js → razor-BCTdG5SN.js} +1 -1
  57. dw/server/ui/assets/{tsMode-CmkUIEUu.js → tsMode-B6BV7a76.js} +1 -1
  58. dw/server/ui/assets/{typescript-BXTFUpwg.js → typescript-DJe7-fvZ.js} +1 -1
  59. dw/server/ui/assets/{workers-Cpj1l6gK.js → workers-DCzLJTPE.js} +1 -1
  60. dw/server/ui/assets/{xml-D1BkO5yz.js → xml-CNvWfUrB.js} +1 -1
  61. dw/server/ui/assets/{yaml-CDFThBDz.js → yaml-ByARP6WE.js} +1 -1
  62. dw/server/ui/index.html +2 -2
  63. dw/task_domains.py +1 -0
  64. dw/tasks/audio_utils.py +9 -4
  65. dw/tasks/h3_latent_upscale.py +341 -0
  66. dw/tasks/h3_latent_upscaler_model.py +274 -0
  67. dw/tasks/loop_bed.py +9 -2
  68. dw/tasks/task.py +74 -0
  69. dw/worker.py +24 -3
  70. dw/workspace.py +5 -3
  71. dw_mcp/__main__.py +1 -1
  72. dw_mcp/assets.py +25 -82
  73. dw_mcp/authoring.py +5 -31
  74. dw_mcp/catalog.py +9 -23
  75. dw_mcp/client.py +75 -53
  76. dw_mcp/confine.py +70 -0
  77. dw_mcp/diagnose.py +32 -23
  78. dw_mcp/loras.py +29 -0
  79. dw_mcp/media.py +84 -254
  80. dw_mcp/server.py +12 -1
  81. dw_mcp/tools_authoring.py +37 -2
  82. dw_mcp/tools_catalog.py +2 -4
  83. dw_mcp/tools_media.py +4 -4
  84. dw_mcp/workspaces.py +17 -31
  85. dw/server/ui/assets/index-3Vw6WAPW.css +0 -1
  86. dw/server/ui/assets/index-CNiY-pOw.js +0 -44
  87. {diffusers_workflow-0.7.0.dist-info → diffusers_workflow-0.8.0.dist-info}/WHEEL +0 -0
  88. {diffusers_workflow-0.7.0.dist-info → diffusers_workflow-0.8.0.dist-info}/entry_points.txt +0 -0
  89. {diffusers_workflow-0.7.0.dist-info → diffusers_workflow-0.8.0.dist-info}/licenses/LICENSE +0 -0
  90. {diffusers_workflow-0.7.0.dist-info → diffusers_workflow-0.8.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffusers-workflow
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: Declarative workflow engine and web UI for Hugging Face Diffusers
5
5
  Author: dkackman
6
6
  License: Apache-2.0
@@ -168,7 +168,7 @@ once; without it the run fails partway through with a 401/403 from the Hub.
168
168
 
169
169
  ## Drive it from an agent
170
170
 
171
- Then just ask. The agent has 59 tools covering the whole surface — the
171
+ Then just ask. The agent has 62 tools covering the whole surface — the
172
172
  workflow catalog, the real diffusers pipeline signatures, the job queue, the
173
173
  gallery, the model cache:
174
174
 
@@ -1,11 +1,11 @@
1
- diffusers_workflow-0.7.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1
+ diffusers_workflow-0.8.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
2
2
  dw/__init__.py,sha256=fWaCvN4c5PtD97ZufrMz0okq33fxTWHmJp9UCuluouw,19183
3
3
  dw/adapter_compatibility.py,sha256=OAJdCDsiU29DX-vW5DIGN3kUcapbq3Bz6vU6GCgV_6w,11316
4
4
  dw/argument_media.py,sha256=yeXBDAoFnLhMKb-YFxtqmqgXhwqmj3Eh-sJblSxsa_4,12816
5
5
  dw/argument_warnings.py,sha256=Kwy-gicCXOnsAEs_08p7X7g-HEjfzukVkP6qQFRHSak,10457
6
6
  dw/arguments.py,sha256=QsE5DkdAopzXoHJowt2-Bm2pscmQagKoQvn6ty7stng,39292
7
7
  dw/assessment_rules.py,sha256=MHfE1hYIYw3aeFoZvmLtFIKxYZD0MxHWxZZVrOtOEVk,7246
8
- dw/assets.py,sha256=6UTMZTD_6hrjui-q7guyU_w3Ud-ogUvqSBJsjjPsJaA,5399
8
+ dw/assets.py,sha256=NT9RVK2Pi4Rs4r1sDru1QCEqZXqzr5YAtsiDG1TYa28,5583
9
9
  dw/audio_qc.py,sha256=9HTb3s8tH0sC7mVRQDqfC70w80m8bNEcgti-TeSVQCs,19113
10
10
  dw/cache_blocks.json,sha256=m7mJV7Pwv5LnwzW-2Daa71W3yKh6x7VdxFS7ShEiUG4,1633
11
11
  dw/cache_blocks.py,sha256=A_S9pID6jqgheRg2DFFmIPLiS7XJUNT44eXk3W01SSg,5719
@@ -14,20 +14,24 @@ dw/dissolve_frame_errors.py,sha256=WrWxAkMAkNXtoeVXJPB9vaxzblAtUMvDSZXfipGr-zU,5
14
14
  dw/download_watch.py,sha256=x0RGfJy7t_ZQJ4FD3GcGcdJd-bjmllLLVCXKYhFE9JI,12656
15
15
  dw/dsp.py,sha256=asxFCk2zFyO0qRnxMtY4rCZyfx3OELE_lk0J1X4iHH8,25268
16
16
  dw/elision.py,sha256=HGlw1IB0k2dMQEYU3DKsIoeNGd1oKhs-J5hcWeVyc8Q,13224
17
- dw/events.py,sha256=isoEkfrKktNkZFFbe2wgtzQr2ITutJSOsFh8VtZdumk,12242
17
+ dw/events.py,sha256=PUZ2OthWZsQh6z5nyvRoMJ1ZbvI2PlXsFLh2gdYK_0o,12626
18
18
  dw/for_each.py,sha256=Bz1iRXCgETDy5ZKVYIPnKuVmnML8X6n1XEBqzxk1tSw,16532
19
19
  dw/host_memory.py,sha256=Gfr-nwgMCSieZExLAhwX3iX78aswrw8h1VqQjJy6qGE,9723
20
20
  dw/host_memory_projection.py,sha256=kGQ7hpmR_jsT66mWypmpZs0NYjQwZ8gVQIqI9Id3pEQ,10320
21
21
  dw/hub_cache.py,sha256=PUxpajmh8WQActZT_jv7YEHHCMNhuEejlzBJOyisvIY,15627
22
- dw/introspection.py,sha256=b9SuwVcz30MKoWat7lwOHPjSErnrrOoHMFp_sePQHo4,29804
22
+ dw/introspection.py,sha256=KQzcY9YHnTZoZnJpGZysLD62mwDcuUI3fgXrDupi_aY,30043
23
23
  dw/kernel_availability.py,sha256=P0gxOCzuNPsjZ-60j9O6TKkyzXRxvSh8QKmQqNKzk3A,9173
24
- dw/library.py,sha256=CzDCNMFqPfyKw6ixcUlD2WNGxeYMd6f6XU48accB8U0,32717
25
- dw/locations.py,sha256=turYZpDHFcIEEIwjrp_XbcmB88-6xsOjeZ-6tPhb3SA,27957
24
+ dw/library.py,sha256=EEkVFQsMOZWCNC1WHHtSnAsERUQ2fr1ZhpwSRdb1lq0,33589
25
+ dw/locations.py,sha256=P8mhmiQJ8NP6r7U2znk7cf6xZBnSz0abLa9Wo5DuR-A,29438
26
26
  dw/log_setup.py,sha256=ATwSO0CCDtgEA-VoPsS8HVeuDwL2jBg--4QXSZwecQs,1478
27
- dw/media.py,sha256=HR3wMloU7AWnQeomGYCutnETE6Jek-DQ4kDW1jxDIMQ,38217
27
+ dw/lora_catalog.py,sha256=B6RRgdyY0NSCyAwMVoDS3_wxyqF9i3Q3JjEx-hCMVAI,4893
28
+ dw/lora_catalog_schema.json,sha256=i-oh9JR8DbKoNxZ2ufnyPaTaNT8hpeY_I6I3Zrhrl_w,2120
29
+ dw/lora_hub.py,sha256=Px2cV9yAQsKve6WZuvuQCOfgLWjJ1bJx0uDbxeK2kmQ,8500
30
+ dw/media.py,sha256=btmfeQ2nCxUDQbJOTHaqJEDMnvrPz_Ll53QfYJVZ4Y4,38411
28
31
  dw/media_frames.py,sha256=2WLLU4Z1NgN4rTxSVDHDs5VZVQqbHXMtOz-ekvonoAA,12789
29
32
  dw/media_types.py,sha256=to2bGLpfF__EJnXxis-t0SHlzgx_WzlK6t0roqLf24g,8045
30
33
  dw/output_extraction.py,sha256=Q4OB2Lnz8yF9sK6H2svBDNuf4G8shEuQRExEaVieUXU,9610
34
+ dw/path_redaction.py,sha256=Zv8sGmZQ0meQYinMhqo10IJKt5egqkjekbiTSPoBVJg,2949
31
35
  dw/pipeline_ownership.py,sha256=sY90vQVLBXzAeyR6jVygGm4i_FqfSeGp7up_0SvNSYE,12944
32
36
  dw/plan.py,sha256=xIFilQAcNwqFQh6Dmgq6l5qns1dcBGtA8ruHErSNP5M,38998
33
37
  dw/previous_results.py,sha256=Ano0nl0714eEgJd76e4Xu-1EC3vvaE4MsdvHVTIBMoU,16313
@@ -40,11 +44,11 @@ dw/reference_limits.py,sha256=w0HGRz7TlIsnMRZ3zMSsufW58mPN4RkmhDQK00xhmCs,8122
40
44
  dw/reference_names.py,sha256=oIBH4c-ICKdwOVufWF0NUOWE1FAWs-FEJQuUyqEJ5vU,5077
41
45
  dw/references.py,sha256=mCb2eIkavb7vg3EUlq_jTdjmvBc_meFNtQaKELYAfWM,5901
42
46
  dw/result.py,sha256=-Xn3KMXJaOq6wOo0rMQY9HeBX6hltKhe5BUSQThCArU,37301
43
- dw/run.py,sha256=dqTIkt1seh2Fs7yNZLUdg6aZHZCdErBaXxXE-gz0GrY,9304
47
+ dw/run.py,sha256=irH-b_QvbFa0X1F_9M2iX1uxNI74K5vnQCE9MiPaK1I,9316
44
48
  dw/runs.py,sha256=4cqsXuXiSUzEJ4SkJawCy0KEQiqjRWz_W80OD-O32Zg,36798
45
49
  dw/scalar_result_validation.py,sha256=vu-2dAIuipCpA2ajUs1hoM-j2Blc1IGCGnzQwCg3TGM,5612
46
50
  dw/schema.py,sha256=QDMwcONbaGQqcaHNp9_gYXKPIRqm6qBGfdLHFDOijbM,10473
47
- dw/security.py,sha256=gV1VfAMjH0sKDcD99nTqxxItCjlrK2RHa26yuVyFyYs,26099
51
+ dw/security.py,sha256=LiP8pbSFzUzFuHRFg8xhszMLbE5T0tvw-XacIGxkzus,26868
48
52
  dw/serve.py,sha256=IrTu9I0OP_JrvogBaKarR__q4jC4B7O96sxKjknjriU,12664
49
53
  dw/settings.py,sha256=DZoO9dx0M7LPe7L3KOjhVdJhKLTgEA6OvAW6o9pIyIo,4094
50
54
  dw/shot_span_preflight.py,sha256=z20FExMyym1W2faT4g_A4yF3ymMJXgJy05-vTy12BDY,4707
@@ -54,7 +58,7 @@ dw/step.py,sha256=0nGm4ZQOTfMLoTHSdrp80VhkEXo-O9BBNKhvI1nSsHc,9329
54
58
  dw/step_cache.py,sha256=mpbvhIRQ8_lAr0BaiGER-LHeNfG7fGphAW47zlH5iho,27743
55
59
  dw/step_value_checks.py,sha256=t0naaW4lcHuBMldj51xBJIuTZnLZUTAdLGq5W1aC7hY,12703
56
60
  dw/subfolders.py,sha256=bYGvz0BUM1jiFd9HxGyLjz-W-oseJrhBmNj7fjminGY,4164
57
- dw/task_domains.py,sha256=tui7IDS-JsnJel0NVopc4f_TlECXMq32oG61ZZGxtY4,18525
61
+ dw/task_domains.py,sha256=9pTtUC2LzVWccEYwr1sYTSYXVYYn5vPYJCpKKezBnLw,18592
58
62
  dw/test.py,sha256=P6JkCw1OjVh-xY_kS-STGlkEHpN9riToXV7A20WX5MA,582
59
63
  dw/trust.py,sha256=YN_CFso36OK5PTjI663r9QPThzGsVT5j5VWwKNjdD-o,11778
60
64
  dw/type_helpers.py,sha256=LlSi34q5k-Nrr3o7y65qWrNkHNikCKIRc42XfDr5yj4,9683
@@ -67,35 +71,35 @@ dw/video_extensions.py,sha256=ctsbigz6ao4wgMc6jLvrRUQIxfbMA5pDaxvUrQAimG4,5523
67
71
  dw/video_size_errors.py,sha256=i-L3UDNRao_iRE8KNaEVDLu_16J37xJn7IYWYZ9em9Y,4861
68
72
  dw/vram_estimate.py,sha256=4AeMEra1xmuBXWX-5n0fJ__7-_070LeCBkZMq00qI_E,16881
69
73
  dw/vram_inheritance.py,sha256=BDgJlLhgnoOUnbhcjcQLiTlrHmFS4aZ53m9IeJ5WitQ,6518
70
- dw/worker.py,sha256=pIdCv8hjwiu6214Rhx6Ka-KkP58novGx_QPsx1WxtY0,33838
74
+ dw/worker.py,sha256=uMs-WvDoGJ607MIAipv0XxHdh7mOH7BFqpAQUMhtYxI,34974
71
75
  dw/worker_manager.py,sha256=stggctseAljNQa3c-ts8Ah5gvWAmyZyBxaSlrnmhjN8,7858
72
76
  dw/worker_protocol.py,sha256=Y9SQJRpE1xZI2a3D0cFx_qqxKN2zRZauOHGCnjcKqhg,6141
73
77
  dw/workflow.py,sha256=gA-047EfH28Euh_XjCLvwH3hxRbVqIRD7fgubZY-acQ,39805
74
78
  dw/workflow_run.py,sha256=wULHYMW9L8f8BWTr6OOzSrq2gsTEy584JeBBcgr6ja8,40725
75
79
  dw/workflow_schema.json,sha256=cLYsknkmjtaiZLxl8cYJ8Rt1mJCqreF9-KIiE8i4Mkw,69314
76
- dw/workspace.py,sha256=6X9bQdJ6fxt7lpAD9Ed2N69hK4EI27dxSZppR6cr8uY,25674
80
+ dw/workspace.py,sha256=8OdAqHjIZGX8MLpuNqzEZcowFXNnHC9kKZot4KNUyyE,25831
77
81
  dw/writers.py,sha256=1ajMnU9mMvx4X62-Us4nODBeP-tk3_IkUoJYoRe2htY,14633
78
82
  dw/community_pipelines/pipeline_flux_rf_inversion.py,sha256=XjLO58h5wQn16qP8wEIZKg2Y46mxzQ8qkUu29iQnrrA,50587
79
83
  dw/docs/ACCELERATION.md,sha256=dLJjJody8rRxPNhyJ0PdPZ29kp-nvtscHHvhAZsGOBY,17258
80
84
  dw/docs/AGENT_LOOP.md,sha256=rMb_c_r2ucsB7djwtQdp9_VVRagvhevWo-Iep7emmS8,4729
81
- dw/docs/ARCHITECTURE.md,sha256=4V7yFXV3UJSfxQOLg2YsWo0Np9zfPPimThakVfl0UCM,27919
85
+ dw/docs/ARCHITECTURE.md,sha256=RFIW1eSQ6l25uA5QKJWDns1i8iJgGoqXxwq-PrHZzuw,35102
82
86
  dw/docs/DEPENDENCIES.md,sha256=avxinFm52qDToYi2_C0M39OTXNo1ERqxZj6t_0HIUjE,4142
83
87
  dw/docs/IP_ADAPTER.md,sha256=AAHaUIfbnOojHfT0noIeypbhdYPluR7sbZeVn5FpbjU,3730
84
- dw/docs/LORAS.md,sha256=iyvoRmFJ94cdxYPMp6_jdIRRjCVpnfN2jwr2iQJPq6c,3605
85
- dw/docs/MCP.md,sha256=5tQ62lA1RjfJ5a68Z2DshTUofXLsejo20etr98DZ6Yk,54875
88
+ dw/docs/LORAS.md,sha256=lwug-7yQp7O1AHJfzv5jzvH8Vta4KMAt5G8m6khyMH8,6895
89
+ dw/docs/MCP.md,sha256=7xnNsSBCK3ge6ceOVN6pgWyQHcdwSF2ei3A7V5XzTtQ,56009
86
90
  dw/docs/PROMPT_WEIGHTING.md,sha256=Pvr25d3yvS8SlnYwX9qc61VvTa8yFMxK_1zMLvrEigI,3031
87
91
  dw/docs/QUANTIZATION.md,sha256=NZCL-09bDM-JhzV1WqK2JGkL1la8VoH9fie1X39arsE,7678
88
92
  dw/docs/RECIPES_24GB.md,sha256=j7CCtMCNg830o6xD7C1DPz7dXRHvBQkbJaViRnH8AR4,16035
89
- dw/docs/RELEASING.md,sha256=ezzIqqjjXKhjgumIUQFtXteR3qdMv6UDibo97Qk12zI,31352
93
+ dw/docs/RELEASING.md,sha256=Ft0BH0ZGpsyqBYd7Ev_jCK61fiWtvCfpZUokF1Y0tXY,38520
90
94
  dw/docs/REMOTE.md,sha256=1TVGxTbLjIg5RpkoxpASSncZW_E7_llDu6zPLarkDbg,6389
91
- dw/docs/SECURITY.md,sha256=iaa8k_iQ-_fdS2ErguhHuU2fCPlOQ2UsweSV6DbK0iA,17728
95
+ dw/docs/SECURITY.md,sha256=HYkBnAGlX83moyCryHylYdyWFodyZzzF7J38elebYGA,17900
92
96
  dw/docs/SECURITY_QUICKREF.md,sha256=-xZNIV6j1oWcoy5B-oHKqh3ko2zJgB2fuNMiDV4f1zY,3537
93
- dw/docs/SERVER.md,sha256=HJOXiRsxpvwzYhxYDmL-PZjTllwjjbI8rfSAGQEE-3s,49903
97
+ dw/docs/SERVER.md,sha256=XAMoVdlCAjTR0AMtupWv5nuDUGClEz31YBfaOObSBlc,52418
94
98
  dw/docs/TASKS.md,sha256=7oMxuz6xLzwTfKn0nsD0uJoxUsUMctFNb84RSS5n0g4,108352
95
99
  dw/docs/TESTING.md,sha256=D4zmQp0iVmREM9J1tq4RxTmmIxvxsp5dRtuRGovP96s,3973
96
100
  dw/docs/WORKER_GUIDE.md,sha256=FqzXVuH91XtonpBeXj_7WhMVz5JiB4Rqu2lnGBHchE4,2065
97
- dw/docs/WORKFLOW_GUIDE.md,sha256=vkgsB0j5RzDyWSPu3PJEvLvXmp-3mmDqWY9mZypMWU4,108940
98
- dw/docs/WORKSPACES.md,sha256=vLzMxioNHkqexKj_41OPTrN84N6A1s6p6gR9gCcaY9k,16181
101
+ dw/docs/WORKFLOW_GUIDE.md,sha256=wYysOYI7BGOxWK-ZjvEwi-vTzzcOZUvWcakx5ibzGNI,119679
102
+ dw/docs/WORKSPACES.md,sha256=lQLM4Fxit_owpYMzJ0wk3sHWicXyajkQ_UOg-Vw6fec,16469
99
103
  dw/pipeline_processors/adapters.py,sha256=HIDYa20vWTuD4XK8q4rntr9zZAHgbxkIPPQqeUVa0oQ,6638
100
104
  dw/pipeline_processors/chain.py,sha256=73MovwXQjwcDg3KQ6Fwpnk9tk5YMN_JhwQsMsuHVCF0,31565
101
105
  dw/pipeline_processors/components.py,sha256=6pwfAbzzWAlGMloVmYSDbeF5IeYQxSte-4G4mSs0uDs,35489
@@ -105,34 +109,37 @@ dw/pipeline_processors/placement.py,sha256=D-7ZMNs2P8t81CTtwc_APVrlk_8bz7Ek0M-Hb
105
109
  dw/pipeline_processors/progress.py,sha256=uSKPsMug1AZqDoaFXsF5sRcJNiNLzbBuX3C3H3xVzms,9196
106
110
  dw/pipeline_processors/remote.py,sha256=gvq6oOUASxx3WlEKRPSKMR72F7jeZrPii_tA15xdits,1651
107
111
  dw/server/__init__.py,sha256=NGXV8LM6oYUZhEwWSDo3ihBvmzrC71az3Wc2gkGodcM,153
108
- dw/server/admission.py,sha256=Nu9tqTKlr6IFtVr1slI7mpeygLXSlRnprRmaTpvxB4s,18072
109
- dw/server/app.py,sha256=PQejjfF5d0Dr3Ousne5-8XZqePGBufpCRqL-E19Tkvg,9352
110
- dw/server/assess.py,sha256=2mPf68FTgkCkxeFqNd6WMrhAQhBeDSCaZyJglqKkLwg,4757
112
+ dw/server/admission.py,sha256=ukLFqbWJCOF5IAiL4HMdV2cT3EHIZvX8-kk_LahWNzw,18974
113
+ dw/server/api_models.py,sha256=-Xa7qhZHaADcyMON2OdsA_kb084QQQYmIf63e9AZqnU,23460
114
+ dw/server/app.py,sha256=bk8rif_x44cs2fAOI8Xtqag4q0af_YRlEO4X1DQoTHY,10328
115
+ dw/server/assess.py,sha256=IkRMk8lth8G8rSYlA9OHWJS4jO5QMOYjqBevbQWAHto,6700
111
116
  dw/server/catalog.py,sha256=B3uR6G_hADm3nKh9RPf5H5IevIkiVXSgExdAbPCU1X8,17998
112
117
  dw/server/catalog_shape.py,sha256=CCfjpLgHpALB9DMir_4KmT3AMvh2XUkecllxZvIFqe4,17929
113
- dw/server/deps.py,sha256=BChMhuVcPl0HpZawho_KxwlgjyPHlZPi3pYxPaZ_WtM,7447
118
+ dw/server/deps.py,sha256=3mBRvKPPjySOa8iuDUPuW27SEkCL5HdQLhBGlpag41g,8100
114
119
  dw/server/enhancers.py,sha256=YLGpxqIA8P3svidumfE4s5opTvbU12RqHdyuW5U27Bw,4696
115
120
  dw/server/exports.py,sha256=25RvcK7W_50LMI5xv86vyCpRz4yunmbZaDQJX4ldz5c,16410
116
- dw/server/guides.py,sha256=FhgNGR1Jkr4vwTXSCu-1Dt26Kiw4NzyndZnQ06jsUOc,11986
121
+ dw/server/guides.py,sha256=fxXbvnFqA8GUzeVbpEpEpg8FstGH6VItevC0n4H93iQ,11986
117
122
  dw/server/http_security.py,sha256=_WptoXRHBXEeyugBoy9sw-r4DHYIWfm-Z3l7GSf_bd8,8827
123
+ dw/server/inline_media.py,sha256=SxCOSLrF7kIthZe_W4DMsdGjFR1UK7Rjeh-wELXEQ5s,4590
118
124
  dw/server/job_history.py,sha256=bW-wFa_X7zqEOioE1kJij89j7ujjmeO2De3z97x45i8,20170
119
125
  dw/server/job_record.py,sha256=WKyjvSSkl8H1L1IT_0T-XwwuFsDeODOvqovtFwwXCDg,12821
120
- dw/server/jobs.py,sha256=mqU_IOD5meDWZmakgdt11-u1QtGyg-KYl7Pz-oLLh6w,38925
126
+ dw/server/jobs.py,sha256=-4NKL-iyo6yW9watGtVRGPALruNg6ulRsHSuPxIoytI,39521
121
127
  dw/server/mcp_mount.py,sha256=XIjfqBzELFKesfHVmdFj69RHSTzr7aF4Ph1Bfz4oPeE,3620
122
128
  dw/server/netinfo.py,sha256=_oo0NfnesQR0n8MlxGt15tTgLutaqNOYyYYuUIBdRB0,4941
123
129
  dw/server/observed_cost.py,sha256=Tq4aepqZoAl_tmVVLVI2NY63_FkPMEdPZ3fL7MfLUQQ,15970
124
- dw/server/outputs.py,sha256=TeUDfXJR3L7utg8U4Y3MQAT_SdEvaCXlQBHSF5qnkMA,16909
130
+ dw/server/outputs.py,sha256=q7jLKuRDnUhIIKGT8EvHlkHFucDtzfIJz4ZZrzXibH8,19060
125
131
  dw/server/sysinfo.py,sha256=WiQeSpMNiIDOadcpYiyYTQSPQgPZc7qPvLSXx2WQHLA,2221
126
132
  dw/server/updater.py,sha256=RYFcjd-oFcZxGC20veMPXpazRdN2JLRRsFAL6ON54d8,7191
127
- dw/server/routes/__init__.py,sha256=okLA6aqxG3a-4oqtQoyuCE13uCZpy86kvADLv6RIY8U,1918
128
- dw/server/routes/assets.py,sha256=qullyjjgmgLJTNQujN-rVphvZdYPj1QsQd8Q9G__P7U,17137
129
- dw/server/routes/files.py,sha256=lcRB3QnqzVpFZvtLIUvv8BienYO1QnkFG2kzCVvZwLA,7128
130
- dw/server/routes/gallery.py,sha256=D5hYSetsf7jYWe3zu_MUxkacLcVHr3O3aqqX5lNNSA4,15667
131
- dw/server/routes/jobs.py,sha256=GQ8OjhbaZWuanj9PZK_5wjatc7VyzelrG6p-cncqU2o,31505
132
- dw/server/routes/library.py,sha256=sRFjSjGwb3F4jvGIXXeKJ_zldpNdVD05hDMN8lD21gQ,26785
133
- dw/server/routes/media.py,sha256=GE0R2iqQ6lkSpWc1ika-lcIMfxT7KAo4XS4IKTjKrXU,22763
134
- dw/server/routes/system.py,sha256=wp1DbpM7UBWfOtn6IK9oOHNA9e4QPfT0_jdMa1q-DNs,15655
135
- dw/server/ui/index.html,sha256=EanLGs4hgbPQmr_y-3831SbDC56jcswl8Pf0BKDWQFE,826
133
+ dw/server/routes/__init__.py,sha256=Z6hnzGs1jdXuY_1C74t09_e1QDYWOxWbCnyjo6_qKB0,1943
134
+ dw/server/routes/assets.py,sha256=D3VSCSo_xKJeBZ-5ZMWWRtMlr1db7iiDPDFIUAPg8_I,17517
135
+ dw/server/routes/files.py,sha256=6c7ySIPe7o8HSc8Z7M2b1fKWonQdkC8S_TPAVppCxOo,7125
136
+ dw/server/routes/gallery.py,sha256=pwE1qsizXpqL-kMieM6UbXAgAHOpdQ1V3MR53510PsU,15107
137
+ dw/server/routes/jobs.py,sha256=gb1bUHepdDxMzJaFYnI7a5dUy0ZFR0WLhzaQuUcUtps,34308
138
+ dw/server/routes/library.py,sha256=GiUFqYuin8nHx1pU28gJsr8m6YvgBNAWoUZjUbT9PYM,29738
139
+ dw/server/routes/loras.py,sha256=OVxlXutJs1ThSsTC3R31pg44sUaV9iH8PhY0Xy9UyVQ,9289
140
+ dw/server/routes/media.py,sha256=vRhH52iZ8BwmPeNtN0wS_zM6A3qj92p2V8E2DwIifN8,26005
141
+ dw/server/routes/system.py,sha256=FgT_kMuITUHP8kUcv-3AWK_2nl_bpny3Qv6CaHq8Ab4,17170
142
+ dw/server/ui/index.html,sha256=Bc_7RXdWZrJjBHLiX4Cv7k2nljSYxbiFFp7g2dI6XJY,826
136
143
  dw/server/ui/assets/abap-08VXUWAP.js,sha256=v_s2iGszAEBUjgmnxo-oLx1BQTQAjswxiNzZ24fNZ3o,11690
137
144
  dw/server/ui/assets/apex-BWPQTe0t.js,sha256=eUu2JicJ0pjmMYETgWVVuzFEJeyxEfievljL436Mt3Q,3469
138
145
  dw/server/ui/assets/azcli-Bc_sGQ0U.js,sha256=LDRk2Ih2wJsTBkEl5yiESmbLMeMCGuNGu5aDZxaZzRA,707
@@ -147,45 +154,45 @@ dw/server/ui/assets/csharp-BKxtCVv1.js,sha256=tcK0xVr_gQziNy8CVDw-kMQEwehIe9ND34
147
154
  dw/server/ui/assets/csp-bTuwJoIa.js,sha256=pUYDwODPsXKr4shrxhfRg0_WRY3TLT8f5omX7nYPw7Y,1278
148
155
  dw/server/ui/assets/css-DIMkf-bt.js,sha256=Nhs17Txzlhf5DumZtrz-bnBHwdMMUt9YQBxQSG9f2OQ,4361
149
156
  dw/server/ui/assets/css.worker-B3ciXF_0.js,sha256=jLdCIshnrz3ctEpiWtKJNf9w21WMelZDM8zmm0iefQQ,1074885
150
- dw/server/ui/assets/cssMode-DQI1FUIr.js,sha256=A2wHNTZoRwb73LnNsSw7Ry3juh47wKywU4nPoWakcTM,2952
157
+ dw/server/ui/assets/cssMode-C1mrKegs.js,sha256=S4zeyshUpCBXVufh4EZTO5-m7hBYRBA9r_p4L4pKJZ8,2952
151
158
  dw/server/ui/assets/cypher-CVaqCwHa.js,sha256=AYGtVhyMHJdRbOwpGLEfAPAyHAdwXc3J0D_mjN4oLVg,3048
152
159
  dw/server/ui/assets/dart-onAF5SnQ.js,sha256=QWSf47NMFu2yUd9XFSGEuisDrfcp-gvscx9WznuMY2w,3931
153
160
  dw/server/ui/assets/dockerfile-DZFCIeNp.js,sha256=hIFKl4QSK6zsn49CP3KacmKpiovwWnTZleepql5VAHo,1728
154
161
  dw/server/ui/assets/ecl-D05T4iGw.js,sha256=8dy8B-9clhaDibzPszzXjx7c9Zj0t2pUw19rgIOlAkM,4623
155
162
  dw/server/ui/assets/editor-jjEx9u7D.css,sha256=_dx8DZIGYqrSRp3hzX8InPqLbXi0KhgcLcmjFs4irOk,79503
156
- dw/server/ui/assets/editor.api-a3j9A86u.js,sha256=RsKBKw3eoL42bu43tRNe6HSy2TyufaLrPZFL-6iSOT0,2654127
163
+ dw/server/ui/assets/editor.api-EZbUgQvM.js,sha256=OzjhwqfhMZB0aozTMFY7bl0piAWT5JVTgIBzikFWtOo,2654127
157
164
  dw/server/ui/assets/editor.worker-q-txB4vs.js,sha256=--zE19Q9FbnLa1zNtUTy3y5oghXcyHADfB2cwmvmifo,300378
158
165
  dw/server/ui/assets/elixir-6RTg0lbw.js,sha256=_AM20WhJvweAHmfSKZJwEaIeLg71t8jkSUJgRVz5P0w,10116
159
166
  dw/server/ui/assets/flow9-C5_-GSwl.js,sha256=kUYiOodGRTZ6qJ5xielY8Ku5yBXlsEOb9kxSY4Fajb0,1669
160
- dw/server/ui/assets/freemarker2-BcdiHyGC.js,sha256=qozlU23EEw9T0PdWUAD2N2wf5de5RcFexeAE3qbPe7M,15548
167
+ dw/server/ui/assets/freemarker2-Dth1K2Vy.js,sha256=gwYups44AdEWlXKyXCQrHLYyvdu4NPonR6oyr8Xy08M,15548
161
168
  dw/server/ui/assets/fsharp-C8Ef5oNN.js,sha256=UTeoJ7rvyxEcL_h0e74Hkkyfnqjz1KegentufCX2nkU,2651
162
169
  dw/server/ui/assets/go-C-y9NEjX.js,sha256=yiNuAvOl-CJdg1l7tlsDbqjKrl95VJ6jchO7KXm8sIU,2350
163
170
  dw/server/ui/assets/graphql-fmXr3nnJ.js,sha256=pm47jqz4rUAXQDgl98x5ePvvxf0fgOpsBE-AWYSMUYY,2119
164
- dw/server/ui/assets/handlebars-DCj-aPE8.js,sha256=PEMrgVUSvCBwHFrRBAAFkak7AdhZBHYdts21E4iTJjQ,6284
171
+ dw/server/ui/assets/handlebars-8Sswqnxq.js,sha256=IuehxKA0j2ayr9OQr1vUMpykPL8xLadLO6imjpArZkA,6284
165
172
  dw/server/ui/assets/hcl-CpzslTdj.js,sha256=FTELtvUdJnCIa6x3jYwjNRaXvSqDk7_x4SlTYehMmdI,3449
166
- dw/server/ui/assets/html-D8xomw9g.js,sha256=-QgOxSR-AGwp5wVCH-rI-Lay--xQk33fJz1ulAdkaBU,4516
173
+ dw/server/ui/assets/html-BYtYo7f1.js,sha256=6YtXiKIDFeyFWXOgspYWsEenodtIHrqzGzKozU6GJyI,4516
167
174
  dw/server/ui/assets/html.worker-C93Ht9o9.js,sha256=8peg8haNK5qh51eN0fJ5PyFESQPNNUoyaGlSzaIa7l4,739943
168
- dw/server/ui/assets/htmlMode-DK_n-eew.js,sha256=SSBF372xpu2fUKKjyAaxyENIf6feA1ApKUZnLONH4Ik,3406
169
- dw/server/ui/assets/index-3Vw6WAPW.css,sha256=pbXkt_MDKZH1CVgAn-RbKW4Oxxcb9uJskXQxmFn0gRU,73445
170
- dw/server/ui/assets/index-CNiY-pOw.js,sha256=uh0tCfQ8G3aTsaWsbbAIpeGVZF3aRBf8UjnVcsBF9As,320000
175
+ dw/server/ui/assets/htmlMode-B_AiWoXc.js,sha256=_R6Ea_FCoX_CNqe0knVs5u-9Fu3E_i7wW_BJHXKclD4,3406
176
+ dw/server/ui/assets/index-B6Ujrvuj.js,sha256=Q1SP440ZAabyS0SUL439mGnugsVv69GfaSpuFrtwdyU,442838
177
+ dw/server/ui/assets/index-BChhQc7I.css,sha256=gldLQiGkc97e9SUhd3yrR0gZV4yz4gcC1PVjB_zFWxc,73184
171
178
  dw/server/ui/assets/ini-sBoK_t0W.js,sha256=6QF6Fp68pxwu26PuYuAa5XlpwDMMopXB8gHj4XgppU4,960
172
179
  dw/server/ui/assets/java-BEtHBSE6.js,sha256=d9OpHur1TgBPjsMh5iCK_s6-JDUjIUa0H2gTU3OACVM,2906
173
- dw/server/ui/assets/javascript-SmmG4uTF.js,sha256=3SlYQs3YIKgNDd6eB-Cz7Whkmy5OBGfw2iFaq9k8EPw,688
180
+ dw/server/ui/assets/javascript-E4m083D3.js,sha256=GScOmM4Htv2gVfpG5lmKwP-Yv6M8aL8x1uFnk0EJVOE,688
174
181
  dw/server/ui/assets/json.worker-B2V3pomh.js,sha256=4L2BlNu1xxbbzYuRRF1xDkui9bTCbXusXbJlZ5XonDc,429596
175
- dw/server/ui/assets/jsonMode-BRyslvRu.js,sha256=hXohnL7qgYQMJwY_vnxhbywiR6TFLHn13hsDabrwUYw,12181
182
+ dw/server/ui/assets/jsonMode--h7ZikWy.js,sha256=xuxa8ZLP0kGSopcBsdJT5nYMzxjk0-Oimiw9f9qr2vQ,12181
176
183
  dw/server/ui/assets/julia-Bri6UV-V.js,sha256=GgHfKwkibx83YYASauJxey9COaeCnDC0-FO9DI5h1ww,6505
177
184
  dw/server/ui/assets/kotlin-BOotOW0E.js,sha256=y9kKjKTUCkkgIf0XZrn0aW0M28yZaabvrArNjMhi9kM,3041
178
185
  dw/server/ui/assets/less-B9JPFI3C.js,sha256=RK-lDgNqYLUdnolGcFtj5W5Nhdj2rhAQjegLMStkLbw,3749
179
186
  dw/server/ui/assets/lexon-CfSJPG6W.js,sha256=3wceYal1Tl_3oIKlurT29e46CCwlH0DYXRxHyki6aAc,2288
180
- dw/server/ui/assets/liquid-CC4C0BTL.js,sha256=agSGgoEzvqoKEeGODvVGGJo7u4qD6CCgKYkS2PAo_sk,3344
181
- dw/server/ui/assets/lspLanguageFeatures-Cmg2_33_.js,sha256=L9mxYGbq1WwYhjIDuRsYbTvvqsgc-rj67US98g-DHOQ,28232
187
+ dw/server/ui/assets/liquid-BzbKdLRW.js,sha256=tKj_p9dW1vCvU67jxBKvItTWOUZDRQnTmcSRe6ZbdG0,3344
188
+ dw/server/ui/assets/lspLanguageFeatures-CRa0bRFV.js,sha256=7H4Kq4XFYeKQslatTKtr4YqzDmmEWVfnyP3XWsGcc6g,28232
182
189
  dw/server/ui/assets/lua-CsQS60Ue.js,sha256=T68zBfv8YbWQOUMOoKDHlS6ZLXQbvUoVzIqjfdKaN80,1982
183
190
  dw/server/ui/assets/m3-D-oSqn_W.js,sha256=wiQpsc-ejuU-Nd_N1EEku70GvFxCKR2enx_4FMaLERU,2520
184
191
  dw/server/ui/assets/markdown-Cimd5fb3.js,sha256=Yh5RI0xP6paio6bg3VkVHxwCFtfLSpYzYe4pqjAseXc,3639
185
- dw/server/ui/assets/mdx-DTAejllH.js,sha256=cJX-YM8pCL5togr7f8hgixQ7pHcWMISA2iNjGpATkp8,4319
192
+ dw/server/ui/assets/mdx-BJ4u6XQs.js,sha256=eR2MfMuZQUgcWxcamYaVV5jpt5s5di0MFEueS5VLL7c,4319
186
193
  dw/server/ui/assets/mips-CIPQ_RoX.js,sha256=Mf9nhH4UiNv4cOxx9GbzZEwcanALyeX1nqZyeDVwn-8,2325
187
194
  dw/server/ui/assets/monaco--ixms01u.css,sha256=kpYA88tuYJq8DuCa0gtgkNNGbd7cIKcfHgzkZ6FFLYQ,82320
188
- dw/server/ui/assets/monaco-C_Um4bRZ.js,sha256=RuMFxJkZy6eOIYI7vsIrKq-4z2c5p5hpF_MVCZreD2E,1268717
195
+ dw/server/ui/assets/monaco-DwaeaVri.js,sha256=vFE32xYhQCKSuvgcjgNIqkBLD1IUVNtoq_HJGukdO_A,1268766
189
196
  dw/server/ui/assets/msdax-DauUninz.js,sha256=x-Ec1FvZQfNyIBufG3aF-nbhjtWWCb4trNEl2w7mORU,4270
190
197
  dw/server/ui/assets/mysql-SOo6toE5.js,sha256=s0175vipA9oId7yWxl-u4jDQp6cAD1LlzIlQ94knUzE,9659
191
198
  dw/server/ui/assets/objective-c-FvmIjYaQ.js,sha256=-06rJpDcN7p7YZ4HQ2hFDtAr48MLT-x4ITThLRR0pXM,2102
@@ -200,10 +207,10 @@ dw/server/ui/assets/powerquery-D3hlyOfw.js,sha256=h7-yZyeDYpf8Vz7I-o-AdOXL673EDo
200
207
  dw/server/ui/assets/powershell-DmHpPYUd.js,sha256=fS-k4myYtbJ7I-nT4AOE2xWBU6BC4yBTsO8utRI2kYA,3057
201
208
  dw/server/ui/assets/protobuf-C531GsRP.js,sha256=CE2QZMYH5tuK5qacJhFCN5Egq0ldACCn8ZMy7drCA_A,8897
202
209
  dw/server/ui/assets/pug-Z5eAx3Zn.js,sha256=3W_Q5pw42PShvXTeZmdid5YpzS29ZEKItG3NbMZkZIY,4468
203
- dw/server/ui/assets/python-DKASw3vF.js,sha256=piJSqdq83487-cb-zHJFzA5_XBBzxSLgOnIdaBhqBzI,3455
210
+ dw/server/ui/assets/python-CoX_gCAL.js,sha256=Z3WL5BXQv2zqDkbVtvOHUChbXpD7-4_MHway2GuNR8U,3455
204
211
  dw/server/ui/assets/qsharp-DkqhCAOL.js,sha256=72cTeKiuU6qRxzI9j4KVb-r2y5u7Yj9O-DppqJMrsw8,2722
205
212
  dw/server/ui/assets/r-BwWrilGY.js,sha256=kjvwR-197La6WrPfRntvc5VS4GcVs7SVUIcq5brgDh4,2836
206
- dw/server/ui/assets/razor-CkEOBTMa.js,sha256=a8NFMdXFXnyfX8pZiFuUoS-jodGQR6c1lbIHTKJ6lnE,8113
213
+ dw/server/ui/assets/razor-BCTdG5SN.js,sha256=HNy3avXpiAcZombpRKcsY-AnIyVbebnhibgDNT1Zda4,8113
207
214
  dw/server/ui/assets/redis-ClamHrr6.js,sha256=P6KIG5bJRWvmyPzG14QO5RZJlmj49pzn-p4hDqSFQ5M,3032
208
215
  dw/server/ui/assets/redshift-DT7zqm-g.js,sha256=PmLS8mPeeCIWu-NLw1SMU7nZp94WvW7aqKAG7TbJv3c,10331
209
216
  dw/server/ui/assets/restructuredtext-BYgofb2h.js,sha256=UmiK7-mgglvXYqrOt4NCdx4oKNNoHilj1XfmVkRw7mA,3744
@@ -223,19 +230,19 @@ dw/server/ui/assets/swift-Bxkupp3x.js,sha256=PAoUaoj9w0C1Q8tOfBsDefytIxzaJLYxXo8
223
230
  dw/server/ui/assets/systemverilog-Bz4Y3fRF.js,sha256=N8BJdmDPdAS3YSLf9-c6WjpeHiC8AUiPFC0b83QRu84,6850
224
231
  dw/server/ui/assets/tcl-DISqw1ZD.js,sha256=tGDwrjRxtiwzHBQVX4aYHPx2tvnzyCbsk3MouRN8nGI,3271
225
232
  dw/server/ui/assets/ts.worker-D7T1-Ig5.js,sha256=l5VlUGJBtGJhrRtzAlbC7iInUtA13foqlGA2sWIgvzE,6913951
226
- dw/server/ui/assets/tsMode-CmkUIEUu.js,sha256=G-Rdd3Pz9IIIn_ecoTw5eIV9jVW141UHVILkOjusV14,21859
233
+ dw/server/ui/assets/tsMode-B6BV7a76.js,sha256=sBOC_QcREHk51TXu3xiwUOkIij-Jx30rGNJrspaA2gw,21859
227
234
  dw/server/ui/assets/twig-De2hgUGE.js,sha256=7UK-mZY0t2AOG2upJFdhUfk_hN4jQxNO37xW_pXsYRk,5781
228
- dw/server/ui/assets/typescript-BXTFUpwg.js,sha256=4pFMxpJItukf8bJ-qMGGbdaZmPE6gs_YRbcuCR2WWnE,4675
235
+ dw/server/ui/assets/typescript-DJe7-fvZ.js,sha256=-98JUuKvr5kDlN3aRBK9dm7t2uTCQpvuCp67uVpgGqY,4675
229
236
  dw/server/ui/assets/typespec-B8J7ngcE.js,sha256=4SiWGtYCn-n7DAFoQw3hFbXpXOEzUIVgPrFnMxeDL0A,2625
230
237
  dw/server/ui/assets/vb-DV3o63ZY.js,sha256=g6FxShoSupLTGxKrGHUt31pO6FoCrY9npMMQpnSqtsM,5300
231
238
  dw/server/ui/assets/wgsl-DpFanUEy.js,sha256=M1uSecn4lmt1G3mQyTCdxT4mfHC4g3AjJAw7cuUwAg4,7182
232
- dw/server/ui/assets/workers-Cpj1l6gK.js,sha256=YoHH6CeZBBJujlasBbVkmz-h0KySowp5sl4E6dhT9TA,1249
233
- dw/server/ui/assets/xml-D1BkO5yz.js,sha256=o6pqdq7J2AjOb0TrfjItNHHFuBXQjjp4RSoM7LS3OTE,1923
234
- dw/server/ui/assets/yaml-CDFThBDz.js,sha256=jhdFCMqN8A7vibDKJzy9i6jmrn0p1irIaI-Cad_AE1k,3543
239
+ dw/server/ui/assets/workers-DCzLJTPE.js,sha256=Asegmw33GBn_tM8pJ0xANjeYHpjhh2lWRD9_dtJOJTA,1249
240
+ dw/server/ui/assets/xml-CNvWfUrB.js,sha256=fu34pK4bFO03u6jfIchwHDnWW0lWwKYbP0L3Ekg82zA,1923
241
+ dw/server/ui/assets/yaml-ByARP6WE.js,sha256=YxAgEUmK5V3EgTIXnadqBwwkALj1lgBcCxiQQqthTw4,3543
235
242
  dw/tasks/assess.py,sha256=fQgj8Q8-Sf6CWXCWIB_sKS6C9RIDembzP378yy4VKd8,31765
236
243
  dw/tasks/audio_dynamics.py,sha256=-dhNkBM3CkWGLbbd5fUExbWCb4FyLJp3mYkqIO4OeIg,18060
237
244
  dw/tasks/audio_transcription.py,sha256=RNyrnz6irSzz6pY4H5pyEn3gwRLHOawUGI-GGbLeU4w,5523
238
- dw/tasks/audio_utils.py,sha256=ibXZoQkhzX3mISNq3vXu8aOZnp0RBcgJP8PGYCrVi_o,38192
245
+ dw/tasks/audio_utils.py,sha256=McWg3Vteli2IiWLw68chyCGCoqz8u7VrVISry25Bmos,38563
239
246
  dw/tasks/background_remover.py,sha256=lwRMBo1VALLVWwUQUOs-5EWtAvOKZOlrVwoAr6jrStQ,1205
240
247
  dw/tasks/borders.py,sha256=ZFnvODeLnF4nMMogOAZKEKHPMM7qebW1A4GaZFyDKmI,4253
241
248
  dw/tasks/compose_text.py,sha256=7N-9ti5XfhwECZIXzx7IgTbmm2Kt8GmcR8yK5mbEXEY,3127
@@ -246,13 +253,15 @@ dw/tasks/dissolve_videos.py,sha256=aGsKRskW34O9adU9oUJ_zJjEJyruf83S5bbOVnjEZws,1
246
253
  dw/tasks/format_messages.py,sha256=LHEFWaIS0GsL0Dm7KGG_MfwlKO9gB62zWf3egxxDZwE,630
247
254
  dw/tasks/gather.py,sha256=C0pYhr7EWZibDm8gOzjAVZARV1Gu7heHhfGuZIdq6oM,5933
248
255
  dw/tasks/grade.py,sha256=QVVaENcgvABJdaS5kAoH5SUhdJ3PEsaQvbRSn5dZlZw,3808
256
+ dw/tasks/h3_latent_upscale.py,sha256=Q4gKKVhr8hNLOQaHEl7Y-R2IMqbaEiAQo47yrgF6FYU,13010
257
+ dw/tasks/h3_latent_upscaler_model.py,sha256=U-W9BXhDiy2ocv7TajxPsbNGmN2a9ymryjuiwP2LlGE,10440
249
258
  dw/tasks/image_to_text.py,sha256=iNza67G5h24y6GIs22mCyLOFgqsAOfz9hf88jBn16iY,1616
250
259
  dw/tasks/image_utils.py,sha256=4mAHIob7Yh8JEdekI5X5yI_dJSKia1PTrRDGjljAOfc,25397
251
260
  dw/tasks/interpolate_frames.py,sha256=Jxp0GcETheu1SBwAP6QrCCRKRs9XfoF5SHzwfUkIwCk,9272
252
261
  dw/tasks/join_into_song.py,sha256=54nr2-Q5MOUV4rTtBeWyJV-oK1misJ86LV2eRRV_BTo,17825
253
262
  dw/tasks/joins.py,sha256=5Mc6DFItML_asJQexSmcGalL66bPb4qIvcqtVIivFSw,25386
254
263
  dw/tasks/judge.py,sha256=fdT6a20x66tCCP37d2NnVFrZAPiuhduuBvg_bsAdtSg,2312
255
- dw/tasks/loop_bed.py,sha256=GqFE2PpHNEryQK4OdJO-x30ztIFSY6KlfhRkL5pxHtg,35139
264
+ dw/tasks/loop_bed.py,sha256=JQ-Zx8qpNiobBtdmRPU4nwYiLJyrje6hAsT8QauXkz0,35563
256
265
  dw/tasks/model_cache.py,sha256=Bh97x5mFFFzT8M8_LiHo0a1izsaIqvsQyIURPkjKxTk,1879
257
266
  dw/tasks/pair_audio.py,sha256=-FxrSzXJoK2nVO7kjL-lZgpmBgNDbUb9awDDfoNrlHk,17178
258
267
  dw/tasks/qr_code.py,sha256=xyckWTixcMYasJPI5N7-co4jmyHwfScGWD2D1RbFzuM,548
@@ -262,7 +271,7 @@ dw/tasks/segment.py,sha256=2g-jndKDlIcVMH4OApWNlWzt-8DzQvhK82_TNMSXoTI,4267
262
271
  dw/tasks/select.py,sha256=HQlINdeyQXpVQr_9ccWvNEbGU85Gp5RbYKbCb7jvx_U,3518
263
272
  dw/tasks/speech_generation.py,sha256=_rpj5o3-KTsvmvVcFuWCBzCO2UrUbvvKfQhIQH2giaM,10754
264
273
  dw/tasks/stabilize.py,sha256=XtVCV87gmsd0Q24U4Do6CqXEt54zxe7Vg6AED6UDsNo,5018
265
- dw/tasks/task.py,sha256=kI6ixKZ0oOG7X8SY7g3OCTfYi1GqsC8L5c9mfahZg_0,34436
274
+ dw/tasks/task.py,sha256=Q-JSKZnoZenbolpfNojc4OTPhvTeRBNu1Wmp9ZMc8hQ,37479
266
275
  dw/tasks/tensor_image.py,sha256=xJDo5-Bi7drP4LqXgg_qGeEbC8q9-KA84iVJolQURhE,2083
267
276
  dw/tasks/text_generation.py,sha256=KeqXCYFTriMCigFSsm0mtF87ZUhBUCVG4DL4VznTiRI,6997
268
277
  dw/tasks/text_sections.py,sha256=0eE7O0eLQCgxEooO3-RLuQSRwmeFwHttLqwhp71q3Lw,3260
@@ -273,25 +282,27 @@ dw/tasks/zoe_depth.py,sha256=s-otGgDA_wIfawzGWhHd9eDtHBiNsNosjCUH3qIr03c,1817
273
282
  dw/workflows/h3_context_ir.json,sha256=nasb5JKFs6bkqYXuTvCyyiGAROBo8N0vDw_X-ec8SYM,13653
274
283
  dw/workflows/test.json,sha256=XFvEH7_8F8MGoX5b1j0FnT8dJghYiuyukj2q0JSEfkU,937
275
284
  dw_mcp/__init__.py,sha256=v6ezMWrVwQmdKO_ze1xrqVF10NhjdnoE-ikK-NbXaus,435
276
- dw_mcp/__main__.py,sha256=yqmbKF1AtJcc-c9Z7ykjOUG0WMee8CgXWMW4nbFzxGg,4366
277
- dw_mcp/assets.py,sha256=2tQMl0m9gXeZY-dwCHVok434pMU0_3hxlcXyV-aaSSw,18292
278
- dw_mcp/authoring.py,sha256=dNYjc1EtqlifozYRI6r1Mr92RThIAlBsOuDiiwGVmQA,6053
279
- dw_mcp/catalog.py,sha256=vZa797mrqigU-OnP5JMhPlTBuIJGcwPCcHKkryRB10A,16218
280
- dw_mcp/client.py,sha256=XhddOIQpHNbLgJ01u38fyTVG4dQS2dgD0b7T5DT_yf0,21285
281
- dw_mcp/diagnose.py,sha256=xGG_sn-bNOi1XFbXAtxayDL60ITUT3YuRqhxyfKvkGU,17557
285
+ dw_mcp/__main__.py,sha256=xiH0reOcZksZivZdK-PWD4A4HQSngiOLq4_D93wIqvg,4364
286
+ dw_mcp/assets.py,sha256=Zdh_fgOgOwa3SLyrrnktbwChuDq5zblA0T43Em07Kbc,15773
287
+ dw_mcp/authoring.py,sha256=dNqhY5JnACSgfK9g1rDIURSLupWEn2h82bqd-iy43yM,5027
288
+ dw_mcp/catalog.py,sha256=RMPqJ_Vtgoc3wFlRp0xd4GedbQVICaI0rkXwiqbvzus,15219
289
+ dw_mcp/client.py,sha256=YhIJY6Nlf2B1MbBfdcMZySsQ5PFvdEVF41dFL8MRhm4,22166
290
+ dw_mcp/confine.py,sha256=bAitZXmyoNMFkmzNa7WwzYNgKhVLT5nUsMOAGe5t-bI,2766
291
+ dw_mcp/diagnose.py,sha256=V9-8gNf1eMVjzRDilj9FiD8dcnHu5AZ9nRVm9AcXIYk,17392
282
292
  dw_mcp/exports.py,sha256=Txly4-pD_GCcKR0CxvfWAWmhbRrcbUsOcvAdO7dMTps,4137
283
293
  dw_mcp/guides.py,sha256=QDvofzCO5FOXTNO5DW82UKqDn2IdvwNEr7rB91fHmxE,1762
284
- dw_mcp/media.py,sha256=mAs-nEJiCv5P8o3lfATRD94RbS6OvfgejSzfiW2PfVo,28170
294
+ dw_mcp/loras.py,sha256=dp0fUZ9YfECYnDemJNvq62ZbvXjJJaEAEPdkRKIDVGM,875
295
+ dw_mcp/media.py,sha256=1MzdoyO9p2B1PKAm8Neu9gCSHYmECEQ_X4boMBHuTvo,20937
285
296
  dw_mcp/models.py,sha256=uzsUY-CgiaP1LZLbdLnVRVXFSK2kcXs_tNquRKM6d9w,4220
286
297
  dw_mcp/prompts.py,sha256=ZgbcATJbWUxHlebt8ssH2PlUc3nBD6rrVLdFLJSo8TM,3944
287
- dw_mcp/server.py,sha256=o__FuMpBezeeWHNB3OMyB8TURpS1jDJR5L2aW1yKn0Q,7483
288
- dw_mcp/tools_authoring.py,sha256=3he2TOvwU0Jwl0Q5CeXgcpSqBJTQ7OPXsJVotSttpMA,10824
289
- dw_mcp/tools_catalog.py,sha256=Rd0qfBVSaX1A-aucerdZ8NwjJ7gjOabGqVAeH8zu5Zc,22221
298
+ dw_mcp/server.py,sha256=dEVWxyyN5yh-lIkc4Yub3S9TwcFOV5TSYNikqyiVXXg,7738
299
+ dw_mcp/tools_authoring.py,sha256=FBelAhWf1OWRQX290rF2Eoy2fY1fpMoG5lZXytBFgpY,12313
300
+ dw_mcp/tools_catalog.py,sha256=cZf32oDGgc-VOeKT4Z8guFDSFzQwPR5HG1oTCW0TR7M,22086
290
301
  dw_mcp/tools_jobs.py,sha256=IhzItLsok4QbwztgeQw5qr3z2KcELIhb954vEOVWAj4,12112
291
- dw_mcp/tools_media.py,sha256=FgfBkpXxSpSDwNy5xqYaGzDSeuJ24OFEWZzAIbUB75I,16848
292
- dw_mcp/workspaces.py,sha256=A8RvsaNkfOWK-3wyDuHxbF4IdTBECJrwaEK4ghu3muQ,8947
293
- diffusers_workflow-0.7.0.dist-info/METADATA,sha256=BsV9ZBQpWuYMBOzuo_PKPe9Gp1dunRrI7eaQwyeZDQs,14938
294
- diffusers_workflow-0.7.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
295
- diffusers_workflow-0.7.0.dist-info/entry_points.txt,sha256=Dem_AOzV-Kcpr9AASlSvJ-S5sn3f6TQu6ABb6BbApho,148
296
- diffusers_workflow-0.7.0.dist-info/top_level.txt,sha256=o-uFAN_oUOrhXfMKO39HsMs2r19L9LykxoVKj2S9q7U,10
297
- diffusers_workflow-0.7.0.dist-info/RECORD,,
302
+ dw_mcp/tools_media.py,sha256=HsMQ5ihUmkUcZ1NELtJMNbxfpSjdfFLQA6-Q9jOhe0w,16848
303
+ dw_mcp/workspaces.py,sha256=OF6oVMQx_pkTuRMLvbOYkpVWwcA6GQwaEf5k0oxqBnI,8449
304
+ diffusers_workflow-0.8.0.dist-info/METADATA,sha256=b4SVA0uisJE416y0YSXwqIn3E2pfA8qqs1SDNTGwOr4,14938
305
+ diffusers_workflow-0.8.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
306
+ diffusers_workflow-0.8.0.dist-info/entry_points.txt,sha256=Dem_AOzV-Kcpr9AASlSvJ-S5sn3f6TQu6ABb6BbApho,148
307
+ diffusers_workflow-0.8.0.dist-info/top_level.txt,sha256=o-uFAN_oUOrhXfMKO39HsMs2r19L9LykxoVKj2S9q7U,10
308
+ diffusers_workflow-0.8.0.dist-info/RECORD,,
dw/assets.py CHANGED
@@ -121,9 +121,12 @@ def resolve_asset_reference(reference, asset_dir=None, base_dir=None, library=No
121
121
  if found:
122
122
  logger.debug(f"Resolved {reference} to {found[0]}")
123
123
  return found[0]
124
- searched = ", ".join(root.root for root in library.roots())
124
+ # Named by origin, not directory: this message reaches API and MCP
125
+ # callers, and the roots are the server's filesystem layout
126
+ searched = ", ".join(dict.fromkeys(root.origin for root in library.roots()))
125
127
  raise ValueError(
126
- f"Asset '{name}' not found in {searched} - an 'asset:' reference "
128
+ f"Asset '{name}' not found in the asset library ({searched}) - an "
129
+ f"'asset:' reference "
127
130
  f"names a file in the asset library, with its extension, like "
128
131
  f"'asset:iris.jpg' or 'asset:gyre/frame_1.jpg'"
129
132
  )
dw/docs/ARCHITECTURE.md CHANGED
@@ -49,6 +49,8 @@ one to open.
49
49
  | Reference name shape | `dw/reference_names.py`: `reference_name_errors` | The shape of every `asset:`, `prompt:` and `output:` name is checked before the queue, and existence is checked later. | `tests/test_reference_names.py::TestTheValidationPass::test_a_malformed_reference_is_refused_before_the_queue` |
50
50
  | Library reads | `dw/library.py`: `LibraryPath` | Reads go through the roots front to back, so an earlier name shadows a later one. | `tests/test_library_path.py::TestResolution::test_the_front_of_the_path_shadows_the_rest` |
51
51
  | Library writes | `dw/library.py`: `LibraryPath` | Writes go only to the front root, so saving something opened from a read-only root writes a copy. | `tests/test_library_path.py::TestConstruction::test_the_writable_root_comes_first`, `tests/test_library_sources.py::TestServer::test_saving_an_example_prompt_writes_a_copy` |
52
+ | LoRA catalog matching | `dw/lora_catalog.py`: `matches`, `workflow_bases` | An entry fits a base only by exact repo id (and H3 partition); no alias or family match. | `tests/test_lora_catalog.py::TestMatching::test_the_base_must_match_exactly` |
53
+ | Hub search | `dw/lora_hub.py`: `search_hub` | The Hub is searched only by `GET /api/loras/recommend`, never raises, and offers no pickle-only repo. | `tests/test_lora_hub.py::TestCandidates::test_a_pickle_only_repo_is_dropped`, `tests/test_lora_hub.py::TestFailure::test_a_hub_error_is_returned_not_raised` |
52
54
  | Packaged builtins | `dw/library.py`: `builtin_root`, `resolve_sub_workflow_reference` | `builtin:` names the packaged `dw/workflows/`, not the top-level `workflows/` examples. | `tests/test_sub_workflow_resolver.py::TestTheResolver::test_a_builtin_resolves_in_the_packaged_root` |
53
55
  | Sub-workflow paths | `dw/library.py`: `resolve_sub_workflow_reference`, `resolve_sub_workflow` | A sub-workflow path is confined to the root it resolves in. The search order is in the docstring of `resolve_sub_workflow`. | `tests/test_sub_workflow_resolver.py::TestTheResolver::test_a_path_escaping_its_root_is_refused` |
54
56
  | Workspace | `dw/workspace.py`: `resolve_workspace`, `set_workspace` | `--workspace` beats `DW_WORKSPACE`, which beats the setting, which beats a working directory that looks like a workspace, which beats `~/diffusers-workspace`. | `tests/test_workspace.py::TestResolution::test_a_flag_wins_over_everything`, `tests/test_workspace.py::TestResolution::test_a_bare_working_directory_falls_back_to_the_home_workspace` |
@@ -99,6 +101,7 @@ one to open.
99
101
  | Worker protocol | `dw/worker_protocol.py`: `parse_reply` | Every command and reply is a frozen dataclass that travels as a wire dict. | `tests/test_worker_messages.py::test_from_wire_inverts_to_wire`, `tests/test_worker_messages.py::test_an_unknown_reply_type_is_kept_whole_rather_than_raised` |
100
102
  | Persistent worker | `dw/worker.py`, `dw/worker_manager.py`, `dw/serve.py` | Jobs run in one spawned worker that keeps models loaded, so a change to engine code needs a server restart. | — |
101
103
  | Failed-run reporting | `dw/worker.py`, `dw/worker_protocol.py`: `Failed`, `Cancelled` | A failed or cancelled run's reply still carries the manifest of the steps that ran. | `tests/test_worker_execute.py::test_failure_carries_the_manifest_of_the_steps_that_ran`, `tests/test_worker_execute.py::test_cancellation_carries_the_manifest_too` |
104
+ | Failure path redaction | `dw/path_redaction.py`: `redact_paths`, called by `dw/worker.py` | A failed run's message and traceback name a file under the job's asset roots or output directory by its `asset:`/`output:` reference, never its absolute server path. | `tests/test_worker_execute.py::test_a_failure_names_an_asset_by_reference_not_by_server_path`, `tests/test_path_redaction.py` |
102
105
  | Run-time warnings | `dw/events.py`: `emit_warning` | A warning found at run time is emitted as an event, so it reaches the caller and not just the log. | `tests/test_concat_videos.py::TestWarningsReachTheCaller::test_the_level_spread_warning_is_emitted_as_an_event` |
103
106
 
104
107
  ## Media and DSP
@@ -140,7 +143,13 @@ one to open.
140
143
  | `dw_mcp` stays torch-free | `dw_mcp/` | `dw_mcp` reaches `dw.serve` over HTTP and imports no `dw` module, because `dw/__init__.py` pulls in torch. | `tests/test_mcp_server.py::TestStartupWeight::test_the_server_starts_without_importing_the_engine` |
141
144
  | Tool surface | `dw_mcp/server.py`, `dw_mcp/tools_*.py` | Only these modules import the MCP SDK, and each tool body is a one-line call into a handler. | `tests/test_mcp_server.py::test_the_wiring_table_covers_every_registered_tool`, `tests/test_mcp_server.py::test_the_stated_tool_count_is_the_registered_one` |
142
145
  | Surface text budget | the tool docstrings in `dw_mcp/tools_*.py`, the instructions in `dw_mcp/server.py` | The instructions and each tool description stay at or under 2,048 characters, and the whole surface stays within its token budget. | `tests/test_mcp_server.py`: `SURFACE_BUDGET`, `CLIENT_TEXT_LIMIT`; `tests/test_mcp_server.py::test_no_text_the_agent_reads_is_cut_off_by_the_client`, `tests/test_mcp_server.py::test_the_tool_surface_fits_the_budget` |
143
- | Spending needs consent | `dw_mcp/diagnose.py` | `run_workflow` and `rerun_job` refuse until `acknowledged_cost` is set. | `tests/test_mcp_diagnose.py::test_run_refuses_without_an_acknowledged_cost`, `tests/test_mcp_diagnose.py::test_rerun_refuses_without_an_acknowledged_cost` |
146
+ | Spending needs consent | each handler behind a tool that takes `acknowledged_cost` (`dw_mcp/diagnose.py`, `models.py`, `prompts.py`, `workspaces.py`) | Every tool that takes `acknowledged_cost` refuses until it is set; `delete_workspace`'s refusal is the server's 409. | `tests/test_mcp_twins.py::test_every_tool_that_takes_acknowledged_cost_refuses_without_it` |
147
+ | Copies of engine rules | the constants and word lists in `dw_mcp/` and `dw/run.py` | `dw_mcp` cannot import its owners, so each copy equals its owner; a copy that needs no twin is deleted, not pinned. | `tests/test_mcp_twins.py` |
148
+ | The CLI is a client of the server | `dw/run.py` | `dw.run` queues on `dw.serve` through `dw_mcp.client`, so `dw` imports `dw_mcp` and never the reverse. | `tests/test_mcp_server.py::TestStartupWeight::test_the_server_starts_without_importing_the_engine`, `tests/test_mcp_twins.py` |
149
+ | Inline images | `dw/server/inline_media.py` | Fitting an image to a longest side and halving it under a base64 budget happens on the server, for `/image` and `/frames` alike; `dw_mcp` forwards the size and budget and imports no Pillow. | `tests/test_server_gallery_image.py`, `tests/test_mcp_server.py::TestStartupWeight::test_the_server_starts_without_importing_the_engine` |
150
+ | Workflow patch | `dw/library.py`: `merge_patch`; `dw/server/routes/library.py`: `patch_workflow` | A merge patch is applied on the server under the lock `PUT` takes; no client reads, merges and writes back. | `tests/test_server_library_path.py::TestPatchWorkflow::test_patch_merges_onto_the_stored_definition` |
151
+ | Deleting a job's run | `dw/server/jobs.py`: `JobManager.run_location`; `dw/server/outputs.py`: `delete_run_directory` | The server resolves a job's run directory against the root the job ran in, and refuses a job still queued or running. | `tests/test_server_jobs.py::TestDeleteAJobsRun::test_a_running_job_is_409` |
152
+ | Level findings | `dw/server/assess.py`: `level_findings` | Gallery metadata reports level problems from `dw/audio_qc.py`'s thresholds; no client restates a threshold. | `tests/test_server_assess.py::TestMetadataLevelFindings::test_level_findings_read_audio_qc_thresholds` |
144
153
  | API errors | `dw_mcp/client.py` | An API failure becomes a message a person can act on, here and nowhere else. | `tests/test_mcp_client.py::test_a_400_surfaces_the_servers_detail_verbatim` |
145
154
 
146
155
  ## UI
@@ -148,3 +157,16 @@ one to open.
148
157
  | Concept | Owner | Rule | Enforced by |
149
158
  | --- | --- | --- | --- |
150
159
  | The UI reads engine fields | `ui/src/lib/plan.ts`: `describePlan`, `ui/src/lib/results.ts`: `sectionBySubfolder` | The UI reads `plan`, `version` and `subfolder` as fields the server sends and derives nothing of its own, and it never sends `acknowledged_cost`. | `ui/src/lib/plan.test.ts`, `ui/src/lib/results.test.ts` |
160
+ | Reference prefixes in the UI | `ui/src/lib/references.ts` | The only module in `ui/src` that spells a reference prefix; each equals `dw/references.py`'s. | `tests/test_ui_twins.py::test_the_ui_spells_every_reference_prefix_the_engine_does`; `prefix_literals` in `ui/scripts/arch-metrics.mjs` |
161
+ | Output kinds on the job page | `dw/server/outputs.py`: `MEDIA_KINDS`, `output_kinds` | The page renders an output by the `output_kinds` the job detail carries, never by its extension. | `tests/test_server.py::test_a_job_reports_each_output_files_media_kind`, `ui/src/lib/pages/JobPage.test.ts` |
162
+ | The editor's live reference check | `ui/src/lib/flow.ts`: `danglingReferenceDetails`, owned by `dw/previous_results.py` and `dw/for_each.py` | The editor warns as the author types, so it keeps a copy of the reference rules; one case file is run through both, the engine deciding each case. | `tests/test_ui_twins.py::test_the_engine_decides_each_shared_reference_case`, `ui/src/lib/flow.test.ts` |
163
+ | Name segments in the UI | `ui/src/lib/names.ts`: `isNameSegment` | Workspaces, folders and stored names follow `dw/security.py`'s `WORKSPACE_NAME_PATTERN` and length cap, counted in code points. | `tests/test_ui_twins.py::test_the_engine_decides_each_shared_workspace_name_case`, `ui/src/lib/names.test.ts` |
164
+ | UI copies of engine rules | the constants `tests/test_ui_twins.py` reads | A list the UI must hold equals its owner, read from the TS source; a rule tested on both sides reads one case file in `tests/fixtures/`. | `tests/test_ui_twins.py` |
165
+ | UI overlays and suggestions | `ui/src/lib/ui/`: `ConfirmDialog`, `Modal`, `Popover`, `Suggest` | Bits UI is imported only here; pages and components use the wrappers, which own focus, Escape, outside presses and scroll lock. Overlay styles and the stacking scale (`--layer-*`) live in `ui/src/app.css`. | `ui/eslint.config.js` (`no-restricted-imports`), `ui/src/lib/ui/*.test.ts`, `ui/e2e/chrome.spec.ts` |
166
+ | Escape on a page under an overlay | `ui/src/lib/ui/layers.svelte.ts`: `holdLayer`, `overlayOpen` | Every open overlay holds a layer; a page's own Escape handling acts only when none is open. | `ui/src/lib/pages/GalleryPage.test.ts` (an Escape that closes a confirm leaves the selection) |
167
+ | The editors' document | `ui/src/lib/editorShell.svelte.ts`: `DocumentEditor` | The workflow and prompt editors keep one rule each for the view (remembered per editor), the JSON draft (a failed parse pins it), dirty against the last load or save, the save path, and the tab-close guard. | `ui/src/lib/editorShell.test.ts`, `ui/src/lib/pages/PromptEditorPage.test.ts`, `ui/src/lib/pages/EditorPage.test.ts` |
168
+ | UI polling | `ui/src/lib/poll.ts`: `poll`, `sleep` | A page that refreshes on a timer starts it through `poll` and stops it with the function `poll` returns. | `ui/src/lib/poll.test.ts` |
169
+ | Workspace state in the UI | `ui/src/lib/workspaceState.svelte.ts`: `workspace` | The current workspace is one `$state`; `api.ts` reads it from here, so the request layer imports no page state. | `import_cycles` in `ui/scripts/arch-metrics.mjs` |
170
+ | The UI's response contract | `dw/server/api_models.py`: `ApiModel`, `send_rejected_responses`; `scripts/dump_openapi.py` | Every JSON route `api.ts` calls declares a response model, and `types.ts` re-exports the types generated from it (`ui/src/lib/generated/`). The payload does not change: an absent key stays absent (`response_model_exclude_unset`), a sometimes-sent key is `sometimes()`. Runtime is lenient - an undeclared key passes and a rejected response is logged and sent as built; tests, the e2e server and the dump run strict (`DW_STRICT_RESPONSES=1`). The document is generated under the FastAPI and Pydantic `constraints-openapi.txt` pins: CI installs them, and the dump refuses to write under others. | `tests/test_api_contract.py`, `tests/test_ui_twins.py::test_every_json_route_the_ui_calls_declares_its_response`, CI's "Response contract" step |
171
+ | Where `--live` appears | `ui/src/app.css` (its header) | The state colour marks machine state only, in the files `ui/scripts/design-rules.test.ts` lists. | `ui/scripts/design-rules.test.ts` |
172
+ | UI architecture ratchet | `ui/scripts/arch-metrics.mjs` | No metric rises above `docs/stabilization/ui/baseline.json`. | the `ui` job in `.github/workflows/ci.yml`; `npm run preflight` |
dw/docs/LORAS.md CHANGED
@@ -129,3 +129,69 @@ python -m dw.run workflow.json lora="other-user/other-lora"
129
129
  - [lora.json](../workflows/templates/lora.json) — Flux with realism LoRA and variables
130
130
  - [lora.json](../workflows/templates/lora.json) — SD 3.5 with yarn art style LoRA
131
131
  - [lora.json](../workflows/templates/lora.json) — A LoRA adapter on FLUX.1 dev, with the SD 3.5 variant in its description
132
+
133
+ ## LoRA catalog
134
+
135
+ The catalog records LoRAs that were tried on a base model: `proven`, `trial`,
136
+ or `rejected` with the reason. It is a library like the prompt library - the
137
+ server's own `loras/` at the workspace root (writable, shared by every
138
+ workspace), then the `loras/` an examples tree brings (read-only). One JSON
139
+ file per LoRA, under a family folder: `loras/qwen-image/voxel-style.json`.
140
+
141
+ ```json
142
+ {
143
+ "model_name": "fal/MiniMax-H3-Realism-People-LoRA",
144
+ "weight_name": "h3-realism-people-t2v-i2v-r2v.safetensors",
145
+ "revision": "<sha>",
146
+ "base_models": ["MiniMaxAI/MiniMax-H3"],
147
+ "workflow": "t2va",
148
+ "description": "Realistic people and faces",
149
+ "use_when": "People, crowds or faces should look photoreal",
150
+ "scale": { "default": 0.7, "range": [0.7, 0.7] },
151
+ "status": "proven",
152
+ "evidence": [{ "issue": 585, "note": "Best arm of the 2026-10-03 eval" }]
153
+ }
154
+ ```
155
+
156
+ `model_name`, `weight_name`, `revision` and `scale.default` drop straight into
157
+ a step's `loras` entry. `base_models` holds exact repo ids, and matching is
158
+ exact - an adapter on the wrong base usually loads and is quietly worse.
159
+ `workflow` constrains a MiniMax-H3 entry to a partition (`t2va`, `fl2va`,
160
+ `ref2va`) - a string, or a list of them for an adapter that covers several
161
+ (the turbo keyframe files are `["t2va", "fl2va"]`). `proven` and `rejected` entries need `evidence`; a rejected
162
+ entry's first note is why. The schema is `GET /api/lora-schema`.
163
+
164
+ Promotion: a trial that worked is saved with `save_lora` (or
165
+ `PUT /api/loras/{name}`) as `proven`, its job id in `evidence`.
166
+
167
+ ## Finding LoRAs on the Hub
168
+
169
+ `recommend_loras(model, query)` (`GET /api/loras/recommend`) is the only
170
+ place dw searches the Hub, and only when called. It returns the catalog's
171
+ entries for the model first, ranked against the query, then Hub adapters
172
+ whose card declares that exact base (`base_model:adapter:<repo>`), most
173
+ downloaded first. Nothing is downloaded; the weight file's header is read to
174
+ check its layout, for a single-weight repo only. Hub rows are candidates to trial, never recommendations,
175
+ and carry `warnings`:
176
+
177
+ | Warning | Meaning |
178
+ | --- | --- |
179
+ | `will_not_load` | Full-weight `.diff` keys diffusers' converters refuse |
180
+ | `unknown_format` | The tensor names match no known LoRA layout |
181
+ | `header_unreadable` | The header range read failed; format unchecked |
182
+ | `multiple_weights` | Several `.safetensors`; pick one from `weights` |
183
+ | `gated` | Needs the server's HF token to have accepted the gate |
184
+ | `no_license` | The card declares none |
185
+ | `stale` | Last changed before its base was - trained on an older revision |
186
+
187
+ A repo holding only pickle `.bin` weights is never offered. A repo the
188
+ catalog marks `rejected` comes back in `hub` as `rejected` with the reason
189
+ only when the Hub search turns it up; rejected entries are left out of
190
+ `catalog` (`list_loras` still shows them). When the
191
+ Hub is unreachable the catalog rows still come back, with `hub_error`.
192
+
193
+ Limits: the search runs the typed query plus at most 4 of its words;
194
+ `query` is capped at 200 characters and `limit` is 1-25. One Hub search runs
195
+ at a time per server, and a concurrent call gets catalog rows plus
196
+ `hub_error` saying a search is already running. An empty `hub` with
197
+ `hub_error` set means the search failed, not that no adapters exist.
dw/docs/MCP.md CHANGED
@@ -187,7 +187,7 @@ Nothing in this sequence costs GPU time.
187
187
 
188
188
  ## Tool reference
189
189
 
190
- 59 tools in six groups. Names and arguments below are transcribed from
190
+ 62 tools in six groups. Names and arguments below are transcribed from
191
191
  `dw_mcp/tools_*.py` — nothing here is renamed or reshaped for the docs.
192
192
 
193
193
  ### Catalog (read-only)
@@ -227,7 +227,7 @@ when no single workflow covers it.
227
227
  | `get_server_info()` | — | What this installation can do and where it keeps things: `device` (the accelerator a run will use), `version`, the `workspace` this session is working in and the workflow/asset/output/prompt `directories` of *that* workspace, the bind address and port, whether a token is required, and whether MCP is mounted. Check the device before authoring - a CUDA-only choice (bitsandbytes, `torch.compile`, flash attention) is not available on an `mps` or `cpu` server. `runtime` (#222) reports the Python version, torch version and the CUDA version torch was built against, the NVIDIA driver version (when `nvidia-smi` is reachable), and the installed versions of diffusers, transformers, accelerate, bitsandbytes, peft, safetensors and sentencepiece (`null` for one not installed) - for diagnosing an environment mismatch between boxes without shelling in |
228
228
  | `list_jobs(limit=20, status=None, workspace=None)` | optional `limit` (newest N), `status` (one state or a comma-separated set of `queued`, `running`, `succeeded`, `failed`, `cancelled`), `workspace` | List queued, running and recent jobs, **newest first**. Bounded by default: the unbounded listing was over a client's tool-result limit on a server with a few months of history, which made it a tool that could not be called at all. `total` says how many matched and `truncated`/`next` say so when the answer was cut - raise `limit` or narrow with `status`. Without `workspace`, a named workspace lists its own jobs and the default one lists every job the server holds |
229
229
  | `list_gallery(limit=50, subfolder=None, only_orphans=False, workspace=None, folder=None, version=None)` | `limit`, `subfolder`, `only_orphans`, `workspace`, `folder`, `version` | List generated output files, newest first. A name is `<workflow>/<run id>/<file>`, where `<file>` may sit in the subfolder the step chose (`final/episode.mp4`); each entry carries `folder` (the workflow) and `subfolder` (by convention `final` or `intermediate`, `''` when the step chose none, any path the workflow wrote otherwise), and `subfolder="final"` lists only deliverables. Each entry carries `run_id` and `version` - that run's ordinal among the workflow's runs, which is how one of several runs that wrote the same basename is named to a person: the web UI labels the same file `v5`. The number is assigned when the run opens and never renumbered, so deleting a run leaves a gap rather than sliding the rest down (a failed run, or a rerun that reused every step, leaves one too - it took a number and may have nothing to list), and it is `null` under the flat output layout, which has no runs. `folder` with `version` lists that one run's files, and `output:<folder>/v5/<file>` names one in a workflow; every other tool takes `name`. Each entry also carries a ready-made `url`, already scoped to the workspace that made it - a hand-built `/outputs/<name>` URL 404s for anything but the default workspace. `only_orphans=True` inverts the call: instead of files, it returns run directories with no media anywhere under them (`runs`, each `{name, mtime}`) - a run whose output was deleted before `delete_output` could remove it by name, or one that failed before writing anything; `subfolder` does not apply in this mode, and `name` is exactly what `delete_output` accepts (#170). `workspace` names the workspace for this one call without switching the session to it - the same pin `run_workflow` takes, so a job run into another workspace stays reachable from the session that queued it |
230
- | `get_gallery_metadata(name, envelope=False, workspace=None)` | `name`, `workspace` | Get the metadata embedded in a generated file — or, when `name` is an `asset:` reference, what an *input* asset holds (`source` says which; `job` is null for an asset). Reading an input's duration, frame count, fps and sample rate before a run is how a caller learns the `total_frames`, `fps` and `sample_rate` a workflow expects it to supply: the exact workflow and arguments that produced it, and, for audio/video, a `media` block (duration, rate, channels, fps, size, peak/mean dBFS). Only an image (PNG/JPEG/WebP) embeds `metadata` this way — it is always null for audio and video, and `next` then points at `get_job_workflow(job_id)` when `job` is known, or says a kept asset carries no provenance at all when it isn't. `envelope=true` adds `media.envelope` — `rms_dbfs` and `peak_dbfs` one entry per second — which is what locates something in a track rather than measuring the whole of it. `media.shots` is set on an output joined from shots: one `{name, start_frame, num_frames, start_sample, num_samples}` per shot, as the join measured them (see the run manifest in docs/WORKFLOW_GUIDE.md), else null. `workspace` names the workspace for this one call without switching the session to it - the same pin `run_workflow` takes, so a job run into another workspace stays reachable from the session that queued it |
230
+ | `get_gallery_metadata(name, envelope=False, workspace=None)` | `name`, `workspace` | Get the metadata embedded in a generated file — or, when `name` is an `asset:` reference, what an *input* asset holds (`source` says which; `job` is null for an asset). Reading an input's duration, frame count, fps and sample rate before a run is how a caller learns the `total_frames`, `fps` and `sample_rate` a workflow expects it to supply: the exact workflow and arguments that produced it, and, for audio/video, a `media` block (duration, rate, channels, fps, size, peak/mean dBFS) and `findings` - each level problem the server measured against `dw/audio_qc.py`'s thresholds (`full_scale`, `near_silent`), with the fix. Only an image (PNG/JPEG/WebP) embeds `metadata` this way — it is always null for audio and video, and `next` then points at `get_job_workflow(job_id)` when `job` is known, or says a kept asset carries no provenance at all when it isn't. `envelope=true` adds `media.envelope` — `rms_dbfs` and `peak_dbfs` one entry per second — which is what locates something in a track rather than measuring the whole of it. `media.shots` is set on an output joined from shots: one `{name, start_frame, num_frames, start_sample, num_samples}` per shot, as the join measured them (see the run manifest in docs/WORKFLOW_GUIDE.md), else null. `workspace` names the workspace for this one call without switching the session to it - the same pin `run_workflow` takes, so a job run into another workspace stays reachable from the session that queued it |
231
231
 
232
232
  ### Media
233
233
 
@@ -239,7 +239,7 @@ when no single workflow covers it.
239
239
  | `get_output_text(name, max_characters=20000, workspace=None)` | `name`, `max_characters`, `workspace` | Read a text output — a prompt enhancement, or any step whose result is `text/plain` or JSON. Reports the file's real length and whether it was truncated. `workspace` names the workspace for this one call without switching the session to it - the same pin `run_workflow` takes, so a job run into another workspace stays reachable from the session that queued it |
240
240
  | `assess_output(name, probe=None, detail=False, workspace=None)` | `name` (a gallery name or `asset:`), `probe`, `detail`, `workspace` | Measure a finished cut on the server, without queueing: the assessment probes (`analyze_shots`, `analyze_seams`, `analyze_sync_drift`) run in the server process over one decode of the file, beside whatever job holds the GPU. Shot boundaries are the ones its run recorded (the manifest for an output, the `keep_output` sidecar for an asset). The answer merges every applicable probe's `findings` (`{rule, severity, at, value, threshold, says}`) with `rules_applied`, `rules_skipped` and `not_applicable` (`{probe: why}` - a still, a mute file, a file with no recorded shots); `detail=true` adds each probe's full body under `probes`, and `probe=` returns that one probe's full body. `probe` is checked against the three names before anything else is read, and an unknown one is refused naming them. Findings are places to look, not verdicts: drill in with `get_output_frames(seams=[n])` / `get_output_audio(start, duration)`. See *Assessing a run's output* in docs/WORKFLOW_GUIDE.md |
241
241
  | `download_output(name, destination=None, overwrite=False, workspace=None)` | `name`, `destination`, `overwrite`, `workspace` | Save one output file to local disk, of any content type. `destination` may be a full path or a directory; `~` expands and missing parent directories are created. `overwrite=True` is required to replace a file already at the resolved path. Over the stdio `dw-mcp`, omitting `destination` saves under the output's own name in the current working directory. Over a `dw.serve --mcp` endpoint the file lands on the server confined to that workspace (a relative path is joined onto it), and `destination` is required there - an omitted one is refused rather than dropped loose in the workspace root, where nothing can find or delete it later (#353); use the `url` `list_gallery` reports, `get_output_image`/`get_output_audio`/`get_output_frames` for inline content, or `keep_output` to make it a named asset instead. Returns nothing to the conversation but where the file landed — unlike the other media tools, the point is a file on disk, not a payload in context. Writes on the machine running the MCP server - over `dw.serve --mcp` that is the GPU box. A write that fails there (a path that exists only on the client, for instance) comes back as an error naming the server-side write and the client-side alternatives, not as an anonymous tool failure. `workspace` names the workspace for this one call without switching the session to it - the same pin `run_workflow` takes, so a job run into another workspace stays reachable from the session that queued it |
242
- | `delete_output(name=None, workspace=None, job_id=None)` | exactly one of `name` / `job_id`, `workspace` | Permanently remove one generated file from the output directory, or - with `name` a `<workflow>/<run id>` run directory, or with `job_id` - a whole run. By `job_id` the run directory is read from the job record (`run_dir`) and the reply adds `job_id` and the resolved `run_dir` to the usual `name` / `deleted` / `run_swept`; a job that never wrote a run directory, or an unknown one, is an error. `workspace` names the workspace for this one call without switching the session to it - the same pin `run_workflow` takes, so a job run into another workspace stays reachable from the session that queued it; a `job_id` delete with no `workspace` goes to the workspace the job ran in |
242
+ | `delete_output(name=None, workspace=None, job_id=None)` | exactly one of `name` / `job_id`, `workspace` | Permanently remove one generated file from the output directory, or - with `name` a `<workflow>/<run id>` run directory, or with `job_id` - a whole run. By `job_id` the server reads the run directory from the job record and the root the job ran in (`DELETE /api/jobs/{id}/run`), and the reply is `job_id`, `run_dir`, `deleted` and `run_swept`; a job that never wrote a run directory, an unknown one, or one still queued or running is an error. `workspace` names the workspace for a `name` delete without switching the session to it - the same pin `run_workflow` takes, so a job run into another workspace stays reachable from the session that queued it |
243
243
 
244
244
  ### Authoring, assets and workspaces
245
245
 
@@ -272,7 +272,7 @@ tools) rather than relying on the session pin.
272
272
  | `validate_workflow(workflow=None, name=None, workspace=None, arguments=None)` | exactly one of `workflow` (inline definition) or `name` (a stored workflow, as `list_workflows` reports it), optional `workspace`, optional `arguments` | Check a workflow against the schema and against real pipeline signatures. Free and instant. Validating by name uses the workflow file's own directory as the base directory, so it sees what a run would. Returns every schema violation in `errors`, each with the JSON path it sits at, so a draft is fixed in one pass, and a `previous_result:` that names no earlier step is one of them. `warnings` covers what still runs but is probably wrong - a signature mismatch, and, for a list-driven variable, an entry key no step reads, at the entry's path. `workspace` names the workspace for this one call without switching the session to it - use it to pin a job whose `output:` or `asset:` references live in a workspace other than the session's. Pass the same `arguments` you will pass to `run_workflow` and they are checked too - an undeclared or renamed variable name, a value that will not coerce to the declared type, and an `asset:`, `prompt:` or `output:` reference that names nothing this workspace can reach, each reported at `arguments.<name>`. `checked_arguments` lists what was covered, so a `valid: true` about the stored defaults cannot be mistaken for one about your values. A reference set the model would refuse - too many images, videos or audio clips, or, for MiniMax-H3, audio as the only reference - is an error here too, rather than a failure minutes into a run you acknowledged. `run_workflow` makes the same check and refuses a bad argument rather than queuing a job that fails on its first step. A valid answer carries `plan` - the fingerprint, step count, list lengths, `downloads_required`, `estimate` (with `basis`) and `elided_steps` for the arguments given; quote from it. `steps` counts what will run: a step nothing reads and which saves no file does not run, and is named in `elided_steps` instead |
273
273
  | `list_workspaces()` | — | The server's workspaces and which one this session is using. Each has its own workflows, assets and outputs; the prompt library is shared by all of them |
274
274
  | `use_workspace(name)` | `name` | Work in that workspace for the rest of the session - every later call reads and writes there. This is how to keep your work out of another agent's namespace rather than sharing the default one. Checked against the server, so a typo fails here rather than scoping every later call to nothing. On a `dw.serve --mcp` endpoint the pin is shared by every connected client (#298, see the note above the table) - a `warning` field appears when this call overwrote a pin already pointed away from `default` |
275
- | `create_workspace(name, use=False)` | `name`, `use` | Create a workspace. Pass use=true to switch this session to it as well; otherwise the session stays where it was and the result says so. `use=true` carries the same mounted-server caveat and `warning` field as `use_workspace` |
275
+ | `create_workspace(name, use=False)` | `name`, `use` | Create a workspace. Pass use=true to switch this session to it as well; otherwise the session stays where it was and the result says so. The result names the workspace (`name`, `default`, `current`, `next`), not its folders - `list_workspaces(detail=true)` is the opt-in for those. `use=true` carries the same mounted-server caveat and `warning` field as `use_workspace` |
276
276
  | `delete_workspace(name, acknowledged_cost=False)` | `name`, `acknowledged_cost` | Permanently delete a workspace and everything in it. Refuses without the acknowledgement, reporting what it would remove |
277
277
  | `list_assets()` | — | The input media on the server, each with the `asset:` reference a workflow argument carries. Look here before asking for a file - what a workflow needs may already be there. `libraries` names the roots searched and which are writable; `shadowed` lists names a nearer library hides |
278
278
  | `keep_output(name, asset_name=None, overwrite=False, shared=False, workspace=None)` | `name`, optional `asset_name`, `overwrite`, `shared`, `workspace` | Keep a generated file as an input asset under a stable `asset:` name, so a later workflow can rely on it. The copy happens on the server: nothing is downloaded or re-uploaded. `asset_name` may name a folder and takes the kept file's extension when it has none; `shared=true` keeps it in the library every workspace shares, which is where a recurring cast belongs. `workspace` names the workspace for this one call without switching the session to it - the same pin `run_workflow` takes, so a job run into another workspace stays reachable from the session that queued it |
@@ -297,6 +297,9 @@ references written in the same session.
297
297
  | `delete_prompt(name)` | `name` | Permanently delete a stored prompt. A workflow still referencing it will fail to load |
298
298
  | `list_enhancers()` | — | List the enhancer presets `enhance_prompt` accepts |
299
299
  | `enhance_prompt(idea, preset="h3", model_name=None, device=None, acknowledged_cost=False)` | `idea`, `preset`, optional `model_name` and `device`, `acknowledged_cost` | Expand a short idea into a full prompt with a language model. Queued as an ordinary job, so it passes the gate; the enhanced text is the text file in the finished manifest, readable with `get_output_text` |
300
+ | `list_loras(model=None, workflow=None, status=None, tag=None)` | optional `model`, `workflow`, `status`, `tag` | List the LoRAs tried on a base model - proven, trial or rejected - with `use_when`, `trigger` and `scale`; exact match on the base. Guide: `loras` |
301
+ | `save_lora(name, entry)` | `name`, `entry` | Save a catalog entry, overwriting any entry of that name; promote a trial to `proven` with its job in `evidence` |
302
+ | `recommend_loras(model, query, limit=8)` | `model`, `query`, optional `limit` | Opt-in: catalog LoRAs ranked against a style request, then Hugging Face Hub adapters of that exact base. Queries the Hub (the one tool with `open_world_hint`); no download, no GPU. Hub rows are candidates to trial. A failed or busy Hub (another search already running) returns the catalog rows plus `hub_error`; an empty `hub` with `hub_error` means the search failed |
300
303
 
301
304
  ### Diagnose
302
305