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.
- {diffusers_workflow-0.4.0b4/diffusers_workflow.egg-info → diffusers_workflow-0.4.0b5}/PKG-INFO +3 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/README.md +1 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5/diffusers_workflow.egg-info}/PKG-INFO +3 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/SOURCES.txt +28 -21
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/requires.txt +1 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/arguments.py +14 -11
- diffusers_workflow-0.4.0b5/dw/docs/AGENT_LOOP.md +86 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/MCP.md +23 -9
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/SECURITY.md +66 -10
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/SECURITY_QUICKREF.md +34 -6
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/SERVER.md +6 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/TASKS.md +19 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/WORKFLOW_GUIDE.md +42 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/introspection.py +12 -0
- diffusers_workflow-0.4.0b5/dw/locations.py +541 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/pipeline_processors/pipeline.py +52 -5
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/pipeline_processors/remote.py +27 -10
- diffusers_workflow-0.4.0b5/dw/reference_limits.py +210 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/repl.py +2 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/schema.py +67 -3
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/serve.py +2 -3
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/app.py +174 -17
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/guides.py +1 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/mcp_mount.py +4 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- diffusers_workflow-0.4.0b5/dw/server/ui/assets/index-CRVAbEJ9.css +1 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/index.html +2 -2
- diffusers_workflow-0.4.0b5/dw/task_domains.py +218 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/audio_utils.py +156 -42
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/concat_videos.py +70 -7
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/gather.py +16 -4
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/image_utils.py +2 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/video_utils.py +6 -9
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/teacache.py +6 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/worker.py +0 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflow.py +29 -6
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflow_schema.json +31 -9
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/assets.py +72 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/catalog.py +15 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/client.py +6 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/diagnose.py +4 -3
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/media.py +74 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/server.py +36 -5
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/pyproject.toml +20 -4
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_argument_updates.py +21 -26
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_arguments.py +12 -10
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_audio_utils.py +117 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_cache_blocks.py +0 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_catalog_structure.py +48 -48
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_chain.py +0 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_concat_videos.py +85 -3
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_configuration_schema.py +3 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_device.py +0 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_diffusion_upscale.py +2 -6
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_examples.py +21 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_gather.py +6 -6
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_integration.py +0 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_introspection.py +1 -2
- diffusers_workflow-0.4.0b5/tests/test_locations.py +476 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_ltx_prompt_library.py +3 -3
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_assets.py +87 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_catalog.py +26 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_main.py +0 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_media.py +98 -6
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_server.py +3 -3
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_pipeline_caching.py +25 -27
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_pipeline_components.py +25 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_plan.py +3 -3
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_plugin_skills.py +34 -15
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_realize.py +12 -13
- diffusers_workflow-0.4.0b5/tests/test_reference_limits.py +138 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_commands.py +2 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_reorganization.py +6 -6
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_result_output_naming.py +0 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_schema.py +226 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_segment.py +0 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server.py +197 -12
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_exports.py +1 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_info.py +17 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_workspaces.py +0 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_step.py +2 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_task.py +6 -6
- diffusers_workflow-0.4.0b5/tests/test_task_domains.py +286 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_template_subfolders.py +9 -9
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_tensor_image.py +0 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_type_helpers.py +0 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_video_utils.py +3 -2
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workflow_step_cache.py +0 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workflow_trust.py +108 -0
- diffusers_workflow-0.4.0b4/dw/server/ui/assets/index-Dvcgq7CV.css +0 -1
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/LICENSE +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/MANIFEST.in +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/dependency_links.txt +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/entry_points.txt +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/top_level.txt +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/__init__.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/assets.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/cache_blocks.json +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/cache_blocks.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/community_pipelines/pipeline_flux_rf_inversion.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/ACCELERATION.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/DEPENDENCIES.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/IP_ADAPTER.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/LORAS.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/PROMPT_WEIGHTING.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/QUANTIZATION.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/RECIPES_24GB.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/RELEASING.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/REMOTE.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/REPL_COMMANDS.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/REPL_WORKER_GUIDE.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/TESTING.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/docs/WORKSPACES.md +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/events.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/for_each.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/host_memory.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/hub_cache.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/log_setup.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/media_info.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/pipeline_processors/chain.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/pipeline_processors/config_objects.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/plan.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/previous_results.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/prompt_schema.json +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/prompt_weighting.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/prompts.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/realize.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/repl_commands.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/repl_worker.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/result.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/run.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/runs.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/security.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/__init__.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/catalog_shape.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/enhancers.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/exports.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/jobs.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/netinfo.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/abap-08VXUWAP.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/apex-BWPQTe0t.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/azcli-Bc_sGQ0U.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/bat-i0X4ZdIN.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/bicep-B5-_aFwp.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/cameligo-DMUM7wLl.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/clojure-Cm7r79vr.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/codicon-Brq4_Ui5.ttf +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/coffee-Ba7i2nA0.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/cpp-C7h46wYY.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/csharp-BKxtCVv1.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/csp-bTuwJoIa.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/css-DIMkf-bt.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/css.worker-B3ciXF_0.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/cypher-CVaqCwHa.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/dart-onAF5SnQ.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/dockerfile-DZFCIeNp.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/ecl-D05T4iGw.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/editor-jjEx9u7D.css +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/editor.worker-q-txB4vs.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/elixir-6RTg0lbw.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/flow9-C5_-GSwl.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/fsharp-C8Ef5oNN.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/go-C-y9NEjX.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/graphql-fmXr3nnJ.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/hcl-CpzslTdj.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/html.worker-C93Ht9o9.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/ini-sBoK_t0W.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/java-BEtHBSE6.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/json.worker-B2V3pomh.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/julia-Bri6UV-V.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/kotlin-BOotOW0E.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/less-B9JPFI3C.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/lexon-CfSJPG6W.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/lua-CsQS60Ue.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/m3-D-oSqn_W.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/markdown-Cimd5fb3.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/mips-CIPQ_RoX.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/monaco--ixms01u.css +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/msdax-DauUninz.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/mysql-SOo6toE5.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/objective-c-FvmIjYaQ.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pascal-DrH0SRf2.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pascaligo-D-ptJ9y-.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/perl-oz_6vUea.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pgsql-DTj74zXo.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/php-nr791fC2.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pla-CopQ2nXW.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/postiats-43DmfD33.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/powerquery-D3hlyOfw.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/powershell-DmHpPYUd.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/protobuf-C531GsRP.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/pug-Z5eAx3Zn.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/qsharp-DkqhCAOL.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/r-BwWrilGY.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/redis-ClamHrr6.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/redshift-DT7zqm-g.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/restructuredtext-BYgofb2h.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/ruby-DezsRK8O.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/rust-DdL9SqIa.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/sb-CcwsVR0C.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/scala-DHpiXF5c.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/scheme-BeGwcela.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/scss-gp-XZpBa.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/shell-CC2rA5mh.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/solidity-BEEn4gHE.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/sophia-CRfGWb83.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/sparql-D_Lu-MrJ.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/sql-NEE52Syq.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/st-DbInun42.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/swift-Bxkupp3x.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/systemverilog-Bz4Y3fRF.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/tcl-DISqw1ZD.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/ts.worker-D7T1-Ig5.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/twig-De2hgUGE.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/typespec-B8J7ngcE.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/vb-DV3o63ZY.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/ui/assets/wgsl-DpFanUEy.js +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/server/updater.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/settings.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/step.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/step_cache.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/subfolders.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/background_remover.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/borders.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/compose_text.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/depth_estimator.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/diffusion_upscale.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/dissolve_videos.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/format_messages.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/image_to_text.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/interpolate_frames.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/model_cache.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/pair_audio.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/qr_code.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/restore_faces.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/rife_model.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/segment.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/speech_generation.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/stabilize.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/task.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/tensor_image.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/text_generation.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/text_sections.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/upscale.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/tasks/zoe_depth.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/teacache_models.json +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/test.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/type_helpers.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/validate.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/variables.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflow_sources.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflows/h3_context_ir.json +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workflows/test.json +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw/workspace.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/__init__.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/__main__.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/authoring.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/exports.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/guides.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/models.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/prompts.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/dw_mcp/workspaces.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/setup.cfg +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_assets.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_borders.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_catalog_shape.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_cli.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_component_pruning.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_compose_text.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_config_objects.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_depth_estimator.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_device_helpers.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_device_portability.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_dialogue_short_voices.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_dissolve_videos.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_docs_links.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_events.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_for_each.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_h3_context_ir.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_hf_placement.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_host_memory.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_hub_cache.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_image_to_text.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_image_utils.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_interpolate_frames.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_job_progress.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_jobs_listing.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_jobs_reused.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_library_sources.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_list_images.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_authoring.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_client.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_diagnose.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_exports.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_guides.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_models.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_prompts.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mcp_workspaces.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_media_info.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_mix_audio.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_model_cache.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_modular_pipeline.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_modular_progress.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_offload_placement.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_output_references.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_pair_audio.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_phase_events.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_previous_results.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_prompt_parser.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_prompt_references.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_prompt_weighting.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_prompts.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_recenter_crop.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_ergonomics.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_hierarchical.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_repl_worker.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_rerun_new_seed.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_resize_bucket.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_result.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_runs.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_scheduler_config.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_security.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_serve_main.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_downloads.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_guides.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_jobs.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_server_mcp.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_speech_generation.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_stabilize.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_step_cache.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_strip_exif_and_watermark.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_subfolders.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_task_discovery.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_teacache.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_text_generation.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_text_sections.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_updater.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_validate_arguments.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_variables.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_worker.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_worker_execute.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workflow.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workflow_sources.py +0 -0
- {diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/tests/test_workspace.py +0 -0
{diffusers_workflow-0.4.0b4/diffusers_workflow.egg-info → diffusers_workflow-0.4.0b5}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diffusers-workflow
|
|
3
|
-
Version: 0.4.
|
|
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:
|
|
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
|
{diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5/diffusers_workflow.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diffusers-workflow
|
|
3
|
-
Version: 0.4.
|
|
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:
|
|
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
|
{diffusers_workflow-0.4.0b4 → diffusers_workflow-0.4.0b5}/diffusers_workflow.egg-info/SOURCES.txt
RENAMED
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
120
|
+
dw/server/ui/assets/handlebars-7APo_5hD.js
|
|
117
121
|
dw/server/ui/assets/hcl-CpzslTdj.js
|
|
118
|
-
dw/server/ui/assets/html-
|
|
122
|
+
dw/server/ui/assets/html-JgrkBemQ.js
|
|
119
123
|
dw/server/ui/assets/html.worker-C93Ht9o9.js
|
|
120
|
-
dw/server/ui/assets/htmlMode-
|
|
121
|
-
dw/server/ui/assets/index-
|
|
122
|
-
dw/server/ui/assets/index-
|
|
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-
|
|
129
|
+
dw/server/ui/assets/javascript-BrFJ1H6j.js
|
|
126
130
|
dw/server/ui/assets/json.worker-B2V3pomh.js
|
|
127
|
-
dw/server/ui/assets/jsonMode-
|
|
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-
|
|
133
|
-
dw/server/ui/assets/lspLanguageFeatures-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
182
|
+
dw/server/ui/assets/tsMode-BuMW6Qar.js
|
|
179
183
|
dw/server/ui/assets/twig-De2hgUGE.js
|
|
180
|
-
dw/server/ui/assets/typescript-
|
|
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-
|
|
185
|
-
dw/server/ui/assets/xml-
|
|
186
|
-
dw/server/ui/assets/yaml-
|
|
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
|
|
@@ -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(
|
|
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 =
|
|
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
|
-
|
|
939
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
1036
|
-
|
|
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.
|
|
416
|
-
client's own filesystem lets it (a full path, a directory, or
|
|
417
|
-
working directory by default, `~` expanded), the way a shell
|
|
418
|
-
would for the same user; a `..` path segment in `destination` is
|
|
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
|
|
135
|
-
MCP client
|
|
136
|
-
the
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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,
|
|
17
|
-
|
|
18
|
-
|
|
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")
|
|
33
|
-
var_name = validate_variable_name("bad;name")
|
|
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)
|
|
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
|