minimal-agent 0.9.0 → 0.10.0
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.
- package/README.md +11 -8
- package/package.json +34 -1
- package/plugins/cron-runner/.claude-plugin/plugin.json +5 -0
- package/plugins/cron-runner/commands/cron.md +26 -0
- package/plugins/cron-runner/commands/crons.md +7 -0
- package/plugins/cron-runner/plugin.js +34 -0
- package/plugins/cron-runner/src/commands.js +348 -0
- package/plugins/cron-runner/src/cronTime.js +148 -0
- package/plugins/cron-runner/src/lock.js +68 -0
- package/plugins/cron-runner/src/runs.js +89 -0
- package/plugins/cron-runner/src/scheduleEngine.js +72 -0
- package/plugins/cron-runner/src/scheduler.js +355 -0
- package/plugins/cron-runner/src/schema.js +140 -0
- package/plugins/cron-runner/src/service.js +167 -0
- package/plugins/cron-runner/src/store.js +298 -0
- package/plugins/cron-runner/src/types.js +1 -0
- package/plugins/workflow-runner/commands/workflow.md +4 -4
- package/plugins/workflow-runner/commands/workflows.md +1 -1
- package/plugins/workflow-runner/plugin.js +2 -1
- package/plugins/workflow-runner/src/agentCommon.js +172 -9
- package/plugins/workflow-runner/src/dslManifest.js +72 -0
- package/plugins/workflow-runner/src/expressions.js +150 -13
- package/plugins/workflow-runner/src/index.js +39 -8
- package/plugins/workflow-runner/src/loader.js +216 -64
- package/plugins/workflow-runner/src/multimodal.js +37 -0
- package/plugins/workflow-runner/src/recovery.js +26 -24
- package/plugins/workflow-runner/src/runner.js +693 -287
- package/plugins/workflow-runner/src/stepExecutors/agent.js +126 -37
- package/plugins/workflow-runner/src/stepExecutors/assert.js +3 -2
- package/plugins/workflow-runner/src/stepExecutors/llm.js +38 -30
- package/plugins/workflow-runner/src/stepExecutors/skill.js +27 -38
- package/plugins/workflow-runner/src/stepExecutors/tool.js +56 -3
- package/plugins/workflow-runner/src/stepExecutors/verify.js +19 -10
- package/plugins/workflow-runner/src/taskIdentity.js +185 -30
- package/plugins/workflow-runner/src/types.js +18 -7
- package/plugins/workflow-runner/src/workflowState.js +355 -55
- package/skills/ai-image/SKILL.md +89 -0
- package/skills/ai-image/scripts/generate.mjs +497 -0
- package/skills/ai-image/scripts/generate_from_plan.mjs +469 -0
- package/skills/ai-image/scripts/generate_from_plan_test.mjs +223 -0
- package/skills/ai-image/scripts/generate_test.mjs +74 -0
- package/skills/browser-automation/SKILL.md +47 -0
- package/skills/docx/SKILL.md +25 -3
- package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
- package/skills/docx/scripts/opc_check.py +253 -0
- package/skills/image-gen-openrouter/SKILL.md +10 -2
- package/skills/image-stats/SKILL.md +65 -0
- package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/image_stats.py +368 -0
- package/skills/image-stats/scripts/image_stats_test.py +181 -0
- package/skills/pptx/SKILL.md +123 -95
- package/skills/pptx/design.md +82 -0
- package/skills/pptx/examples/README.md +29 -0
- package/skills/pptx/examples/hybrid_example.mjs +107 -0
- package/skills/pptx/examples/hybrid_example.pptx +0 -0
- package/skills/pptx/pptxgenjs.md +41 -0
- package/skills/pptx/scripts/deck_helpers.mjs +224 -0
- package/skills/pptx/scripts/layout_lint.py +293 -0
- package/skills/pptx/scripts/layout_lint_test.py +160 -0
- package/skills/pptx/scripts/opc_check.py +339 -0
- package/skills/pptx/scripts/svg_fallback.mjs +145 -0
- package/skills/pptx/svg.md +67 -0
- package/skills/tts-zh/SKILL.md +19 -2
- package/skills/ui-design/SKILL.md +158 -0
- package/skills/ui-design/claude_design.md +309 -0
- package/skills/ui-design/evals/evals.json +254 -0
- package/skills/ui-design/references/aesthetic-direction.md +83 -0
- package/skills/ui-design/references/claude-design-protocol.md +36 -0
- package/skills/ui-design/references/design-context.md +53 -0
- package/skills/ui-design/references/design-execution-playbook.md +82 -0
- package/skills/ui-design/references/export-pptx.md +124 -0
- package/skills/ui-design/references/layout-composition.md +654 -0
- package/skills/ui-design/references/preview-feedback.md +37 -0
- package/skills/ui-design/references/source-image-layout.md +189 -0
- package/skills/ui-design/references/starter-components.md +78 -0
- package/skills/ui-design/references/vi-aegis-vector.md +144 -0
- package/skills/ui-design/references/vi-amber-prism.md +133 -0
- package/skills/ui-design/references/vi-aqua-glass.md +200 -0
- package/skills/ui-design/references/vi-comfort-vision.md +147 -0
- package/skills/ui-design/references/vi-ember-prism.md +140 -0
- package/skills/ui-design/references/vi-nebula-console.md +151 -0
- package/skills/ui-design/references/vi-obsidian-optics.md +139 -0
- package/skills/ui-design/references/vi-obsidian-xui.md +143 -0
- package/skills/ui-design/references/vi-precision-horizon-dark.md +117 -0
- package/skills/ui-design/references/vi-precision-horizon.md +215 -0
- package/skills/ui-design/references/vi-solar-relay.md +130 -0
- package/skills/ui-design/references/vi-template-workflow.md +48 -0
- package/skills/ui-design/references/vi-verdant-grid.md +141 -0
- package/skills/ui-design/references/vi-violet-meridian.md +172 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/assemble_material.py +217 -0
- package/skills/ui-design/scripts/assemble_material_test.py +149 -0
- package/skills/ui-design/scripts/browser_check_ui_artifact.mjs +221 -0
- package/skills/ui-design/scripts/chart_sanity_check.py +261 -0
- package/skills/ui-design/scripts/chart_sanity_check_test.py +165 -0
- package/skills/ui-design/scripts/check_language_policy.py +351 -0
- package/skills/ui-design/scripts/check_ui_artifact.py +435 -0
- package/skills/ui-design/scripts/check_ui_artifact_pptx_test.py +251 -0
- package/skills/ui-design/scripts/deck_pages_check.py +158 -0
- package/skills/ui-design/scripts/deck_pages_check_test.py +134 -0
- package/skills/ui-design/scripts/deck_visual_style_check.py +767 -0
- package/skills/ui-design/scripts/deck_visual_style_check_test.py +713 -0
- package/skills/ui-design/scripts/design_budget_check.py +271 -0
- package/skills/ui-design/scripts/design_budget_check_test.py +183 -0
- package/skills/ui-design/scripts/design_repair_hints.py +162 -0
- package/skills/ui-design/scripts/design_repair_hints_test.py +54 -0
- package/skills/ui-design/scripts/design_style_check.py +397 -0
- package/skills/ui-design/scripts/design_style_check_test.py +233 -0
- package/skills/ui-design/scripts/draft_coverage_check.py +184 -0
- package/skills/ui-design/scripts/draft_coverage_check_test.py +131 -0
- package/skills/ui-design/scripts/export_pptx_from_html.mjs +2367 -0
- package/skills/ui-design/scripts/extract_source_assets.py +607 -0
- package/skills/ui-design/scripts/extract_source_assets_test.py +256 -0
- package/skills/ui-design/scripts/generated_image_review_collect.py +206 -0
- package/skills/ui-design/scripts/generated_image_review_collect_test.py +91 -0
- package/skills/ui-design/scripts/image_plan_lint.py +571 -0
- package/skills/ui-design/scripts/image_plan_lint_test.py +515 -0
- package/skills/ui-design/scripts/image_prompt_rewrite.py +713 -0
- package/skills/ui-design/scripts/image_prompt_rewrite_test.py +966 -0
- package/skills/ui-design/scripts/layout_balance.py +881 -0
- package/skills/ui-design/scripts/layout_balance_test.py +927 -0
- package/skills/ui-design/scripts/normalize_design_json.py +272 -0
- package/skills/ui-design/scripts/normalize_design_json_test.py +119 -0
- package/skills/ui-design/scripts/plan_source_layout.py +1450 -0
- package/skills/ui-design/scripts/plan_source_layout_test.py +1136 -0
- package/skills/ui-design/scripts/resolve_source_input.py +270 -0
- package/skills/ui-design/scripts/resolve_source_input_test.py +98 -0
- package/skills/ui-design/scripts/scaffold_ui_artifact.py +377 -0
- package/skills/ui-design/scripts/source_usage_check.py +581 -0
- package/skills/ui-design/scripts/source_usage_check_test.py +427 -0
- package/skills/ui-design/scripts/text_readability_pixel.py +340 -0
- package/skills/ui-design/scripts/text_readability_pixel_test.py +219 -0
- package/skills/ui-design/scripts/visual_quality_gate.py +301 -0
- package/skills/ui-design/scripts/visual_quality_gate_test.py +233 -0
- package/skills/ui-design/tests/e2e/prompts/deck.md +19 -0
- package/skills/ui-design/tests/e2e/prompts/webpage.md +17 -0
- package/skills/ui-design/tests/e2e/render_check.mjs +101 -0
- package/skills/ui-design/tests/e2e/rubric.json +54 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/language-check.txt +12 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/static-check.txt +15 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/outputs/index.html +837 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/review.md +21 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/homepage.html +373 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/platform.html +378 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/outputs/index.html +656 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/render_check.mjs +67 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/outputs/index.html +587 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/review.md +36 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/language-check.txt +8 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/static-check.txt +16 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/outputs/index.html +739 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/prompt.md +11 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/review.md +22 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/checks/browser-check.json +52 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/outputs/index.html +641 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/outputs/index.html +467 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/homepage.html +373 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/platform.html +378 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/language-check.txt +4 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/execution_notes.md +10 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/outputs/index.html +587 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/prompt.md +14 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/review.md +13 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/browser-check.json +24 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/execution_notes.md +21 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/outputs/deck.html +451 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-01.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-02.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/review.md +79 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/browser-check.json +26 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/execution_notes.md +20 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/outputs/index.html +534 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/browser-check.json +64 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/language-check.txt +7 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-console.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-homepage.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/console.html +600 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/homepage.html +556 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/prompt.md +29 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/review.md +57 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/browser-check.json +33 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/language-check.txt +6 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/outputs/index.html +682 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/review.md +59 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-01.html +466 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-02.html +433 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/language-check.txt +3 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/execution_notes.md +24 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/outputs/index.html +723 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/prompt.md +15 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-dark.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-light.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/language-check.txt +11 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-dark.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-light.txt +3 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/execution_notes.md +23 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/dark.html +392 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/light.html +476 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/prompt.md +23 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/review.md +41 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/browser-check.json +54 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/language-check.txt +5 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/outputs/index.html +765 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/prompt.md +15 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/review.md +59 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/outputs/index.html +508 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/browser-check.json +54 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/language-check.txt +6 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/outputs/index.html +788 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/prompt.md +14 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/review.md +60 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/mobile.png +0 -0
- package/skills/video-compose/SKILL.md +8 -1
- package/skills/web-crawler/SKILL.md +70 -0
- package/skills/web-crawler/scripts/crawl.mjs +538 -0
- package/skills/web-crawler/scripts/crawl.test.mjs +204 -0
- package/skills/xlsx/SKILL.md +12 -0
- package/skills/xlsx/scripts/opc_check.py +253 -0
- package/src/advisorState.js +22 -0
- package/src/askBridge.js +87 -3
- package/src/bootstrap/workingDir.js +12 -1
- package/src/cli/args.js +17 -1
- package/src/cli/configMenu.js +236 -0
- package/src/cli/configWizard.js +7 -5
- package/src/cli/print.js +37 -4
- package/src/cli/streamJson.js +77 -24
- package/src/cli/wizards/advisorWizard.js +147 -0
- package/src/cli/wizards/fieldForm.js +149 -0
- package/src/cli/wizards/imageWizard.js +60 -0
- package/src/cli/wizards/openRouterWizard.js +23 -0
- package/src/cli/wizards/providerPresets.js +95 -0
- package/src/cli/wizards/providerWizard.js +219 -0
- package/src/cli/wizards/searchWizard.js +23 -0
- package/src/cli/wizards/ttsWizard.js +34 -0
- package/src/config/configFile.js +441 -83
- package/src/config/configService.js +446 -0
- package/src/config.js +24 -64
- package/src/context/agentHome.js +9 -0
- package/src/context/archive.js +3 -2
- package/src/context/compact.js +8 -5
- package/src/context/contextLock.js +81 -0
- package/src/context/persistContext.js +30 -11
- package/src/context/reactiveCompact.js +4 -2
- package/src/context/recentDirs.js +21 -61
- package/src/context/sessionPath.js +97 -23
- package/src/context/sessionRegistry.js +303 -24
- package/src/context/tokenCounter.js +18 -0
- package/src/context/workspaceIndex.js +731 -0
- package/src/infra/verification.js +3 -2
- package/src/llm/client.js +293 -206
- package/src/llm/providers/anthropicFormat.js +241 -0
- package/src/llm/providers/openaiFormat.js +190 -0
- package/src/loop.js +211 -27
- package/src/main.js +61 -11
- package/src/messageQueue.js +97 -0
- package/src/multimodal.js +203 -0
- package/src/plugin-sdk.js +15 -0
- package/src/plugins/commandRouter.js +3 -0
- package/src/plugins/hookEngine.js +5 -1
- package/src/plugins/pluginLifecycle.js +28 -0
- package/src/plugins/pluginRunner.js +40 -0
- package/src/plugins/transcript.js +4 -3
- package/src/prompts/pluginList.js +2 -2
- package/src/prompts/projectInstructions.js +3 -3
- package/src/prompts/promptAssembly.js +133 -109
- package/src/prompts/skillList.js +12 -22
- package/src/session/runAgentTurn.js +70 -0
- package/src/session/runTurn.js +41 -6
- package/src/toolGate.js +17 -0
- package/src/tools/advisor/advisor.js +379 -0
- package/src/tools/agent/agent.js +555 -0
- package/src/tools/agent/agentTypes.js +59 -0
- package/src/tools/agent/coordinator.js +93 -0
- package/src/tools/agent/worktree.js +270 -0
- package/src/tools/ask/ask.js +7 -2
- package/src/tools/bash/bash.js +112 -18
- package/src/tools/download/download.js +144 -0
- package/src/tools/edit/edit.js +1 -0
- package/src/tools/edit/multi-edit.js +1 -0
- package/src/tools/genimage/genimage.js +242 -0
- package/src/tools/genspeech/genspeech.js +67 -0
- package/src/tools/glob/glob.js +1 -0
- package/src/tools/grep/grep.js +3 -0
- package/src/tools/grep/rgPath.js +2 -0
- package/src/tools/index.js +25 -2
- package/src/tools/read/read.js +1 -0
- package/src/tools/shared/killTree.js +52 -0
- package/src/tools/toolProgressBridge.js +48 -0
- package/src/tools/webbrowser/agentBrowserPath.js +258 -0
- package/src/tools/webbrowser/browser.js +59 -42
- package/src/tools/webbrowser/browserControl.js +118 -0
- package/src/tools/webbrowser/browserDaemon.js +97 -0
- package/src/tools/webbrowser/browserService.js +27 -0
- package/src/tools/webbrowser/browserStream.js +119 -0
- package/src/tools/webbrowser/webbrowser.js +699 -130
- package/src/tools/webfetch/webfetch.js +1 -0
- package/src/tools/websearch/websearch.js +134 -51
- package/src/tools/write/write.js +1 -0
- package/src/ui/App.js +249 -22
- package/src/ui/AskQuestion.js +19 -17
- package/src/ui/InputBox.js +34 -9
- package/src/ui/LiveArea.js +112 -19
- package/src/ui/MessageList.js +100 -14
- package/src/ui/ModelPicker.js +56 -0
- package/src/ui/QueuedMessagesBanner.js +14 -0
- package/src/ui/Root.js +18 -10
- package/src/ui/SessionPicker.js +102 -0
- package/src/ui/StatusLine.js +13 -4
- package/src/ui/WorkspacePicker.js +55 -0
- package/src/ui/figures.js +44 -0
- package/src/ui/hooks/askSlot.js +82 -0
- package/src/ui/hooks/useChat.js +345 -64
- package/src/ui/hooks/usePasteHandler.js +11 -1
- package/src/ui/hooks/useTextBuffer.js +1 -3
- package/src/ui/liveViewport.js +5 -1
- package/src/ui/markdown.js +206 -0
- package/src/ui/textBuffer.js +0 -7
- package/src/ui/theme.js +32 -0
- package/src/utils/debugLog.js +0 -4
- package/src/utils/resourcePaths.js +2 -2
- package/src/utils/stripThink.js +50 -0
- package/src/web/browserBridge.js +447 -0
- package/src/web/protocol.js +19 -0
- package/workflows/adaptive-research.yaml +9 -2
- package/workflows/book-review-short.yaml +31 -7
- package/workflows/e2e-write-greet.yaml +3 -0
- package/workflows/illustrate.yaml +227 -0
- package/workflows/plan.yaml +437 -207
- package/workflows/ppt.yaml +1659 -0
- package/workflows/ralph-loop.yaml +142 -112
- package/workflows/schema.json +81 -23
- package/workflows/webppt.yaml +496 -0
- package/workflows/word.yaml +710 -0
- package/workflows/youtube-shorts.yaml +38 -10
- package/MINIMAL-TRACE.md +0 -77
- package/plugins/workflow-runner/src/voteHelpers.js +0 -110
- package/skills/config/SKILL.md +0 -123
- package/skills/frontend-design/LICENSE.txt +0 -177
- package/skills/frontend-design/SKILL.md +0 -42
- package/skills/pptx/scripts/office/__pycache__/soffice.cpython-314.pyc +0 -0
- package/src/ui/ProgressPanel.js +0 -54
- package/src/ui/StreamingBlock.js +0 -11
- package/src/ui/ToolStatus.js +0 -11
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
* 5. 中断后上下文完整:已完成的步骤全在 history 里,可继续/调整
|
|
14
14
|
*
|
|
15
15
|
* 与 llm 步的区别:
|
|
16
|
-
* - agent 有 maxTurns 上限(默认
|
|
16
|
+
* - agent 有 maxTurns 上限(默认 25),允许多轮工具调用
|
|
17
17
|
* - agent 的产出经过验证闸门(interpretMiniReActResult)
|
|
18
18
|
* - llm 只跑单轮 chat(maxTurns=1)
|
|
19
19
|
* ============================================================
|
|
20
20
|
*/
|
|
21
|
-
import {
|
|
22
|
-
import { interpolate } from '../expressions.js';
|
|
23
|
-
import {
|
|
21
|
+
import { describeCaptureContract, describeLlmFailure, describeMaxTurnsCutoff, effectiveGoalAnchor, interpretMiniReActResult, runStepQuery, } from '../agentCommon.js';
|
|
22
|
+
import { evalExpr, interpolate } from '../expressions.js';
|
|
23
|
+
import { resolveWorkflowMultimodalOptions } from '../multimodal.js';
|
|
24
24
|
/**
|
|
25
25
|
* 执行一个 agent 步骤:构造 step prompt → 委托 runQuery(TAOR) → 提取结果。
|
|
26
26
|
*
|
|
@@ -31,54 +31,143 @@ import { describeCaptureContract, interpretMiniReActResult, } from '../agentComm
|
|
|
31
31
|
* 4. yield UI 事件(text_delta / tool_start / tool_end / ...)
|
|
32
32
|
*/
|
|
33
33
|
export async function* execAgentStep(step, vars, ctx) {
|
|
34
|
-
|
|
34
|
+
// 默认 25(与 skill 步 skill.ts 对齐)。agent 步本就是「开放多工具任务」执行器,
|
|
35
|
+
// 弱模型常一轮只调一个工具(Read/Grep/Glob 各占一轮),旧默认 12 对探索类步骤
|
|
36
|
+
// (如 plan.yaml stage1_research)太紧——12 轮还没收集完就撞顶截断、误判失败。
|
|
37
|
+
// 这是安全阀不是性能阀;要更紧的步显式写小值即可。
|
|
38
|
+
const maxTurns = step.maxTurns ?? 25;
|
|
39
|
+
// 未定义变量插值可见化(裸 ${goal} 这类拼写/命名空间错的病根,静默空串会坑死下游)
|
|
40
|
+
const missing = [];
|
|
41
|
+
const iopts = { onMissing: (e) => missing.push(e) };
|
|
35
42
|
// 构造用户提示:包含步骤指令 + 变量 + capture 约束 + 内部标记防护
|
|
36
|
-
const userPrompt = interpolate(step.agent ?? '', vars)
|
|
37
|
-
describeCaptureContract(step) +
|
|
38
|
-
(step.input ? `\n\n上下文变量:${interpolate(step.input, vars)}` : '') +
|
|
39
|
-
'\n\n⚠️ 输出规范:直接输出你的工作成果即可,不要在输出中包含任何类似「放弃」、' +
|
|
40
|
-
'「GIVEUP」、' +
|
|
41
|
-
'「__AGENT__」或' +
|
|
42
|
-
'「[wf-internal」的内部标记文本。';
|
|
43
|
+
const userPrompt = `${interpolate(step.agent ?? '', vars, iopts)}${describeCaptureContract(step)}${step.input ? `\n\n上下文变量:${interpolate(step.input, vars, iopts)}` : ''}\n\n⚠️ 输出规范:直接输出你的工作成果即可,不要在输出中包含任何类似「放弃」、「GIVEUP」、「__AGENT__」或「[wf-internal」的内部标记文本。`;
|
|
43
44
|
// 如果有 output_schema,把 schema 约束嵌入 prompt(runQuery 不原生支持 responseFormat)
|
|
44
45
|
const schemaHint = step.output_schema
|
|
45
46
|
? `\n\n【结构化输出约束】请严格按照以下 JSON Schema 输出结果(不要包裹在 markdown 代码块中):\n${JSON.stringify(step.output_schema, null, 2)}`
|
|
46
47
|
: '';
|
|
47
48
|
const fullPrompt = userPrompt + schemaHint;
|
|
48
|
-
//
|
|
49
|
-
//
|
|
49
|
+
// 通用目标锚定(原始目标 + 累积的用户补充要求),前置注入 prompt。
|
|
50
|
+
// 确保每步 LLM 都能看到用户原始目标与运行中的补充要求,
|
|
50
51
|
// 避免长上下文 / fresh_context 导致目标被稀释或遗忘。
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
const anchor = effectiveGoalAnchor(ctx);
|
|
53
|
+
const effectivePrompt = anchor ? `${anchor}\n\n${fullPrompt}` : fullPrompt;
|
|
54
|
+
const multimodal = resolveWorkflowMultimodalOptions(step, vars, ctx, (e) => missing.push(e));
|
|
55
|
+
if (missing.length > 0) {
|
|
56
|
+
yield {
|
|
57
|
+
type: 'warning',
|
|
58
|
+
message: `step "${step.id}": 模板变量未定义,已按空串插值:${[...new Set(missing)].map((m) => `\${${m}}`).join('、')}(裸名请用 inputs.<name> 或先 capture/set)`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// 委托 TAOR 引擎执行(共享消费层 runStepQuery:携带 sessionState 以启用上下文压缩,
|
|
62
|
+
// 并统一侦测终结错误——runQuery 遇 LLM 失败是 yield error 后 return 不 throw)。
|
|
63
|
+
const { rawText, sawToolCall, toolNames, toolOkCount, toolFailCount, aborted, sawLlmError, sawMaxTurns, llmErrorDetail, } = yield* runStepQuery(effectivePrompt, step, ctx, {
|
|
61
64
|
maxTurns,
|
|
62
|
-
|
|
63
|
-
executeTool: ctx.executeTool,
|
|
64
|
-
sessionState: ctx.sessionState,
|
|
65
|
+
...multimodal,
|
|
65
66
|
});
|
|
66
|
-
// 从 history 中提取本步产生的最后一条 assistant message 内容(用于 capture 绑定)
|
|
67
|
-
let rawText = '';
|
|
68
|
-
for (let i = ctx.history.length - 1; i >= historyLenBefore; i--) {
|
|
69
|
-
const msg = ctx.history[i];
|
|
70
|
-
if (msg.role === 'assistant' && typeof msg.content === 'string' && msg.content.trim()) {
|
|
71
|
-
rawText = msg.content;
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// 验证闸门:判断结果是"真交付"还是"放弃"
|
|
76
67
|
const stepResult = {
|
|
77
68
|
raw: { text: rawText, result: rawText },
|
|
78
69
|
preview: rawText.length > 200 ? `${rawText.slice(0, 200)}...` : rawText,
|
|
79
70
|
};
|
|
71
|
+
// 用户中断导致的空产出:不过验证闸门(否则会误抛「放弃: 没有产出任何结果」),
|
|
72
|
+
// 直接返回当前(可能为空的)结果,由 runner 据 signal.aborted 收口(不当作可重试失败)。
|
|
73
|
+
if (aborted)
|
|
74
|
+
return stepResult;
|
|
75
|
+
// P0-1(同 llm.ts / skill.ts):LLM 失败(超时/网络错)且本步无任何产出 →
|
|
76
|
+
// 抛「可重试失败」交给 runner 的 in-run retry。必须在验证闸门之前——
|
|
77
|
+
// 否则 provider 故障会被闸门误归因为「agent 步骤放弃: 没有产出任何结果」,
|
|
78
|
+
// 混淆「provider 失败(该重试)」与「模型真放弃/空答(诚实 halt)」。
|
|
79
|
+
if (!rawText.trim() && sawLlmError) {
|
|
80
|
+
// 抛错文案附带 provider 真实报错(经 runner 落 progress.md,刷屏后仍可排障)
|
|
81
|
+
throw new Error(describeLlmFailure(step.id, llmErrorDetail));
|
|
82
|
+
}
|
|
83
|
+
// 撞 maxTurns 截断:截断时刻的文本是半截工作叙述,不是可信交付——
|
|
84
|
+
// 即使非空也不能过闸门(曾被静默当成功:半成品 PPTX 被整条链当真交付)。
|
|
85
|
+
// 抛可重试失败 → in-run retry 在共享 history 上续作(模型看到已有进度接着干)。
|
|
86
|
+
if (sawMaxTurns) {
|
|
87
|
+
throw new Error(describeMaxTurnsCutoff(step.id, maxTurns));
|
|
88
|
+
}
|
|
89
|
+
// done_when 验收兜底(K3/A2):弱模型常「宣告要干活」却不调工具就 end_turn
|
|
90
|
+
//(announce-not-do,2026-06-12 plan 工作流实跑事故的执行步烂尾根因之一)。
|
|
91
|
+
// yaml 作者声明确定性完成条件(如 fileExists('./doc/x.pptx')),不满足时
|
|
92
|
+
// 引擎自动 nudge 同一 agent 在共享 history 上继续干(看得到自己刚才的半截工作),
|
|
93
|
+
// 把「对抗模型不可靠」从每个 yaml 的 prompt 工程收回引擎单点。
|
|
94
|
+
if (step.done_when) {
|
|
95
|
+
const NUDGES = 2; // 提醒上限:超过说明模型真干不动,交给 onError/max_retries
|
|
96
|
+
let result = resultIfTextLooksDeliverable(step, rawText);
|
|
97
|
+
let lastOutcome = {
|
|
98
|
+
rawText,
|
|
99
|
+
sawToolCall,
|
|
100
|
+
toolNames,
|
|
101
|
+
toolOkCount,
|
|
102
|
+
toolFailCount,
|
|
103
|
+
};
|
|
104
|
+
for (let n = 0;; n++) {
|
|
105
|
+
if (evalDoneWhen(step, vars)) {
|
|
106
|
+
return result ?? doneWhenSatisfiedResult(step);
|
|
107
|
+
}
|
|
108
|
+
if (n >= NUDGES) {
|
|
109
|
+
throw new Error(`agent 步骤 "${step.id}" 完成条件未满足(done_when: ${step.done_when}),已提醒 ${NUDGES} 次仍未达成。${describeAttemptForDoneWhen(lastOutcome)}`);
|
|
110
|
+
}
|
|
111
|
+
yield {
|
|
112
|
+
type: 'warning',
|
|
113
|
+
message: `⏩ step "${step.id}" 完成条件未满足(${step.done_when}),提醒 agent 继续执行(第 ${n + 1}/${NUDGES} 次)。${describeAttemptForDoneWhen(lastOutcome)}`,
|
|
114
|
+
};
|
|
115
|
+
const nudge = yield* runStepQuery(`检查发现这一步还没有真正完成:完成条件 \`${step.done_when}\` 仍不成立。不要解释、不要宣告计划——继续实际执行(调用工具落盘/操作),直到完成条件成立,然后给出简短完成报告。`, step, ctx, { maxTurns });
|
|
116
|
+
if (nudge.aborted)
|
|
117
|
+
return result ?? stepResult;
|
|
118
|
+
if (!nudge.rawText.trim() && nudge.sawLlmError) {
|
|
119
|
+
throw new Error(describeLlmFailure(step.id, nudge.llmErrorDetail));
|
|
120
|
+
}
|
|
121
|
+
if (nudge.sawMaxTurns) {
|
|
122
|
+
throw new Error(describeMaxTurnsCutoff(step.id, maxTurns));
|
|
123
|
+
}
|
|
124
|
+
lastOutcome = nudge;
|
|
125
|
+
if (nudge.rawText.trim()) {
|
|
126
|
+
result = resultIfTextLooksDeliverable(step, nudge.rawText) ?? result;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// 验证闸门:判断结果是"真交付"还是"放弃"。注意:带 done_when 的步骤已在上方
|
|
131
|
+
// 由确定性条件验收,避免"文件已落盘但最终空文本"或"还没落盘但空文本"绕过 nudge。
|
|
80
132
|
const outcome = interpretMiniReActResult(stepResult, !!step.output_schema);
|
|
81
133
|
if (!outcome.ok)
|
|
82
134
|
throw new Error(`agent 步骤放弃: ${outcome.reason}`);
|
|
83
135
|
return outcome.value;
|
|
84
136
|
}
|
|
137
|
+
function evalDoneWhen(step, vars) {
|
|
138
|
+
try {
|
|
139
|
+
return Boolean(evalExpr(step.done_when ?? '', vars));
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
// 表达式坏了是 yaml 作者错误:响亮失败(同 max_iterations 解析失败哲学),
|
|
143
|
+
// 不能静默当 false 把好结果 nudge 死、也不能静默当 true 放走烂尾。
|
|
144
|
+
throw new Error(`step "${step.id}" 的 done_when 表达式求值失败: ${e.message}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function doneWhenSatisfiedResult(step) {
|
|
148
|
+
const text = `完成条件已满足:${step.done_when}`;
|
|
149
|
+
return { raw: { text, result: text, content: text }, preview: text };
|
|
150
|
+
}
|
|
151
|
+
function resultIfTextLooksDeliverable(step, text) {
|
|
152
|
+
if (!text.trim())
|
|
153
|
+
return null;
|
|
154
|
+
const outcome = interpretMiniReActResult({
|
|
155
|
+
raw: { text, result: text },
|
|
156
|
+
preview: text.length > 200 ? `${text.slice(0, 200)}...` : text,
|
|
157
|
+
}, !!step.output_schema);
|
|
158
|
+
return outcome.ok ? outcome.value : null;
|
|
159
|
+
}
|
|
160
|
+
function describeAttemptForDoneWhen(outcome) {
|
|
161
|
+
const textState = outcome.rawText.trim()
|
|
162
|
+
? '本轮有文本报告'
|
|
163
|
+
: '本轮没有文本报告';
|
|
164
|
+
if (!outcome.sawToolCall) {
|
|
165
|
+
return `${textState},且没有观察到工具调用;请不要只宣告计划,必须调用工具完成产物。`;
|
|
166
|
+
}
|
|
167
|
+
const names = outcome.toolNames.length ? outcome.toolNames.join('、') : '未知工具';
|
|
168
|
+
const wrote = outcome.toolNames.some((name) => ['Write', 'Edit', 'MultiEdit', 'Bash'].includes(name));
|
|
169
|
+
const writeHint = wrote
|
|
170
|
+
? '已观察到写入类工具调用,但完成条件仍未满足,请检查路径或实际写入结果'
|
|
171
|
+
: '未观察到写入类工具调用,请立即调用 Write/Edit/Bash 落盘产物';
|
|
172
|
+
return `${textState};本轮工具调用:${names}(成功 ${outcome.toolOkCount},失败 ${outcome.toolFailCount})。${writeHint}。`;
|
|
173
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================
|
|
3
|
-
* src/
|
|
3
|
+
* plugins/workflow-runner/src/stepExecutors/assert.ts —— assert step 执行
|
|
4
4
|
* ------------------------------------------------------------
|
|
5
5
|
* evalExpr(condition) → 真值通过;假值抛错(带 onFail 自定义信息)。
|
|
6
6
|
*
|
|
@@ -28,7 +28,8 @@ export function execAssertStep(step, vars, ctx) {
|
|
|
28
28
|
}
|
|
29
29
|
// ════ v0.9.3:上下文统一 —— assert 通过也留痕 ════
|
|
30
30
|
// 让后续 LLM 步骤知道某个前置条件/不变量已确认满足。
|
|
31
|
-
|
|
31
|
+
// ctx 必填(签名强制,runner 唯一调用点 dispatchActionStep 始终传),直接访问 history。
|
|
32
|
+
if (ctx.history) {
|
|
32
33
|
ctx.history.push({
|
|
33
34
|
role: 'assistant',
|
|
34
35
|
content: `[workflow:${step.id}] ✅ 断言通过:${step.condition}`,
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* (runQuery / src/loop.ts)执行。
|
|
7
7
|
*
|
|
8
8
|
* 与 agent 步的区别:
|
|
9
|
-
* - llm 默认单轮(maxTurns=1
|
|
10
|
-
* - 有 context_files 时允许少量轮次读取文件后输出
|
|
9
|
+
* - llm 默认单轮(maxTurns=1),不下发工具
|
|
10
|
+
* - 有 context_files 或 allowed_tools 时允许少量轮次读取文件后输出
|
|
11
11
|
* - output_schema 嵌入 prompt 作为结构化约束
|
|
12
12
|
* - 不经过 interpretMiniReActResult 验证闸门(直接信任 LLM 输出)
|
|
13
13
|
*
|
|
@@ -16,19 +16,23 @@
|
|
|
16
16
|
* - `{ <field>: var_name }` 当 output_schema 存在时按 JSON 字段取值
|
|
17
17
|
* ============================================================
|
|
18
18
|
*/
|
|
19
|
-
import {
|
|
20
|
-
import { extractJsonPayload } from '../jsonPayload.js';
|
|
19
|
+
import { describeLlmFailure, describeMaxTurnsCutoff, effectiveGoalAnchor, runStepQuery, } from '../agentCommon.js';
|
|
21
20
|
import { interpolate } from '../expressions.js';
|
|
21
|
+
import { extractJsonPayload } from '../jsonPayload.js';
|
|
22
|
+
import { resolveWorkflowMultimodalOptions } from '../multimodal.js';
|
|
22
23
|
export async function* execLlmStep(step, vars, ctx) {
|
|
23
24
|
if (typeof step.llm !== 'string')
|
|
24
25
|
throw new Error(`step ${step.id}: 缺少 llm 字段`);
|
|
25
|
-
|
|
26
|
+
// 未定义变量插值可见化(静默空串是下游 prompt 留白的病根)
|
|
27
|
+
const missing = [];
|
|
28
|
+
const iopts = { onMissing: (e) => missing.push(e) };
|
|
29
|
+
const prompt = interpolate(step.llm, vars, iopts);
|
|
26
30
|
// 有 context_files → 在 prompt 中附上文件列表,runQuery 的 TAOR 循环中
|
|
27
31
|
// 模型可自主用 Read 工具读取(ALL_TOOLS 全量可用)
|
|
28
32
|
let fullPrompt = prompt;
|
|
29
33
|
if (step.context_files && step.context_files.length > 0) {
|
|
30
34
|
const fileList = step.context_files
|
|
31
|
-
.map((f) => `- ${interpolate(f.path, vars)}${f.hint ? ` — ${f.hint}` : ''}`)
|
|
35
|
+
.map((f) => `- ${interpolate(f.path, vars, iopts)}${f.hint ? ` — ${f.hint}` : ''}`)
|
|
32
36
|
.join('\n');
|
|
33
37
|
fullPrompt = `${prompt}\n\n**以下上下文文件可用,请用 Read 工具按需读取**:\n${fileList}`;
|
|
34
38
|
}
|
|
@@ -37,34 +41,38 @@ export async function* execLlmStep(step, vars, ctx) {
|
|
|
37
41
|
? `\n\n【结构化输出约束】请严格按照以下 JSON Schema 输出有效 JSON 对象本身(不要 markdown 代码块包裹):\n${JSON.stringify(step.output_schema, null, 2)}`
|
|
38
42
|
: '';
|
|
39
43
|
fullPrompt += schemaHint;
|
|
40
|
-
//
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
// 通用目标锚定(原始目标 + 补充要求):同 agent.ts,确保每步 LLM 不偏离
|
|
45
|
+
const anchor = effectiveGoalAnchor(ctx);
|
|
46
|
+
const effectivePrompt = anchor ? `${anchor}\n\n${fullPrompt}` : fullPrompt;
|
|
47
|
+
const needsTools = !!step.context_files?.length || step.allowed_tools !== undefined;
|
|
48
|
+
const queryStep = needsTools ? step : { ...step, allowed_tools: [] };
|
|
49
|
+
// llm 步默认单轮;需要工具时允许多轮(读文件→输出)
|
|
45
50
|
const maxTurns = step.maxTurns ?? (step.context_files?.length ? 10 : 1);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const multimodal = resolveWorkflowMultimodalOptions(step, vars, ctx, (e) => missing.push(e));
|
|
52
|
+
if (missing.length > 0) {
|
|
53
|
+
yield {
|
|
54
|
+
type: 'warning',
|
|
55
|
+
message: `step "${step.id}": 模板变量未定义,已按空串插值:${[...new Set(missing)].map((m) => `\${${m}}`).join('、')}(裸名请用 inputs.<name> 或先 capture/set)`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// 委托 TAOR 引擎执行(共享消费层 runStepQuery:携带 sessionState 以启用上下文压缩,
|
|
59
|
+
// 并统一侦测终结错误——runQuery 遇 LLM 失败是 yield error 后 return 不 throw,
|
|
60
|
+
// 直透会让本步静默返回空文本、runner 的 in-run retry 不触发 → 产出空如空 PLAN.md)。
|
|
61
|
+
const { rawText, aborted, sawLlmError, sawMaxTurns, llmErrorDetail } = yield* runStepQuery(effectivePrompt, queryStep, ctx, {
|
|
53
62
|
maxTurns,
|
|
54
|
-
|
|
55
|
-
executeTool: ctx.executeTool,
|
|
56
|
-
sessionState: ctx.sessionState,
|
|
63
|
+
...multimodal,
|
|
57
64
|
});
|
|
58
|
-
// 从 history 提取本步最后一条 assistant 消息
|
|
59
|
-
let rawText = '';
|
|
60
|
-
for (let i = ctx.history.length - 1; i >= historyLenBefore; i--) {
|
|
61
|
-
const msg = ctx.history[i];
|
|
62
|
-
if (msg.role === 'assistant' && typeof msg.content === 'string' && msg.content.trim()) {
|
|
63
|
-
rawText = msg.content;
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
65
|
const trimmed = rawText.trim();
|
|
66
|
+
// P0-1:LLM 失败(超时/网络错)且本步无任何产出 → 抛异常,触发 runner 的 max_retries 重跑。
|
|
67
|
+
// 必须放在 output_schema 解析之前(空文本本就无法解析),且只在 !aborted 时抛
|
|
68
|
+
// (用户中断不该被当成可重试失败;aborted 时按现状返回空结果即可)。
|
|
69
|
+
if (!trimmed && sawLlmError && !aborted) {
|
|
70
|
+
throw new Error(describeLlmFailure(step.id, llmErrorDetail));
|
|
71
|
+
}
|
|
72
|
+
// 撞 maxTurns 截断 → 截断时产出不可信,抛可重试失败(续作语义,同 agent.ts)
|
|
73
|
+
if (sawMaxTurns && !aborted) {
|
|
74
|
+
throw new Error(describeMaxTurnsCutoff(step.id, maxTurns));
|
|
75
|
+
}
|
|
68
76
|
// 结构化输出模式:解析 JSON
|
|
69
77
|
if (step.output_schema) {
|
|
70
78
|
const payload = extractJsonPayload(trimmed);
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { readdir, readFile } from 'node:fs/promises';
|
|
19
19
|
import { join } from 'node:path';
|
|
20
|
-
import { runQuery } from '../../../../src/loop.js';
|
|
21
20
|
import { getResourceSearchPaths } from '../../../../src/plugin-sdk.js';
|
|
21
|
+
import { describeLlmFailure, describeMaxTurnsCutoff, effectiveGoalAnchor, runStepQuery, } from '../agentCommon.js';
|
|
22
22
|
import { interpolate } from '../expressions.js';
|
|
23
23
|
function stripFrontmatter(content) {
|
|
24
24
|
return content.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
@@ -33,10 +33,7 @@ function parseFrontmatterName(content) {
|
|
|
33
33
|
return nm[1].trim().replace(/^["']|["']$/g, '');
|
|
34
34
|
}
|
|
35
35
|
async function findSkillFile(skillName, cwd) {
|
|
36
|
-
const roots = getResourceSearchPaths('skills', import.meta.url);
|
|
37
|
-
// 优先搜索 cwd/skills(工作目录下的 skills 优先于包内 skills)
|
|
38
|
-
const cwdSkills = join(cwd, 'skills');
|
|
39
|
-
roots.unshift(cwdSkills);
|
|
36
|
+
const roots = getResourceSearchPaths('skills', import.meta.url, cwd);
|
|
40
37
|
for (const root of roots) {
|
|
41
38
|
let entries;
|
|
42
39
|
try {
|
|
@@ -76,46 +73,38 @@ export async function* execSkillStep(step, vars, ctx) {
|
|
|
76
73
|
// 构造用户提示:skill 指令 + 步骤 input
|
|
77
74
|
// 系统提示词已在 history[0] 中(含完整 skill 列表和描述),
|
|
78
75
|
// 这里不需要再拼 system message——把 SKILL.md body 作为操作指令即可
|
|
76
|
+
const missing = [];
|
|
79
77
|
const userInput = step.input
|
|
80
|
-
? interpolate(step.input, vars)
|
|
78
|
+
? interpolate(step.input, vars, { onMissing: (e) => missing.push(e) })
|
|
81
79
|
: `请按以下 SKILL "${skillName}" 的指示完成任务。`;
|
|
82
80
|
const fullPrompt = `【执行 Skill:${skillName}】\n\n${body}\n\n---\n\n当前任务:\n${userInput}`;
|
|
83
|
-
//
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
: fullPrompt;
|
|
81
|
+
// 通用目标锚定(原始目标 + 补充要求):确保 skill 执行时也不偏离
|
|
82
|
+
const anchor = effectiveGoalAnchor(ctx);
|
|
83
|
+
const effectivePrompt = anchor ? `${anchor}\n\n${fullPrompt}` : fullPrompt;
|
|
87
84
|
const maxTurns = step.maxTurns ?? 25;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
85
|
+
if (missing.length > 0) {
|
|
86
|
+
yield {
|
|
87
|
+
type: 'warning',
|
|
88
|
+
message: `step "${step.id}": 模板变量未定义,已按空串插值:${[...new Set(missing)].map((m) => `\${${m}}`).join('、')}(裸名请用 inputs.<name> 或先 capture/set)`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// 委托 TAOR 引擎在共享 history 上执行(共享消费层 runStepQuery)。
|
|
92
|
+
// suppressTurnDone:turn_done 是 runQuery 单次调用的终结标记,不是 workflow 终结,
|
|
93
|
+
// 外泄会导致 gateway broker / -p json 模式误判 workflow 中途结束。
|
|
94
|
+
const { rawText, aborted, sawLlmError, sawMaxTurns, llmErrorDetail } = yield* runStepQuery(effectivePrompt, step, ctx, {
|
|
97
95
|
maxTurns,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
continue;
|
|
106
|
-
// error / interrupted 应该冒泡让 runner 处理
|
|
107
|
-
yield ev;
|
|
96
|
+
suppressTurnDone: true,
|
|
97
|
+
});
|
|
98
|
+
const trimmed = rawText.trim();
|
|
99
|
+
// P0-1:LLM 失败(超时/网络错)且本步无任何产出 → 抛异常,触发 runner 的 max_retries 重跑。
|
|
100
|
+
// 用户中断(aborted)不该被当成可重试失败,按现状返回空结果即可。
|
|
101
|
+
if (!trimmed && sawLlmError && !aborted) {
|
|
102
|
+
throw new Error(describeLlmFailure(step.id, llmErrorDetail));
|
|
108
103
|
}
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const msg = ctx.history[i];
|
|
113
|
-
if (msg.role === 'assistant' && typeof msg.content === 'string' && msg.content.trim()) {
|
|
114
|
-
rawText = msg.content;
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
104
|
+
// 撞 maxTurns 截断 → 截断时产出不可信,抛可重试失败(续作语义,同 agent.ts)
|
|
105
|
+
if (sawMaxTurns && !aborted) {
|
|
106
|
+
throw new Error(describeMaxTurnsCutoff(step.id, maxTurns));
|
|
117
107
|
}
|
|
118
|
-
const trimmed = rawText.trim();
|
|
119
108
|
return {
|
|
120
109
|
raw: { text: trimmed, result: trimmed },
|
|
121
110
|
preview: trimmed.length > 200 ? `${trimmed.slice(0, 200)}...` : trimmed,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================
|
|
3
|
-
* src/
|
|
3
|
+
* plugins/workflow-runner/src/stepExecutors/tool.ts —— tool step 执行
|
|
4
4
|
* ------------------------------------------------------------
|
|
5
5
|
* 把 step.args 递归 ${var} 插值后 JSON.stringify,转发到 executeTool。
|
|
6
6
|
* 失败(ok=false)抛 Error,让 runner 走 onError 处理。
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
* - `{ args.<任意字段>: var_name }` 绑入参的具名字段
|
|
22
22
|
* ============================================================
|
|
23
23
|
*/
|
|
24
|
-
import {
|
|
24
|
+
import { existsSync } from 'node:fs';
|
|
25
|
+
import { resolve } from 'node:path';
|
|
26
|
+
import { executeTool, getToolByName, recordRead, } from '../../../../src/plugin-sdk.js';
|
|
25
27
|
import { interpolateDeep } from '../expressions.js';
|
|
26
28
|
export async function* execToolStep(step, vars, ctx) {
|
|
27
29
|
if (!step.tool)
|
|
@@ -29,7 +31,17 @@ export async function* execToolStep(step, vars, ctx) {
|
|
|
29
31
|
const tool = getToolByName(step.tool);
|
|
30
32
|
if (!tool)
|
|
31
33
|
throw new Error(`step ${step.id}: 未知工具 "${step.tool}"`);
|
|
32
|
-
|
|
34
|
+
// 未定义变量插值可见化(args 里静默空串会让工具拿到空路径/空内容)
|
|
35
|
+
const missing = [];
|
|
36
|
+
const args = interpolateDeep(step.args ?? {}, vars, {
|
|
37
|
+
onMissing: (e) => missing.push(e),
|
|
38
|
+
});
|
|
39
|
+
if (missing.length > 0) {
|
|
40
|
+
yield {
|
|
41
|
+
type: 'warning',
|
|
42
|
+
message: `step "${step.id}": 模板变量未定义,已按空串插值:${[...new Set(missing)].map((m) => `\${${m}}`).join('、')}(裸名请用 inputs.<name> 或先 capture/set)`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
33
45
|
const argsJson = JSON.stringify(args);
|
|
34
46
|
const toolCallId = `wf_${step.id}`;
|
|
35
47
|
const argsPreview = argsJson.length > 80 ? `${argsJson.slice(0, 80)}…` : argsJson;
|
|
@@ -40,6 +52,14 @@ export async function* execToolStep(step, vars, ctx) {
|
|
|
40
52
|
argsPreview,
|
|
41
53
|
argsFriendly: friendlyToolDesc(tool.name, args),
|
|
42
54
|
};
|
|
55
|
+
// ════ 声明产物覆盖判定(解 Write/Edit 的 pre-read 守卫) ════
|
|
56
|
+
// 内核写类工具有「文件已存在必须先 Read」守卫(fileState 进程级 Map,
|
|
57
|
+
// 跨进程 / resume / 残留旧产物时必空)。确定性 tool 步的 args 是 yaml 作者
|
|
58
|
+
// 写死的,模型没有机会先 Read —— 目标文件若是工作流**声明的产物**
|
|
59
|
+
// (def 级 + step 级 artifacts:,= 工作流自己拥有、本就要覆盖的文件),
|
|
60
|
+
// 这里自动 pre-Read 一次解除守卫(管线动作,不 yield 事件、结果丢弃)。
|
|
61
|
+
// 非声明产物的盲写保护原样生效;pre-Read 失败也不拦,让写工具自己报错。
|
|
62
|
+
await preReadDeclaredArtifact(tool, args, step, ctx);
|
|
43
63
|
const result = await executeTool(tool.name, argsJson, ctx.signal);
|
|
44
64
|
yield {
|
|
45
65
|
type: 'tool_end',
|
|
@@ -70,6 +90,39 @@ export async function* execToolStep(step, vars, ctx) {
|
|
|
70
90
|
preview: content.length > 200 ? `${content.slice(0, 200)}...` : content,
|
|
71
91
|
};
|
|
72
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* 写类 tool 步的目标文件若命中声明产物且已存在 → pre-Read 解除内核守卫。
|
|
95
|
+
*
|
|
96
|
+
* 路径归一化:artifacts 声明相对 cwd;args.file_path 可能是 ./相对 或 绝对,
|
|
97
|
+
* 双方都 resolve(cwd, …) 后比较(win32 文件系统大小写不敏感 → lowercase 比较;
|
|
98
|
+
* 其余平台保持大小写敏感,避免 Plan.md / plan.md 误判同文件)。
|
|
99
|
+
*/
|
|
100
|
+
async function preReadDeclaredArtifact(tool, args, step, ctx) {
|
|
101
|
+
if (tool.isReadOnly !== false)
|
|
102
|
+
return; // 只对写类工具生效
|
|
103
|
+
if (typeof args.file_path !== 'string')
|
|
104
|
+
return;
|
|
105
|
+
const norm = (p) => {
|
|
106
|
+
const abs = resolve(ctx.cwd, p);
|
|
107
|
+
return process.platform === 'win32' ? abs.toLowerCase() : abs;
|
|
108
|
+
};
|
|
109
|
+
const target = norm(args.file_path);
|
|
110
|
+
const declared = [...(ctx.declaredArtifacts ?? []), ...(step.artifacts ?? [])];
|
|
111
|
+
if (!declared.some((a) => norm(a) === target))
|
|
112
|
+
return;
|
|
113
|
+
const abs = resolve(ctx.cwd, args.file_path);
|
|
114
|
+
if (!existsSync(abs))
|
|
115
|
+
return; // 新建文件不需要解守卫
|
|
116
|
+
// 直接登记一次「完整已读」状态解除内核 pre-read 守卫——不真正 Read 内容:
|
|
117
|
+
// 1. 声明产物本就要被本步整体覆盖,旧内容无需进上下文/烧 token;
|
|
118
|
+
// 2. 真 Read 大文件会触发字符上限截断(read.ts → recordRead({truncated:true})),
|
|
119
|
+
// 反而踩中 Write 的「截断禁写」硬守卫(write.ts: existsSync && wasTruncated → 拒绝),
|
|
120
|
+
// 正是本步要解除的同一道墙——曾导致 plan.yaml 回写变长的 PLAN.md 时 halt
|
|
121
|
+
// (首轮新建 PLAN.md 不存在直接放行,审批反馈后回写已存在的大 PLAN.md 被挡死)。
|
|
122
|
+
// 两道守卫(never-read + truncated)必须一并解除,声明产物的整体覆盖才算真正授权。
|
|
123
|
+
// recordRead 内部自带 statSync 失败兜底(返回 1、不抛),无需再包 try/catch。
|
|
124
|
+
recordRead(abs, { truncated: false });
|
|
125
|
+
}
|
|
73
126
|
/**
|
|
74
127
|
* 给 tool_start 生成人话描述(LiveArea spinner 行用)。
|
|
75
128
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================
|
|
3
|
-
* stepExecutors/verify.ts —— verify step 执行
|
|
3
|
+
* plugins/workflow-runner/src/stepExecutors/verify.ts —— verify step 执行
|
|
4
4
|
* ------------------------------------------------------------
|
|
5
|
-
*
|
|
5
|
+
* 复用内核共享验证基础设施(经 plugin-sdk 门面取 runVerification/parseCheckString),
|
|
6
6
|
* 支持 shell / file_exists / file_contains / test_count 四种检查。
|
|
7
7
|
*
|
|
8
8
|
* 与 assert 的区别:
|
|
@@ -10,27 +10,36 @@
|
|
|
10
10
|
* - verify: 完整检查器(重量,支持命令执行/正则匹配/测试计数)
|
|
11
11
|
* ============================================================
|
|
12
12
|
*/
|
|
13
|
-
import { parseCheckString, runVerification } from '../../../../src/
|
|
13
|
+
import { parseCheckString, runVerification } from '../../../../src/plugin-sdk.js';
|
|
14
14
|
import { interpolate } from '../expressions.js';
|
|
15
15
|
export async function execVerifyStep(step, vars) {
|
|
16
|
-
// 兼容两种格式:YAML 数组
|
|
16
|
+
// 兼容两种格式:YAML 数组 或逗号分隔字符串。
|
|
17
|
+
// 关键:【先插值再按逗号分割】。checks 可能是 "${verify_checks}" 这类模板,插值后才
|
|
18
|
+
// 展开成逗号分隔的多项(如 "shell:bun test,file_exists:x")。若先分割再插值,整段模板
|
|
19
|
+
// 会被当成一项,解析时 value 混入逗号、多项检查失效(ralph-loop 的 run_verify 即如此)。
|
|
17
20
|
let rawChecks;
|
|
18
21
|
if (Array.isArray(step.checks) && step.checks.length > 0) {
|
|
19
|
-
rawChecks = step.checks
|
|
22
|
+
rawChecks = step.checks
|
|
23
|
+
.flatMap((s) => interpolate(s, vars).split(','))
|
|
24
|
+
.map((s) => s.trim())
|
|
25
|
+
.filter(Boolean);
|
|
20
26
|
}
|
|
21
27
|
else if (typeof step.checks === 'string' && step.checks.trim() !== '') {
|
|
22
|
-
rawChecks = step.checks
|
|
28
|
+
rawChecks = interpolate(step.checks, vars)
|
|
29
|
+
.split(',')
|
|
30
|
+
.map((s) => s.trim())
|
|
31
|
+
.filter(Boolean);
|
|
23
32
|
}
|
|
24
33
|
else {
|
|
25
34
|
throw new Error(`step ${step.id}: verify 缺少 checks(需要数组或逗号分隔字符串)`);
|
|
26
35
|
}
|
|
27
|
-
//
|
|
36
|
+
// 解析每条已插值的 check 字符串(插值后若整体为空——如 ${verify_checks} 取到空串——
|
|
37
|
+
// 则 checks 为空,runVerification 视为"无检查项"通过;ralph-loop 另有 when 守卫不会走到这)
|
|
28
38
|
const checks = [];
|
|
29
39
|
for (const raw of rawChecks) {
|
|
30
|
-
const
|
|
31
|
-
const check = parseCheckString(interpolated);
|
|
40
|
+
const check = parseCheckString(raw);
|
|
32
41
|
if (!check) {
|
|
33
|
-
throw new Error(`step ${step.id}: 无法解析 check "${
|
|
42
|
+
throw new Error(`step ${step.id}: 无法解析 check "${raw}",格式应为 "type:value"`);
|
|
34
43
|
}
|
|
35
44
|
checks.push(check);
|
|
36
45
|
}
|