diffusers-workflow 0.4.0b4__tar.gz → 0.4.0b5__tar.gz

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 (363) hide show
  1. {diffusers_workflow-0.4.0b4/diffusers_workflow.egg-info → diffusers_workflow-0.4.0b5}/PKG-INFO +3 -2
  2. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/README.md +1 -0
  3. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5/diffusers_workflow.egg-info}/PKG-INFO +3 -2
  4. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/SOURCES.txt +28 -21
  5. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/requires.txt +1 -1
  6. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/arguments.py +14 -11
  7. diffusers_workflow-0.4.0b5/dw/docs/AGENT_LOOP.md +86 -0
  8. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/MCP.md +23 -9
  9. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/SECURITY.md +66 -10
  10. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/SECURITY_QUICKREF.md +34 -6
  11. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/SERVER.md +6 -1
  12. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/TASKS.md +19 -2
  13. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/WORKFLOW_GUIDE.md +42 -1
  14. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/introspection.py +12 -0
  15. diffusers_workflow-0.4.0b5/dw/locations.py +541 -0
  16. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/pipeline_processors/pipeline.py +52 -5
  17. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/pipeline_processors/remote.py +27 -10
  18. diffusers_workflow-0.4.0b5/dw/reference_limits.py +210 -0
  19. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/repl.py +2 -2
  20. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/schema.py +67 -3
  21. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/serve.py +2 -3
  22. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/app.py +174 -17
  23. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/guides.py +1 -1
  24. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/mcp_mount.py +4 -0
  25. diffusers_workflow-0.4.0b4/dw/server/ui/assets/cssMode-_LF3nQQz.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/cssMode-BQ03gENP.js +1 -1
  26. diffusers_workflow-0.4.0b4/dw/server/ui/assets/editor.api-Df8mF5HS.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/editor.api-CzvLX8mb.js +1 -1
  27. diffusers_workflow-0.4.0b4/dw/server/ui/assets/freemarker2-BFhhUaaI.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/freemarker2-C8c7lwsP.js +1 -1
  28. diffusers_workflow-0.4.0b4/dw/server/ui/assets/handlebars-uOyL83kB.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/handlebars-7APo_5hD.js +1 -1
  29. diffusers_workflow-0.4.0b4/dw/server/ui/assets/html-CNOcS1qq.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/html-JgrkBemQ.js +1 -1
  30. diffusers_workflow-0.4.0b4/dw/server/ui/assets/htmlMode-BrZs8ZFo.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/htmlMode-BH9VsgGh.js +1 -1
  31. diffusers_workflow-0.4.0b4/dw/server/ui/assets/index-BkC2KOK-.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/index-B1DfbIuu.js +29 -29
  32. diffusers_workflow-0.4.0b5/dw/server/ui/assets/index-CRVAbEJ9.css +1 -0
  33. diffusers_workflow-0.4.0b4/dw/server/ui/assets/javascript-BjmXvHYV.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/javascript-BrFJ1H6j.js +1 -1
  34. diffusers_workflow-0.4.0b4/dw/server/ui/assets/jsonMode-CUpeMAA9.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/jsonMode-C10gRe-2.js +1 -1
  35. diffusers_workflow-0.4.0b4/dw/server/ui/assets/liquid-CDCYHjo5.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/liquid-CjfGWTAZ.js +1 -1
  36. diffusers_workflow-0.4.0b4/dw/server/ui/assets/lspLanguageFeatures-C3BQ9bHy.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/lspLanguageFeatures-O-lB5SDv.js +1 -1
  37. diffusers_workflow-0.4.0b4/dw/server/ui/assets/mdx-Z0OBIKet.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/mdx-D7b-hMTY.js +1 -1
  38. diffusers_workflow-0.4.0b4/dw/server/ui/assets/monaco-CXIxqF1g.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/monaco-DBnxML20.js +4 -4
  39. diffusers_workflow-0.4.0b4/dw/server/ui/assets/python-zEGBkDvi.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/python-NfJjzkPL.js +1 -1
  40. diffusers_workflow-0.4.0b4/dw/server/ui/assets/razor-QEBcCsTz.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/razor-CgQtwMBj.js +1 -1
  41. diffusers_workflow-0.4.0b4/dw/server/ui/assets/tsMode-YMmO0OvA.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/tsMode-BuMW6Qar.js +1 -1
  42. diffusers_workflow-0.4.0b4/dw/server/ui/assets/typescript-DmCSelwV.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/typescript-Bfmxt754.js +1 -1
  43. diffusers_workflow-0.4.0b4/dw/server/ui/assets/workers-DNhR6kh1.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/workers-BSu9lD5s.js +1 -1
  44. diffusers_workflow-0.4.0b4/dw/server/ui/assets/xml-B9wx0o_u.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/xml-BJ2IwGRC.js +1 -1
  45. diffusers_workflow-0.4.0b4/dw/server/ui/assets/yaml-DRuGviYp.js → diffusers_workflow-0.4.0b5/dw/server/ui/assets/yaml-Cq85tEmC.js +1 -1
  46. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/index.html +2 -2
  47. diffusers_workflow-0.4.0b5/dw/task_domains.py +218 -0
  48. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/audio_utils.py +156 -42
  49. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/concat_videos.py +70 -7
  50. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/gather.py +16 -4
  51. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/image_utils.py +2 -2
  52. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/video_utils.py +6 -9
  53. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/teacache.py +6 -1
  54. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/worker.py +0 -1
  55. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflow.py +29 -6
  56. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflow_schema.json +31 -9
  57. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/assets.py +72 -0
  58. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/catalog.py +15 -1
  59. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/client.py +6 -0
  60. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/diagnose.py +4 -3
  61. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/media.py +74 -2
  62. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/server.py +36 -5
  63. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/pyproject.toml +20 -4
  64. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_argument_updates.py +21 -26
  65. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_arguments.py +12 -10
  66. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_audio_utils.py +117 -0
  67. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_cache_blocks.py +0 -2
  68. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_catalog_structure.py +48 -48
  69. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_chain.py +0 -2
  70. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_concat_videos.py +85 -3
  71. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_configuration_schema.py +3 -1
  72. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_device.py +0 -1
  73. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_diffusion_upscale.py +2 -6
  74. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_examples.py +21 -0
  75. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_gather.py +6 -6
  76. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_integration.py +0 -1
  77. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_introspection.py +1 -2
  78. diffusers_workflow-0.4.0b5/tests/test_locations.py +476 -0
  79. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_ltx_prompt_library.py +3 -3
  80. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_assets.py +87 -0
  81. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_catalog.py +26 -0
  82. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_main.py +0 -2
  83. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_media.py +98 -6
  84. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_server.py +3 -3
  85. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_pipeline_caching.py +25 -27
  86. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_pipeline_components.py +25 -1
  87. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_plan.py +3 -3
  88. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_plugin_skills.py +34 -15
  89. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_realize.py +12 -13
  90. diffusers_workflow-0.4.0b5/tests/test_reference_limits.py +138 -0
  91. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_commands.py +2 -2
  92. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_reorganization.py +6 -6
  93. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_result_output_naming.py +0 -2
  94. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_schema.py +226 -0
  95. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_segment.py +0 -1
  96. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server.py +197 -12
  97. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_exports.py +1 -1
  98. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_info.py +17 -0
  99. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_workspaces.py +0 -1
  100. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_step.py +2 -2
  101. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_task.py +6 -6
  102. diffusers_workflow-0.4.0b5/tests/test_task_domains.py +286 -0
  103. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_template_subfolders.py +9 -9
  104. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_tensor_image.py +0 -1
  105. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_type_helpers.py +0 -2
  106. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_video_utils.py +3 -2
  107. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workflow_step_cache.py +0 -1
  108. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workflow_trust.py +108 -0
  109. diffusers_workflow-0.4.0b4/dw/server/ui/assets/index-Dvcgq7CV.css +0 -1
  110. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/LICENSE +0 -0
  111. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/MANIFEST.in +0 -0
  112. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/dependency_links.txt +0 -0
  113. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/entry_points.txt +0 -0
  114. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/top_level.txt +0 -0
  115. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/__init__.py +0 -0
  116. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/assets.py +0 -0
  117. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/cache_blocks.json +0 -0
  118. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/cache_blocks.py +0 -0
  119. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/community_pipelines/pipeline_flux_rf_inversion.py +0 -0
  120. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/ACCELERATION.md +0 -0
  121. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/DEPENDENCIES.md +0 -0
  122. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/IP_ADAPTER.md +0 -0
  123. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/LORAS.md +0 -0
  124. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/PROMPT_WEIGHTING.md +0 -0
  125. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/QUANTIZATION.md +0 -0
  126. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/RECIPES_24GB.md +0 -0
  127. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/RELEASING.md +0 -0
  128. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/REMOTE.md +0 -0
  129. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/REPL_COMMANDS.md +0 -0
  130. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/REPL_WORKER_GUIDE.md +0 -0
  131. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/TESTING.md +0 -0
  132. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/WORKSPACES.md +0 -0
  133. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/events.py +0 -0
  134. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/for_each.py +0 -0
  135. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/host_memory.py +0 -0
  136. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/hub_cache.py +0 -0
  137. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/log_setup.py +0 -0
  138. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/media_info.py +0 -0
  139. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/pipeline_processors/chain.py +0 -0
  140. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/pipeline_processors/config_objects.py +0 -0
  141. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/plan.py +0 -0
  142. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/previous_results.py +0 -0
  143. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/prompt_schema.json +0 -0
  144. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/prompt_weighting.py +0 -0
  145. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/prompts.py +0 -0
  146. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/realize.py +0 -0
  147. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/repl_commands.py +0 -0
  148. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/repl_worker.py +0 -0
  149. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/result.py +0 -0
  150. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/run.py +0 -0
  151. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/runs.py +0 -0
  152. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/security.py +0 -0
  153. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/__init__.py +0 -0
  154. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/catalog_shape.py +0 -0
  155. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/enhancers.py +0 -0
  156. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/exports.py +0 -0
  157. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/jobs.py +0 -0
  158. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/netinfo.py +0 -0
  159. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/abap-08VXUWAP.js +0 -0
  160. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/apex-BWPQTe0t.js +0 -0
  161. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/azcli-Bc_sGQ0U.js +0 -0
  162. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/bat-i0X4ZdIN.js +0 -0
  163. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/bicep-B5-_aFwp.js +0 -0
  164. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/cameligo-DMUM7wLl.js +0 -0
  165. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/clojure-Cm7r79vr.js +0 -0
  166. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/codicon-Brq4_Ui5.ttf +0 -0
  167. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/coffee-Ba7i2nA0.js +0 -0
  168. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/cpp-C7h46wYY.js +0 -0
  169. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/csharp-BKxtCVv1.js +0 -0
  170. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/csp-bTuwJoIa.js +0 -0
  171. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/css-DIMkf-bt.js +0 -0
  172. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/css.worker-B3ciXF_0.js +0 -0
  173. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/cypher-CVaqCwHa.js +0 -0
  174. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/dart-onAF5SnQ.js +0 -0
  175. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/dockerfile-DZFCIeNp.js +0 -0
  176. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/ecl-D05T4iGw.js +0 -0
  177. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/editor-jjEx9u7D.css +0 -0
  178. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/editor.worker-q-txB4vs.js +0 -0
  179. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/elixir-6RTg0lbw.js +0 -0
  180. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/flow9-C5_-GSwl.js +0 -0
  181. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/fsharp-C8Ef5oNN.js +0 -0
  182. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/go-C-y9NEjX.js +0 -0
  183. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/graphql-fmXr3nnJ.js +0 -0
  184. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/hcl-CpzslTdj.js +0 -0
  185. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/html.worker-C93Ht9o9.js +0 -0
  186. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/ini-sBoK_t0W.js +0 -0
  187. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/java-BEtHBSE6.js +0 -0
  188. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/json.worker-B2V3pomh.js +0 -0
  189. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/julia-Bri6UV-V.js +0 -0
  190. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/kotlin-BOotOW0E.js +0 -0
  191. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/less-B9JPFI3C.js +0 -0
  192. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/lexon-CfSJPG6W.js +0 -0
  193. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/lua-CsQS60Ue.js +0 -0
  194. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/m3-D-oSqn_W.js +0 -0
  195. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/markdown-Cimd5fb3.js +0 -0
  196. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/mips-CIPQ_RoX.js +0 -0
  197. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/monaco--ixms01u.css +0 -0
  198. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/msdax-DauUninz.js +0 -0
  199. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/mysql-SOo6toE5.js +0 -0
  200. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/objective-c-FvmIjYaQ.js +0 -0
  201. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pascal-DrH0SRf2.js +0 -0
  202. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pascaligo-D-ptJ9y-.js +0 -0
  203. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/perl-oz_6vUea.js +0 -0
  204. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pgsql-DTj74zXo.js +0 -0
  205. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/php-nr791fC2.js +0 -0
  206. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pla-CopQ2nXW.js +0 -0
  207. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/postiats-43DmfD33.js +0 -0
  208. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/powerquery-D3hlyOfw.js +0 -0
  209. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/powershell-DmHpPYUd.js +0 -0
  210. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/protobuf-C531GsRP.js +0 -0
  211. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pug-Z5eAx3Zn.js +0 -0
  212. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/qsharp-DkqhCAOL.js +0 -0
  213. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/r-BwWrilGY.js +0 -0
  214. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/redis-ClamHrr6.js +0 -0
  215. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/redshift-DT7zqm-g.js +0 -0
  216. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/restructuredtext-BYgofb2h.js +0 -0
  217. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/ruby-DezsRK8O.js +0 -0
  218. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/rust-DdL9SqIa.js +0 -0
  219. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/sb-CcwsVR0C.js +0 -0
  220. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/scala-DHpiXF5c.js +0 -0
  221. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/scheme-BeGwcela.js +0 -0
  222. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/scss-gp-XZpBa.js +0 -0
  223. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/shell-CC2rA5mh.js +0 -0
  224. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/solidity-BEEn4gHE.js +0 -0
  225. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/sophia-CRfGWb83.js +0 -0
  226. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/sparql-D_Lu-MrJ.js +0 -0
  227. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/sql-NEE52Syq.js +0 -0
  228. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/st-DbInun42.js +0 -0
  229. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/swift-Bxkupp3x.js +0 -0
  230. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/systemverilog-Bz4Y3fRF.js +0 -0
  231. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/tcl-DISqw1ZD.js +0 -0
  232. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/ts.worker-D7T1-Ig5.js +0 -0
  233. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/twig-De2hgUGE.js +0 -0
  234. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/typespec-B8J7ngcE.js +0 -0
  235. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/vb-DV3o63ZY.js +0 -0
  236. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/wgsl-DpFanUEy.js +0 -0
  237. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/updater.py +0 -0
  238. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/settings.py +0 -0
  239. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/step.py +0 -0
  240. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/step_cache.py +0 -0
  241. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/subfolders.py +0 -0
  242. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/background_remover.py +0 -0
  243. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/borders.py +0 -0
  244. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/compose_text.py +0 -0
  245. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/depth_estimator.py +0 -0
  246. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/diffusion_upscale.py +0 -0
  247. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/dissolve_videos.py +0 -0
  248. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/format_messages.py +0 -0
  249. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/image_to_text.py +0 -0
  250. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/interpolate_frames.py +0 -0
  251. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/model_cache.py +0 -0
  252. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/pair_audio.py +0 -0
  253. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/qr_code.py +0 -0
  254. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/restore_faces.py +0 -0
  255. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/rife_model.py +0 -0
  256. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/segment.py +0 -0
  257. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/speech_generation.py +0 -0
  258. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/stabilize.py +0 -0
  259. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/task.py +0 -0
  260. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/tensor_image.py +0 -0
  261. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/text_generation.py +0 -0
  262. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/text_sections.py +0 -0
  263. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/upscale.py +0 -0
  264. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/zoe_depth.py +0 -0
  265. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/teacache_models.json +0 -0
  266. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/test.py +0 -0
  267. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/type_helpers.py +0 -0
  268. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/validate.py +0 -0
  269. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/variables.py +0 -0
  270. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflow_sources.py +0 -0
  271. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflows/h3_context_ir.json +0 -0
  272. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflows/test.json +0 -0
  273. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workspace.py +0 -0
  274. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/__init__.py +0 -0
  275. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/__main__.py +0 -0
  276. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/authoring.py +0 -0
  277. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/exports.py +0 -0
  278. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/guides.py +0 -0
  279. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/models.py +0 -0
  280. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/prompts.py +0 -0
  281. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/workspaces.py +0 -0
  282. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/setup.cfg +0 -0
  283. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_assets.py +0 -0
  284. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_borders.py +0 -0
  285. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_catalog_shape.py +0 -0
  286. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_cli.py +0 -0
  287. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_component_pruning.py +0 -0
  288. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_compose_text.py +0 -0
  289. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_config_objects.py +0 -0
  290. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_depth_estimator.py +0 -0
  291. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_device_helpers.py +0 -0
  292. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_device_portability.py +0 -0
  293. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_dialogue_short_voices.py +0 -0
  294. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_dissolve_videos.py +0 -0
  295. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_docs_links.py +0 -0
  296. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_events.py +0 -0
  297. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_for_each.py +0 -0
  298. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_h3_context_ir.py +0 -0
  299. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_hf_placement.py +0 -0
  300. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_host_memory.py +0 -0
  301. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_hub_cache.py +0 -0
  302. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_image_to_text.py +0 -0
  303. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_image_utils.py +0 -0
  304. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_interpolate_frames.py +0 -0
  305. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_job_progress.py +0 -0
  306. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_jobs_listing.py +0 -0
  307. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_jobs_reused.py +0 -0
  308. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_library_sources.py +0 -0
  309. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_list_images.py +0 -0
  310. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_authoring.py +0 -0
  311. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_client.py +0 -0
  312. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_diagnose.py +0 -0
  313. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_exports.py +0 -0
  314. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_guides.py +0 -0
  315. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_models.py +0 -0
  316. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_prompts.py +0 -0
  317. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_workspaces.py +0 -0
  318. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_media_info.py +0 -0
  319. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mix_audio.py +0 -0
  320. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_model_cache.py +0 -0
  321. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_modular_pipeline.py +0 -0
  322. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_modular_progress.py +0 -0
  323. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_offload_placement.py +0 -0
  324. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_output_references.py +0 -0
  325. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_pair_audio.py +0 -0
  326. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_phase_events.py +0 -0
  327. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_previous_results.py +0 -0
  328. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_prompt_parser.py +0 -0
  329. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_prompt_references.py +0 -0
  330. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_prompt_weighting.py +0 -0
  331. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_prompts.py +0 -0
  332. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_recenter_crop.py +0 -0
  333. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_ergonomics.py +0 -0
  334. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_hierarchical.py +0 -0
  335. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_worker.py +0 -0
  336. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_rerun_new_seed.py +0 -0
  337. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_resize_bucket.py +0 -0
  338. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_result.py +0 -0
  339. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_runs.py +0 -0
  340. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_scheduler_config.py +0 -0
  341. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_security.py +0 -0
  342. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_serve_main.py +0 -0
  343. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_downloads.py +0 -0
  344. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_guides.py +0 -0
  345. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_jobs.py +0 -0
  346. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_mcp.py +0 -0
  347. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_speech_generation.py +0 -0
  348. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_stabilize.py +0 -0
  349. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_step_cache.py +0 -0
  350. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_strip_exif_and_watermark.py +0 -0
  351. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_subfolders.py +0 -0
  352. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_task_discovery.py +0 -0
  353. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_teacache.py +0 -0
  354. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_text_generation.py +0 -0
  355. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_text_sections.py +0 -0
  356. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_updater.py +0 -0
  357. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_validate_arguments.py +0 -0
  358. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_variables.py +0 -0
  359. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_worker.py +0 -0
  360. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_worker_execute.py +0 -0
  361. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workflow.py +0 -0
  362. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workflow_sources.py +0 -0
  363. {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffusers-workflow
3
- Version: 0.4.0b4
3
+ Version: 0.4.0b5
4
4
  Summary: Declarative workflow engine and web UI for Hugging Face Diffusers
5
5
  Author: dkackman
6
6
  License: Apache-2.0
@@ -68,7 +68,7 @@ Requires-Dist: pytest-timeout>=2.4.0; extra == "dev"
68
68
  Requires-Dist: pytest-mock>=3.15.1; extra == "dev"
69
69
  Requires-Dist: pytest-asyncio>=1.4.0; extra == "dev"
70
70
  Requires-Dist: httpx>=0.28.1; extra == "dev"
71
- Requires-Dist: black>=26.5.1; extra == "dev"
71
+ Requires-Dist: ruff>=0.15.0; extra == "dev"
72
72
  Requires-Dist: build; extra == "dev"
73
73
  Requires-Dist: mcp>=2.1.1; extra == "dev"
74
74
  Dynamic: license-file
@@ -295,3 +295,4 @@ frame interpolation and more.
295
295
  - [Security](docs/SECURITY.md) — Security model
296
296
  - [Testing](docs/TESTING.md) — Running the test suite
297
297
  - [Releasing](docs/RELEASING.md) — Cutting a release from a version tag
298
+ - [Agent Loop](docs/AGENT_LOOP.md) — What the automated implementer/tester ticket labels mean, for anyone joining an Issue
@@ -220,3 +220,4 @@ frame interpolation and more.
220
220
  - [Security](docs/SECURITY.md) — Security model
221
221
  - [Testing](docs/TESTING.md) — Running the test suite
222
222
  - [Releasing](docs/RELEASING.md) — Cutting a release from a version tag
223
+ - [Agent Loop](docs/AGENT_LOOP.md) — What the automated implementer/tester ticket labels mean, for anyone joining an Issue
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffusers-workflow
3
- Version: 0.4.0b4
3
+ Version: 0.4.0b5
4
4
  Summary: Declarative workflow engine and web UI for Hugging Face Diffusers
5
5
  Author: dkackman
6
6
  License: Apache-2.0
@@ -68,7 +68,7 @@ Requires-Dist: pytest-timeout>=2.4.0; extra == "dev"
68
68
  Requires-Dist: pytest-mock>=3.15.1; extra == "dev"
69
69
  Requires-Dist: pytest-asyncio>=1.4.0; extra == "dev"
70
70
  Requires-Dist: httpx>=0.28.1; extra == "dev"
71
- Requires-Dist: black>=26.5.1; extra == "dev"
71
+ Requires-Dist: ruff>=0.15.0; extra == "dev"
72
72
  Requires-Dist: build; extra == "dev"
73
73
  Requires-Dist: mcp>=2.1.1; extra == "dev"
74
74
  Dynamic: license-file
@@ -295,3 +295,4 @@ frame interpolation and more.
295
295
  - [Security](docs/SECURITY.md) — Security model
296
296
  - [Testing](docs/TESTING.md) — Running the test suite
297
297
  - [Releasing](docs/RELEASING.md) — Cutting a release from a version tag
298
+ - [Agent Loop](docs/AGENT_LOOP.md) — What the automated implementer/tester ticket labels mean, for anyone joining an Issue
@@ -18,6 +18,7 @@ dw/for_each.py
18
18
  dw/host_memory.py
19
19
  dw/hub_cache.py
20
20
  dw/introspection.py
21
+ dw/locations.py
21
22
  dw/log_setup.py
22
23
  dw/media_info.py
23
24
  dw/plan.py
@@ -26,6 +27,7 @@ dw/prompt_schema.json
26
27
  dw/prompt_weighting.py
27
28
  dw/prompts.py
28
29
  dw/realize.py
30
+ dw/reference_limits.py
29
31
  dw/repl.py
30
32
  dw/repl_commands.py
31
33
  dw/repl_worker.py
@@ -39,6 +41,7 @@ dw/settings.py
39
41
  dw/step.py
40
42
  dw/step_cache.py
41
43
  dw/subfolders.py
44
+ dw/task_domains.py
42
45
  dw/teacache.py
43
46
  dw/teacache_models.json
44
47
  dw/test.py
@@ -52,6 +55,7 @@ dw/workflow_sources.py
52
55
  dw/workspace.py
53
56
  dw/community_pipelines/pipeline_flux_rf_inversion.py
54
57
  dw/docs/ACCELERATION.md
58
+ dw/docs/AGENT_LOOP.md
55
59
  dw/docs/DEPENDENCIES.md
56
60
  dw/docs/IP_ADAPTER.md
57
61
  dw/docs/LORAS.md
@@ -99,45 +103,45 @@ dw/server/ui/assets/csharp-BKxtCVv1.js
99
103
  dw/server/ui/assets/csp-bTuwJoIa.js
100
104
  dw/server/ui/assets/css-DIMkf-bt.js
101
105
  dw/server/ui/assets/css.worker-B3ciXF_0.js
102
- dw/server/ui/assets/cssMode-_LF3nQQz.js
106
+ dw/server/ui/assets/cssMode-BQ03gENP.js
103
107
  dw/server/ui/assets/cypher-CVaqCwHa.js
104
108
  dw/server/ui/assets/dart-onAF5SnQ.js
105
109
  dw/server/ui/assets/dockerfile-DZFCIeNp.js
106
110
  dw/server/ui/assets/ecl-D05T4iGw.js
107
111
  dw/server/ui/assets/editor-jjEx9u7D.css
108
- dw/server/ui/assets/editor.api-Df8mF5HS.js
112
+ dw/server/ui/assets/editor.api-CzvLX8mb.js
109
113
  dw/server/ui/assets/editor.worker-q-txB4vs.js
110
114
  dw/server/ui/assets/elixir-6RTg0lbw.js
111
115
  dw/server/ui/assets/flow9-C5_-GSwl.js
112
- dw/server/ui/assets/freemarker2-BFhhUaaI.js
116
+ dw/server/ui/assets/freemarker2-C8c7lwsP.js
113
117
  dw/server/ui/assets/fsharp-C8Ef5oNN.js
114
118
  dw/server/ui/assets/go-C-y9NEjX.js
115
119
  dw/server/ui/assets/graphql-fmXr3nnJ.js
116
- dw/server/ui/assets/handlebars-uOyL83kB.js
120
+ dw/server/ui/assets/handlebars-7APo_5hD.js
117
121
  dw/server/ui/assets/hcl-CpzslTdj.js
118
- dw/server/ui/assets/html-CNOcS1qq.js
122
+ dw/server/ui/assets/html-JgrkBemQ.js
119
123
  dw/server/ui/assets/html.worker-C93Ht9o9.js
120
- dw/server/ui/assets/htmlMode-BrZs8ZFo.js
121
- dw/server/ui/assets/index-BkC2KOK-.js
122
- dw/server/ui/assets/index-Dvcgq7CV.css
124
+ dw/server/ui/assets/htmlMode-BH9VsgGh.js
125
+ dw/server/ui/assets/index-B1DfbIuu.js
126
+ dw/server/ui/assets/index-CRVAbEJ9.css
123
127
  dw/server/ui/assets/ini-sBoK_t0W.js
124
128
  dw/server/ui/assets/java-BEtHBSE6.js
125
- dw/server/ui/assets/javascript-BjmXvHYV.js
129
+ dw/server/ui/assets/javascript-BrFJ1H6j.js
126
130
  dw/server/ui/assets/json.worker-B2V3pomh.js
127
- dw/server/ui/assets/jsonMode-CUpeMAA9.js
131
+ dw/server/ui/assets/jsonMode-C10gRe-2.js
128
132
  dw/server/ui/assets/julia-Bri6UV-V.js
129
133
  dw/server/ui/assets/kotlin-BOotOW0E.js
130
134
  dw/server/ui/assets/less-B9JPFI3C.js
131
135
  dw/server/ui/assets/lexon-CfSJPG6W.js
132
- dw/server/ui/assets/liquid-CDCYHjo5.js
133
- dw/server/ui/assets/lspLanguageFeatures-C3BQ9bHy.js
136
+ dw/server/ui/assets/liquid-CjfGWTAZ.js
137
+ dw/server/ui/assets/lspLanguageFeatures-O-lB5SDv.js
134
138
  dw/server/ui/assets/lua-CsQS60Ue.js
135
139
  dw/server/ui/assets/m3-D-oSqn_W.js
136
140
  dw/server/ui/assets/markdown-Cimd5fb3.js
137
- dw/server/ui/assets/mdx-Z0OBIKet.js
141
+ dw/server/ui/assets/mdx-D7b-hMTY.js
138
142
  dw/server/ui/assets/mips-CIPQ_RoX.js
139
143
  dw/server/ui/assets/monaco--ixms01u.css
140
- dw/server/ui/assets/monaco-CXIxqF1g.js
144
+ dw/server/ui/assets/monaco-DBnxML20.js
141
145
  dw/server/ui/assets/msdax-DauUninz.js
142
146
  dw/server/ui/assets/mysql-SOo6toE5.js
143
147
  dw/server/ui/assets/objective-c-FvmIjYaQ.js
@@ -152,10 +156,10 @@ dw/server/ui/assets/powerquery-D3hlyOfw.js
152
156
  dw/server/ui/assets/powershell-DmHpPYUd.js
153
157
  dw/server/ui/assets/protobuf-C531GsRP.js
154
158
  dw/server/ui/assets/pug-Z5eAx3Zn.js
155
- dw/server/ui/assets/python-zEGBkDvi.js
159
+ dw/server/ui/assets/python-NfJjzkPL.js
156
160
  dw/server/ui/assets/qsharp-DkqhCAOL.js
157
161
  dw/server/ui/assets/r-BwWrilGY.js
158
- dw/server/ui/assets/razor-QEBcCsTz.js
162
+ dw/server/ui/assets/razor-CgQtwMBj.js
159
163
  dw/server/ui/assets/redis-ClamHrr6.js
160
164
  dw/server/ui/assets/redshift-DT7zqm-g.js
161
165
  dw/server/ui/assets/restructuredtext-BYgofb2h.js
@@ -175,15 +179,15 @@ dw/server/ui/assets/swift-Bxkupp3x.js
175
179
  dw/server/ui/assets/systemverilog-Bz4Y3fRF.js
176
180
  dw/server/ui/assets/tcl-DISqw1ZD.js
177
181
  dw/server/ui/assets/ts.worker-D7T1-Ig5.js
178
- dw/server/ui/assets/tsMode-YMmO0OvA.js
182
+ dw/server/ui/assets/tsMode-BuMW6Qar.js
179
183
  dw/server/ui/assets/twig-De2hgUGE.js
180
- dw/server/ui/assets/typescript-DmCSelwV.js
184
+ dw/server/ui/assets/typescript-Bfmxt754.js
181
185
  dw/server/ui/assets/typespec-B8J7ngcE.js
182
186
  dw/server/ui/assets/vb-DV3o63ZY.js
183
187
  dw/server/ui/assets/wgsl-DpFanUEy.js
184
- dw/server/ui/assets/workers-DNhR6kh1.js
185
- dw/server/ui/assets/xml-B9wx0o_u.js
186
- dw/server/ui/assets/yaml-DRuGviYp.js
188
+ dw/server/ui/assets/workers-BSu9lD5s.js
189
+ dw/server/ui/assets/xml-BJ2IwGRC.js
190
+ dw/server/ui/assets/yaml-Cq85tEmC.js
187
191
  dw/tasks/audio_utils.py
188
192
  dw/tasks/background_remover.py
189
193
  dw/tasks/borders.py
@@ -269,6 +273,7 @@ tests/test_jobs_listing.py
269
273
  tests/test_jobs_reused.py
270
274
  tests/test_library_sources.py
271
275
  tests/test_list_images.py
276
+ tests/test_locations.py
272
277
  tests/test_ltx_prompt_library.py
273
278
  tests/test_mcp_assets.py
274
279
  tests/test_mcp_authoring.py
@@ -303,6 +308,7 @@ tests/test_prompt_weighting.py
303
308
  tests/test_prompts.py
304
309
  tests/test_realize.py
305
310
  tests/test_recenter_crop.py
311
+ tests/test_reference_limits.py
306
312
  tests/test_repl_commands.py
307
313
  tests/test_repl_ergonomics.py
308
314
  tests/test_repl_hierarchical.py
@@ -334,6 +340,7 @@ tests/test_strip_exif_and_watermark.py
334
340
  tests/test_subfolders.py
335
341
  tests/test_task.py
336
342
  tests/test_task_discovery.py
343
+ tests/test_task_domains.py
337
344
  tests/test_teacache.py
338
345
  tests/test_template_subfolders.py
339
346
  tests/test_tensor_image.py
@@ -47,7 +47,7 @@ pytest-timeout>=2.4.0
47
47
  pytest-mock>=3.15.1
48
48
  pytest-asyncio>=1.4.0
49
49
  httpx>=0.28.1
50
- black>=26.5.1
50
+ ruff>=0.15.0
51
51
  build
52
52
  mcp>=2.1.1
53
53
 
@@ -17,6 +17,7 @@ from .security import (
17
17
  ALLOWED_VIDEO_EXTENSIONS,
18
18
  ALLOWED_AUDIO_EXTENSIONS,
19
19
  )
20
+ from .locations import validate_media_path, validate_media_url
20
21
 
21
22
  logger = logging.getLogger("dw")
22
23
 
@@ -905,7 +906,7 @@ def fetch_image(img_spec, base_dir=None):
905
906
 
906
907
  # If already a PIL Image, return as-is (allows multiple realize_args calls)
907
908
  if hasattr(img_spec, "mode") and hasattr(img_spec, "size"):
908
- logger.debug(f"Image already loaded, returning as-is")
909
+ logger.debug("Image already loaded, returning as-is")
909
910
  return img_spec
910
911
 
911
912
  # Handle dict format: {"location": "url_or_path"}
@@ -931,12 +932,13 @@ def fetch_image(img_spec, base_dir=None):
931
932
  if isinstance(img_spec, str) and (
932
933
  img_spec.startswith("http://") or img_spec.startswith("https://")
933
934
  ):
934
- validated_url = validate_url(img_spec)
935
+ validated_url = validate_media_url(img_spec, "an image argument")
935
936
  return load_image(validated_url)
936
937
  else:
937
- # Treat as file path, relative to the workflow file
938
- validated_path = validate_path(
939
- resolve_relative_path(str(img_spec), base_dir), allow_create=False
938
+ # Treat as file path, relative to the workflow file, and confined
939
+ # to the directories this workflow may read (dw/locations.py)
940
+ validated_path = validate_media_path(
941
+ str(img_spec), base_dir, "an image argument"
940
942
  )
941
943
  # Validate file extension
942
944
  ext = os.path.splitext(validated_path)[1].lower()
@@ -995,12 +997,12 @@ def fetch_video(video_spec, base_dir=None):
995
997
  return [fetch_video(vid, base_dir) for vid in video_spec]
996
998
  # Otherwise assume it's already loaded video frames
997
999
  else:
998
- logger.debug(f"Video frames already loaded, returning as-is")
1000
+ logger.debug("Video frames already loaded, returning as-is")
999
1001
  return video_spec
1000
1002
 
1001
1003
  # If already loaded video frames (tuple), return as-is
1002
1004
  if isinstance(video_spec, tuple):
1003
- logger.debug(f"Video frames already loaded, returning as-is")
1005
+ logger.debug("Video frames already loaded, returning as-is")
1004
1006
  return video_spec
1005
1007
 
1006
1008
  # Handle dict format: {"location": "url_or_path"}
@@ -1028,12 +1030,13 @@ def fetch_video(video_spec, base_dir=None):
1028
1030
  if isinstance(video_spec, str) and (
1029
1031
  video_spec.startswith("http://") or video_spec.startswith("https://")
1030
1032
  ):
1031
- validated_url = validate_url(video_spec)
1033
+ validated_url = validate_media_url(video_spec, "a video argument")
1032
1034
  return _with_frame_rate(load_video(validated_url), validated_url)
1033
1035
  else:
1034
- # Treat as file path, relative to the workflow file
1035
- validated_path = validate_path(
1036
- resolve_relative_path(str(video_spec), base_dir), allow_create=False
1036
+ # Treat as file path, relative to the workflow file, and confined
1037
+ # to the directories this workflow may read (dw/locations.py)
1038
+ validated_path = validate_media_path(
1039
+ str(video_spec), base_dir, "a video argument"
1037
1040
  )
1038
1041
  # Validate file extension
1039
1042
  ext = os.path.splitext(validated_path)[1].lower()
@@ -0,0 +1,86 @@
1
+ # Agent Loop
2
+
3
+ Some of the Issues in this repo are worked by an automated implementer/tester
4
+ agent loop, not a human. It lives in a separate repo
5
+ ([`dkackman/iterate`](https://github.com/dkackman/iterate) — private) that
6
+ drives two Claude Code agents in strict alternation against this repo's
7
+ Issues. Nothing about running the loop lives here; this page exists so that
8
+ anyone who opens or comments on one of its Issues — a human, or another
9
+ agent joining in — knows how to act on it correctly.
10
+
11
+ ## The two roles
12
+
13
+ - **Implementer** — has this repo checked out and SSH access to the box
14
+ running the MCP server. Reproduces, fixes, deploys, and hands the ticket
15
+ back. Never verifies its own fix.
16
+ - **Tester** — talks to the MCP server only as a protocol client (MCP tool
17
+ calls), no source checkout, no shell/SSH access to the server box. Its job
18
+ is independent verification: it re-runs the original repro over MCP and
19
+ either confirms the fix or bounces the ticket back.
20
+
21
+ That asymmetry — the only role that can mark an issue verified is the one
22
+ with no ability to patch around a bug — is the entire point of the loop. A
23
+ human or third agent joining in should preserve it: don't fix and verify the
24
+ same ticket yourself.
25
+
26
+ A third, standalone **regression agent** periodically runs a growing suite
27
+ of scripted MCP calls (`regression-suite-*.md` in the `iterate` repo) against
28
+ the live server and files/comments on Issues for anything that regresses. It
29
+ doesn't participate in the implementer/tester handoff.
30
+
31
+ ## Reading a ticket
32
+
33
+ Tickets use the **MCP agent-loop ticket** issue template. Two label
34
+ families carry all the state — check both before acting:
35
+
36
+ - **`owner:*`** — exactly one of `owner:implementer` / `owner:tester` /
37
+ `owner:don` at a time: whoever is expected to act on it next. If you're
38
+ not that owner, leave the issue alone beyond reading it (or the specific
39
+ handoff comment/label a role prompt allows).
40
+ - **`status:*`** — where the ticket is in its lifecycle:
41
+ - *(no status label)* — open, ready for the implementer to reproduce.
42
+ - `status:fixed-pending-verify` — implementer has fixed and deployed;
43
+ waiting on the tester to re-run the repro over MCP.
44
+ - `status:verified` — tester confirmed the fix over MCP; issue is closed
45
+ as `completed`.
46
+ - `status:needs-info` — a question bounce; whoever is asked needs to
47
+ answer before work continues.
48
+ - `status:needs-approval` (+ `owner:don`) — parked for the human. The
49
+ implementer uses this for anything beyond a rename-level change
50
+ (engine behavior, breaking syntax). Neither agent touches a parked
51
+ issue.
52
+
53
+ Two built-in GitHub labels close a ticket without a fix:
54
+
55
+ - **`wontfix`** — the implementer's call, with a reason in a comment; issue
56
+ closed as `not planned`. The tester may reopen once with new evidence; a
57
+ second `wontfix` is final.
58
+ - **`duplicate`** — closed as `not planned`, with a comment naming the
59
+ issue it duplicates (`duplicate of #NN`). A closed issue is still
60
+ canonical for duplicate detection — the implementer checks
61
+ `gh issue list --state all` before starting work, not just open issues.
62
+
63
+ `breaking-change` marks an Issue whose fix changed the MCP interface, so the
64
+ tester adjusts its calls instead of filing the change as a new bug.
65
+
66
+ ## If you want to participate
67
+
68
+ Whether you're a human or another agent:
69
+
70
+ - Only touch an issue that's currently owned by you (or, for a human, one
71
+ parked with `owner:don`).
72
+ - When you hand a ticket to the next owner, swap the `owner:*` label and
73
+ say what you did in a comment — the next actor has no memory of this
74
+ session, only the issue thread.
75
+ - Keep implementer and tester roles separate. If you're fixing code, don't
76
+ also close the issue as verified — that requires an independent MCP call
77
+ from someone who didn't write the patch.
78
+ - Reference the issue number in any commit that fixes it
79
+ (`fix(mcp): #42 - ...`), and work on a branch merged to `develop`, never
80
+ `master`.
81
+ - Only the tester (or an equivalently independent verifier) closes an issue
82
+ as `completed`/`status:verified`, and only after a real MCP call
83
+ reproduces the fix — not by reading the diff.
84
+
85
+ See the `iterate` repo's `CLAUDE.md` for the full protocol this is
86
+ summarized from, including how the automated loop itself is run.
@@ -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 |
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, workspace=None)` | `limit`, `subfolder`, `workspace` | 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 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. `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: the exact workflow and arguments that produced it, and, for audio/video, a `media` block (duration, rate, channels, fps, size, peak/mean dBFS). `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. `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). `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. `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
 
@@ -235,7 +235,7 @@ when no single workflow covers it.
235
235
  | --- | --- | --- |
236
236
  | `get_output_image(name, max_dimension=768, workspace=None)` | `name`, `max_dimension`, `workspace` | Look at a generated image, downscaled to `max_dimension` on its longest side. Returns the image plus a text part reporting `original_size`, `returned_size` and `bytes`, so a downscale is never silent. `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 |
237
237
  | `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 |
238
- | `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, a directory, or omitted to save under the output's own name in the current working directory; `~` expands and missing parent directories are created. `overwrite=True` is required to replace a file already at the resolved path. 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 |
238
+ | `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, a directory, or omitted to save under the output's own name in the current working directory; `~` expands and missing parent directories are created. `overwrite=True` is required to replace a file already at the resolved path. Over a `dw.serve --mcp` endpoint the file lands on the server, so the destination is confined to that workspace and a relative one is joined onto it. 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 |
239
239
  | `delete_output(name, workspace=None)` | `name`, `workspace` | Permanently remove one generated file from the output directory. `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
 
241
241
  ### Authoring, assets and workspaces
@@ -249,7 +249,7 @@ The session starts in `default` and stays there unless it is told otherwise.
249
249
 
250
250
  | Tool | Arguments | Purpose |
251
251
  | --- | --- | --- |
252
- | `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. `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` and `estimate` (with `basis`) for the arguments given; quote from it |
252
+ | `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` and `estimate` (with `basis`) for the arguments given; quote from it |
253
253
  | `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 |
254
254
  | `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 |
255
255
  | `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 |
@@ -412,13 +412,22 @@ localhost binding, no auth, `Origin` header checks, and path confinement in
412
412
  Nothing under `dw_mcp/` re-implements or loosens that confinement; it is
413
413
  purely a client of the same validated endpoints the web UI uses - except for
414
414
  `download_output`, the one tool that writes a local file for the MCP client
415
- rather than only reading through the API. It may write anywhere the
416
- client's own filesystem lets it (a full path, a directory, or the current
417
- working directory by default, `~` expanded), the way a shell redirect
418
- would for the same user; a `..` path segment in `destination` is refused,
419
- and an existing file is left alone unless the caller passes
415
+ rather than only reading through the API. Over a stdio `dw-mcp` it may write
416
+ anywhere the client's own filesystem lets it (a full path, a directory, or
417
+ the current working directory by default, `~` expanded), the way a shell
418
+ redirect would for the same user; a `..` path segment in `destination` is
419
+ refused, and an existing file is left alone unless the caller passes
420
420
  `overwrite=True`.
421
421
 
422
+ Over `dw.serve --mcp` the write happens **on the server**, and there the
423
+ destination is confined to that workspace: an absolute or `~` path outside
424
+ it is refused, and a relative one is joined onto the workspace rather than
425
+ onto whatever the server process's working directory happens to be. The
426
+ transport is what distinguishes the two - on stdio "local disk" is genuinely
427
+ the caller's own machine, over HTTP it is the operator's. Confinement is on
428
+ the resolved real path, not a substring test, because an absolute path needs
429
+ no `..` to reach anywhere the server can write.
430
+
422
431
  `dw-mcp` may be pointed at a `dw.serve` on another machine only when that
423
432
  server was started with a token, and the same token is passed here
424
433
  (`--token` / `DW_API_TOKEN`); it refuses to start otherwise. The token is
@@ -450,8 +459,13 @@ default) for any server an MCP client can reach.
450
459
  runs on. Over `dw.serve --mcp` that is the GPU box, so a file sitting on
451
460
  the client's laptop is not reachable that way - put it on the server, or
452
461
  give the workflow a URL (the arguments that take a path take a URL too).
462
+ On a `--mcp` endpoint `file_path` is also *confined* to the directories the
463
+ server works in (its workspace, workflows, assets, outputs and prompts), and
464
+ the refusal comes before the file is looked for, so the tool cannot be used
465
+ to probe which paths exist on the box (#138).
453
466
  `download_output` has the same asymmetry in the other direction: on a
454
- `--mcp` endpoint it writes on the GPU box, not the client's machine.
467
+ `--mcp` endpoint it writes on the GPU box, not the client's machine, and is
468
+ confined to the workspace there.
455
469
  - **Prompts are not per-workspace.** Switching workspaces changes which
456
470
  workflows, assets and outputs the session sees; the prompt library is one
457
471
  library shared by all of them, because `prompt:` is shared by reference.
@@ -91,6 +91,52 @@ diffusers' remote-code paths open. No bundled catalog entry sets either
91
91
  (`tests/test_catalog_structure.py` refuses one that does); a workflow that
92
92
  needs them needs `--trust-workflows`.
93
93
 
94
+ ### Where a workflow may read and reach (`dw/locations.py`)
95
+
96
+ Code execution is not the only thing a workflow file chooses. Its arguments
97
+ choose *locations* - which image to open, which URL to fetch, which
98
+ directory a glob expands over - and until 2026-09-13 each loader trusted the
99
+ one it was handed. A workflow could name `/usr/share/pixmaps/debian-logo.png`
100
+ as its `image` and get it decoded, glob `/usr/share/pixmaps/*.png` and get
101
+ every match republished verbatim as an output, or point an `image` at
102
+ `http://127.0.0.1:8765` and have the server fetch its own loopback.
103
+ `remote_text_encoder.url` was the worst of them: the request carries this
104
+ machine's HuggingFace token.
105
+
106
+ One policy now answers all of it, untrusted:
107
+
108
+ - **A path** must resolve inside a root this installation already works in -
109
+ the workflow file's own directory, the asset libraries on the search path,
110
+ the output root. `validate_path` already refuses `..`, so in practice this
111
+ closes the absolute path that pointed somewhere else entirely; a relative
112
+ one that climbs out is refused on its `..` segments, at validation time as
113
+ well as at the loader, so both spellings are answered at the same moment
114
+ rather than one of them three seconds into a queued job (#124). The remedy
115
+ for a file outside is to put it in the asset library and use an `asset:`
116
+ reference. Containment is checked **before** existence, so the refusal
117
+ cannot be used as a file-existence oracle.
118
+ - **A glob** is contained the same way, on the fixed directory its pattern
119
+ starts from, and every match is re-checked on its real path so a symlink
120
+ cannot carry the expansion out.
121
+ - **An `http(s)` URL** must not resolve to an address inside the deployment -
122
+ loopback, link-local (`169.254.0.0/16`, the cloud metadata address),
123
+ private ranges. Checked after DNS resolution, not on the literal string.
124
+ - **`remote_text_encoder.url`** is https-only, and the HuggingFace token is
125
+ attached only for `huggingface.co`, `huggingface.cloud` and `hf.space`. An
126
+ endpoint elsewhere is still reachable; it just does not get the credential.
127
+ - **`model_name`** must be a Hub repo id or a path inside a root - the same
128
+ shape check `download_model` has always applied to `repo_id`. A URL is
129
+ neither, and is refused as such rather than resolving into the workflow's
130
+ own directory as a path-shaped name (#117).
131
+
132
+ Enforced twice: `location_errors` runs inside `validation_errors`, so
133
+ `validate_workflow` refuses before a model load is spent on the run, and the
134
+ loaders call the same functions for a location that arrives through a
135
+ variable or a previous result. All of it yields to `--trust-workflows`.
136
+
137
+ `GET /api/server` reports `trust_workflows`, so a client can read the posture
138
+ it is running against rather than infer it.
139
+
94
140
  `--trust-workflows` is a blanket, process-wide choice - it is not scoped
95
141
  per-workflow or per-request. A `dw-serve` instance that accepts jobs from
96
142
  anything other than yourself (including an MCP client - see below) should
@@ -131,14 +177,21 @@ validated there, exactly as it would be for a browser request from the web
131
177
  UI. A remote `dw.serve` is allowed only with a token — see
132
178
  [MCP Server](MCP.md#security) and [REMOTE.md](REMOTE.md).
133
179
 
134
- The one exception is `download_output`, which writes a local file for the
135
- MCP client rather than only reading through the API. It may write anywhere
136
- the client's own filesystem permissions allow (the machine running the MCP
137
- server — the GPU box when served by `dw.serve --mcp`) — a full path, a
138
- directory, or the current working directory by default, `~` expanded — since
139
- it acts for the local user the same way a shell redirect would; a `..` path segment in
140
- `destination` is refused regardless, and an existing file at the resolved
141
- path is left alone unless the caller passes `overwrite=True`.
180
+ The two exceptions are `download_output`, which writes a local file for the
181
+ MCP client, and `upload_asset(file_path=...)`, which reads one — neither goes
182
+ through the API for that half of its work. Both turn on whose machine "local"
183
+ is. Over a **stdio `dw-mcp`** it is the user's own, so both act for the local
184
+ user the way a shell redirect would: `download_output` writes anywhere the
185
+ process may (a full path, a directory, or the working directory by default,
186
+ `~` expanded) and `upload_asset` reads anything it may. Over **`dw.serve
187
+ --mcp`** it is the operator's box, which the caller never chose, so both are
188
+ confined there: `download_output`'s `destination` to the workspace (#113) and
189
+ `upload_asset`'s `file_path` to the directories the server works in — its
190
+ workspace, workflows, assets, outputs and prompts (#138). `upload_asset`'s
191
+ refusal is ordered ahead of the existence and extension checks so it cannot
192
+ be used as a path-existence oracle. A `..` path segment in `destination` is
193
+ refused regardless, and an existing file at the resolved path is left alone
194
+ unless the caller passes `overwrite=True`.
142
195
 
143
196
  ## Exception Hierarchy
144
197
 
@@ -160,10 +213,13 @@ SecurityError
160
213
  - **Path traversal** — Cannot access files outside allowed directories
161
214
  - **Command injection** — No shell interpretation is used anywhere in `dw/`; `sanitize_command_args()` is available as a guard should a subprocess call be added
162
215
  - **Resource exhaustion** — File size limits prevent memory exhaustion
163
- - **Malicious URLs** — Only http/https schemes allowed
216
+ - **Malicious URLs** — Only http/https schemes allowed, and an untrusted
217
+ workflow may not name a host inside the deployment (SSRF)
218
+ - **Arbitrary file read through a media argument** — a location a workflow
219
+ supplies is confined to the roots it may read (`dw/locations.py`)
164
220
 
165
221
  ## Testing
166
222
 
167
223
  ```bash
168
- pytest tests/test_security.py -v
224
+ pytest tests/test_security.py tests/test_locations.py tests/test_workflow_trust.py -v
169
225
  ```
@@ -13,12 +13,39 @@ and [REMOTE.md](REMOTE.md).
13
13
 
14
14
  ```python
15
15
  from dw.security import (
16
- validate_path, validate_workflow_path, validate_output_path,
17
- validate_url, validate_variable_name, validate_string_input,
18
- sanitize_command_args, SecurityError, PathTraversalError, InvalidInputError
16
+ validate_path,
17
+ validate_workflow_path,
18
+ validate_output_path,
19
+ validate_url,
20
+ validate_variable_name,
21
+ validate_string_input,
22
+ sanitize_command_args,
23
+ SecurityError,
24
+ PathTraversalError,
25
+ InvalidInputError,
19
26
  )
20
27
  ```
21
28
 
29
+ ## Locations a workflow supplies
30
+
31
+ A media path, glob or URL that comes out of a workflow's arguments is not
32
+ just a path - it is untrusted input choosing where the server reads. Use
33
+ `dw/locations.py`, never `validate_path`/`validate_url` directly, for
34
+ anything a workflow names:
35
+
36
+ ```python
37
+ from dw.locations import (
38
+ validate_media_path, # confined to the workflow dir / assets / outputs
39
+ validate_media_glob, # the same, on a pattern's fixed prefix
40
+ contained_matches, # each match re-checked on its real path
41
+ validate_media_url, # no loopback / link-local / private host
42
+ validate_model_name, # a Hub repo id, or a contained path
43
+ )
44
+ ```
45
+
46
+ Containment is checked before existence, so a refusal never discloses
47
+ whether the file is there. All of it yields to `--trust-workflows`.
48
+
22
49
  ## Common Patterns
23
50
 
24
51
  ```python
@@ -29,13 +56,14 @@ workflow_path = validate_workflow_path("workflow.json")
29
56
  output_path = validate_output_path(user_path, base_output_dir)
30
57
 
31
58
  # User input
32
- var_name = validate_variable_name("prompt") # OK
33
- var_name = validate_variable_name("bad;name") # raises InvalidInputError
59
+ var_name = validate_variable_name("prompt") # OK
60
+ var_name = validate_variable_name("bad;name") # raises InvalidInputError
34
61
  value = validate_string_input(user_input, max_length=1000)
35
- url = validate_url(user_url) # http/https only
62
+ url = validate_url(user_url) # http/https only
36
63
 
37
64
  # Subprocess (dw/ doesn't currently shell out anywhere - pattern for if/when it does)
38
65
  import subprocess
66
+
39
67
  cmd = sanitize_command_args(["python", "-m", "dw.run", validated_path])
40
68
  subprocess.Popen(cmd, shell=False)
41
69
  ```
@@ -277,7 +277,12 @@ The editor's forms come from these; they are just as usable from scripts:
277
277
  makes the same check and answers 400 rather than queuing a job that would
278
278
  fail on its first step; `checked_arguments` on a valid answer names what
279
279
  was covered, since without arguments the verdict is about the stored
280
- defaults only.
280
+ defaults only. A reference set a pipeline would refuse is an error here
281
+ too - too many images, videos or audio clips for the family, or, for
282
+ MiniMax-H3, audio as the only reference - because the pipeline enforces
283
+ those only once its checkpoint is loaded, minutes into an acknowledged
284
+ run (`dw/reference_limits.py`, which reads each limit off the diffusers
285
+ block that enforces it rather than restating it).
281
286
 
282
287
  A valid answer also carries `plan`, what the run will execute for those
283
288
  arguments: `fingerprint` (`sha256:…` over the realized, expanded