minimal-agent 0.12.0 → 0.14.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 +6 -5
- package/package.json +62 -5
- package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
- package/plugins/cron-runner/src/commands.js +4 -4
- package/plugins/cron-runner/src/commands.ts +4 -4
- package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
- package/plugins/workflow-runner/commands/workflow.md +57 -90
- package/plugins/workflow-runner/commands/workflows.md +4 -4
- package/plugins/workflow-runner/plugin.js +24 -13
- package/plugins/workflow-runner/plugin.ts +28 -13
- package/plugins/workflow-runner/src/discovery.js +160 -0
- package/plugins/workflow-runner/src/discovery.ts +194 -0
- package/plugins/workflow-runner/src/goalAnchor.js +53 -0
- package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
- package/plugins/workflow-runner/src/index.js +204 -185
- package/plugins/workflow-runner/src/index.ts +249 -224
- package/plugins/workflow-runner/src/inputCoercion.js +40 -0
- package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
- package/plugins/workflow-runner/src/journal.js +224 -0
- package/plugins/workflow-runner/src/journal.ts +274 -0
- package/plugins/workflow-runner/src/jsonSchema.js +132 -0
- package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
- package/plugins/workflow-runner/src/moduleResolution.js +64 -0
- package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
- package/plugins/workflow-runner/src/resourceInputs.js +220 -0
- package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
- package/plugins/workflow-runner/src/runner.js +404 -467
- package/plugins/workflow-runner/src/runner.ts +491 -535
- package/plugins/workflow-runner/src/runtime/config.js +46 -0
- package/plugins/workflow-runner/src/runtime/config.ts +69 -0
- package/plugins/workflow-runner/src/runtime/context.js +1304 -0
- package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
- package/plugins/workflow-runner/src/runtime/exec.js +34 -0
- package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
- package/plugins/workflow-runner/src/runtime/flow.js +8 -0
- package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
- package/plugins/workflow-runner/src/runtime/fs.js +27 -0
- package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
- package/plugins/workflow-runner/src/runtime/model.js +6 -0
- package/plugins/workflow-runner/src/runtime/model.ts +8 -0
- package/plugins/workflow-runner/src/runtime/output.js +7 -0
- package/plugins/workflow-runner/src/runtime/output.ts +21 -0
- package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
- package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
- package/plugins/workflow-runner/src/runtime/state.js +16 -0
- package/plugins/workflow-runner/src/runtime/state.ts +19 -0
- package/plugins/workflow-runner/src/runtime/tools.js +3 -0
- package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
- package/plugins/workflow-runner/src/sandbox.js +141 -0
- package/plugins/workflow-runner/src/sandbox.ts +182 -0
- package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
- package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
- package/plugins/workflow-runner/src/taskIdentity.js +172 -152
- package/plugins/workflow-runner/src/taskIdentity.ts +233 -200
- package/plugins/workflow-runner/src/toolRuntime.js +29 -8
- package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
- package/plugins/workflow-runner/src/types.js +7 -105
- package/plugins/workflow-runner/src/types.ts +155 -520
- package/plugins/workflow-runner/src/util.js +47 -0
- package/plugins/workflow-runner/src/util.ts +51 -0
- package/plugins/workflow-runner/src/workflowContext.js +20 -0
- package/plugins/workflow-runner/src/workflowContext.ts +58 -0
- package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
- package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
- package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
- package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
- package/plugins/workflow-runner/src/workflowState.js +542 -469
- package/plugins/workflow-runner/src/workflowState.ts +639 -589
- package/plugins/workflow-runner/test/api.test.ts +223 -0
- package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
- package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
- package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
- package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
- package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
- package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
- package/plugins/workflow-runner/test/discovery.test.ts +234 -0
- package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
- package/plugins/workflow-runner/test/goalController.test.ts +317 -0
- package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
- package/plugins/workflow-runner/test/listResources.test.ts +106 -0
- package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
- package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
- package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
- package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
- package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
- package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
- package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
- package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
- package/skills/pptx/examples/assets/cover-bg.svg +23 -0
- package/skills/pptx/examples/assets/icon-spark.svg +5 -0
- package/skills/skill-creator/scripts/run_eval.py +3 -2
- package/skills/ui-design/SKILL.md +5 -2
- package/skills/ui-design/references/layout-composition.md +1 -1
- package/skills/workflow-creator/SKILL.md +344 -0
- package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
- package/skills/workflow-creator/references/api.md +216 -0
- package/skills/workflow-creator/references/migration.md +103 -0
- package/skills/workflow-creator/references/patterns.md +779 -0
- package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
- package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
- package/skills/workflow-creator/scripts/validate.mjs +275 -0
- package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
- package/src/advisor/advisorCoordinator.js +503 -0
- package/src/advisor/advisorCoordinator.ts +657 -0
- package/src/cli/configMenu.tsx +0 -1
- package/src/cli/print.js +44 -6
- package/src/cli/print.ts +73 -4
- package/src/cli/streamJson.js +5 -6
- package/src/cli/streamJson.ts +8 -4
- package/src/cli/wizards/advisorWizard.js +4 -2
- package/src/cli/wizards/advisorWizard.tsx +8 -2
- package/src/cli/wizards/contextAdvisorWizard.js +5 -4
- package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
- package/src/collaboration/taskFlow.js +115 -0
- package/src/collaboration/taskFlow.ts +169 -0
- package/src/config/configDefaults.js +41 -1
- package/src/config/configDefaults.ts +43 -1
- package/src/config/configDiagnostics.ts +2 -2
- package/src/config/configFile.js +40 -9
- package/src/config/configFile.ts +60 -11
- package/src/config/configService.js +443 -74
- package/src/config/configService.ts +723 -142
- package/src/config/numericLimits.js +22 -0
- package/src/config/numericLimits.ts +24 -0
- package/src/config.js +1 -0
- package/src/config.ts +3 -2
- package/src/context/budgetPlan.js +1 -1
- package/src/context/budgetPlan.ts +1 -1
- package/src/context/compact.js +7 -2
- package/src/context/compact.ts +9 -2
- package/src/context/microCompactLite.js +212 -13
- package/src/context/microCompactLite.ts +261 -12
- package/src/context/sessionRegistry.js +8 -1
- package/src/context/sessionRegistry.ts +18 -5
- package/src/context/toolResultArchive.js +72 -0
- package/src/context/toolResultArchive.ts +95 -0
- package/src/goal/errors.js +8 -0
- package/src/goal/errors.ts +18 -0
- package/src/goal/goalRuntime.js +344 -0
- package/src/goal/goalRuntime.ts +466 -0
- package/src/goal/goalStore.js +200 -0
- package/src/goal/goalStore.ts +219 -0
- package/src/goal/index.js +4 -0
- package/src/goal/index.ts +4 -0
- package/src/goal/statusMapping.js +71 -0
- package/src/goal/statusMapping.ts +95 -0
- package/src/goal/types.js +7 -0
- package/src/goal/types.ts +179 -0
- package/src/goal/workflowController.js +306 -0
- package/src/goal/workflowController.ts +360 -0
- package/src/harness/evidenceLedger.js +2 -0
- package/src/harness/evidenceLedger.ts +1 -0
- package/src/harness/stallGuard.js +9 -3
- package/src/harness/stallGuard.ts +7 -3
- package/src/images/imageResolver.js +161 -0
- package/src/images/imageResolver.ts +189 -0
- package/src/infra/verification.js +56 -20
- package/src/infra/verification.ts +87 -20
- package/src/llm/client.js +79 -21
- package/src/llm/client.ts +182 -35
- package/src/llm/gatewayClient.js +201 -0
- package/src/llm/gatewayClient.ts +299 -0
- package/src/llm/messageProvenance.js +46 -0
- package/src/llm/messageProvenance.ts +58 -0
- package/src/llm/modelProvider.js +1 -0
- package/src/llm/modelProvider.ts +22 -0
- package/src/llm/providers/anthropicFormat.js +108 -1
- package/src/llm/providers/anthropicFormat.ts +115 -4
- package/src/llm/providers/openaiFormat.js +9 -0
- package/src/llm/providers/openaiFormat.ts +12 -3
- package/src/loop.js +319 -54
- package/src/loop.ts +373 -57
- package/src/main.js +4 -1
- package/src/main.tsx +4 -1
- package/src/managedExecution/index.js +2 -0
- package/src/managedExecution/index.ts +2 -0
- package/src/managedExecution/registry.js +15 -0
- package/src/managedExecution/registry.ts +20 -0
- package/src/managedExecution/types.js +1 -0
- package/src/managedExecution/types.ts +86 -0
- package/src/modelRef.js +9 -0
- package/src/modelRef.ts +31 -0
- package/src/multimodal.js +14 -28
- package/src/multimodal.ts +17 -33
- package/src/net/lanDiscovery.js +65 -0
- package/src/net/lanDiscovery.ts +82 -0
- package/src/plugin-sdk.js +28 -3
- package/src/plugin-sdk.ts +39 -6
- package/src/plugins/pluginApi.ts +16 -1
- package/src/plugins/pluginLoader.js +4 -0
- package/src/plugins/pluginLoader.ts +6 -0
- package/src/plugins/pluginRunner.js +152 -9
- package/src/plugins/pluginRunner.ts +186 -8
- package/src/plugins/slashFallback.js +113 -0
- package/src/plugins/slashFallback.ts +137 -0
- package/src/prompts/policyRegistry.js +15 -8
- package/src/prompts/policyRegistry.ts +18 -8
- package/src/prompts/promptAssembly.js +103 -12
- package/src/prompts/promptAssembly.ts +114 -12
- package/src/prompts/skillList.js +21 -3
- package/src/prompts/skillList.ts +27 -2
- package/src/prompts/stableSystemPrompt.js +18 -0
- package/src/prompts/stableSystemPrompt.ts +33 -0
- package/src/runtime/agentRuntimeContext.js +8 -2
- package/src/runtime/agentRuntimeContext.ts +17 -4
- package/src/session/runAgentTurn.js +78 -12
- package/src/session/runAgentTurn.ts +105 -23
- package/src/session/runTurn.js +10 -9
- package/src/session/runTurn.ts +17 -8
- package/src/session/sessionState.ts +2 -0
- package/src/team/auth.js +186 -0
- package/src/team/auth.ts +298 -0
- package/src/team/cli.js +105 -0
- package/src/team/cli.ts +122 -0
- package/src/team/onlineToolContract.js +64 -0
- package/src/team/onlineToolContract.ts +109 -0
- package/src/team/toolPolicy.js +36 -0
- package/src/team/toolPolicy.ts +75 -0
- package/src/tools/advisor/advisor.js +148 -37
- package/src/tools/advisor/advisor.ts +161 -38
- package/src/tools/advisor/advisorDecision.js +71 -0
- package/src/tools/advisor/advisorDecision.ts +85 -0
- package/src/tools/agent/agent.js +18 -5
- package/src/tools/agent/agent.ts +21 -7
- package/src/tools/agent/agentControl.js +246 -0
- package/src/tools/agent/agentControl.ts +284 -0
- package/src/tools/agent/agentTaskService.js +40 -1
- package/src/tools/agent/agentTaskService.ts +44 -1
- package/src/tools/agent/agentTypes.js +14 -2
- package/src/tools/agent/agentTypes.ts +15 -2
- package/src/tools/applypatch/applyPatch.js +362 -0
- package/src/tools/applypatch/applyPatch.ts +428 -0
- package/src/tools/bash/bash.js +70 -18
- package/src/tools/bash/bash.ts +75 -20
- package/src/tools/capabilities.js +10 -5
- package/src/tools/capabilities.ts +10 -5
- package/src/tools/computeruse/computerIntent.js +32 -0
- package/src/tools/computeruse/computerIntent.ts +46 -0
- package/src/tools/computeruse/telemetryLog.js +12 -0
- package/src/tools/computeruse/telemetryLog.ts +16 -0
- package/src/tools/computeruse/vision/telemetry.js +1 -0
- package/src/tools/computeruse/vision/telemetry.ts +1 -0
- package/src/tools/effectiveToolSet.js +4 -0
- package/src/tools/effectiveToolSet.ts +4 -0
- package/src/tools/index.js +21 -2
- package/src/tools/index.ts +33 -2
- package/src/tools/powershell/powershell.js +18 -1
- package/src/tools/powershell/powershell.ts +18 -2
- package/src/tools/presentresult/presentresult.js +6 -15
- package/src/tools/presentresult/presentresult.ts +6 -15
- package/src/tools/read/read.js +69 -11
- package/src/tools/read/read.ts +70 -11
- package/src/tools/shared/fileUtils.js +1 -2
- package/src/tools/shared/fileUtils.ts +1 -2
- package/src/tools/shared/permanentDeleteGuard.js +34 -3
- package/src/tools/shared/permanentDeleteGuard.ts +43 -6
- package/src/tools/shared/toolOutputStore.js +23 -1
- package/src/tools/shared/toolOutputStore.ts +22 -1
- package/src/tools/skill/skill.js +9 -3
- package/src/tools/skill/skill.ts +8 -4
- package/src/tools/toolPromptGuides.js +117 -0
- package/src/tools/toolPromptGuides.ts +137 -0
- package/src/tools/webbrowser/agentBrowserPath.js +19 -9
- package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
- package/src/tools/webbrowser/browser.js +27 -11
- package/src/tools/webbrowser/browser.ts +68 -24
- package/src/tools/webbrowser/browserAutomation.js +329 -0
- package/src/tools/webbrowser/browserAutomation.ts +467 -0
- package/src/tools/webbrowser/browserAxState.js +97 -0
- package/src/tools/webbrowser/browserAxState.ts +142 -0
- package/src/tools/webbrowser/browserBatch.js +1578 -0
- package/src/tools/webbrowser/browserBatch.ts +2382 -0
- package/src/tools/webbrowser/browserCdp.js +208 -0
- package/src/tools/webbrowser/browserCdp.ts +255 -0
- package/src/tools/webbrowser/browserConditions.js +24 -0
- package/src/tools/webbrowser/browserConditions.ts +45 -0
- package/src/tools/webbrowser/browserContent.js +281 -0
- package/src/tools/webbrowser/browserContent.ts +438 -0
- package/src/tools/webbrowser/browserControl.js +131 -30
- package/src/tools/webbrowser/browserControl.ts +210 -50
- package/src/tools/webbrowser/browserDaemon.js +22 -14
- package/src/tools/webbrowser/browserDaemon.ts +54 -21
- package/src/tools/webbrowser/browserFrames.js +47 -0
- package/src/tools/webbrowser/browserFrames.ts +54 -0
- package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
- package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
- package/src/tools/webbrowser/browserLocator.js +140 -0
- package/src/tools/webbrowser/browserLocator.ts +194 -0
- package/src/tools/webbrowser/browserOutcome.js +10 -17
- package/src/tools/webbrowser/browserOutcome.ts +48 -31
- package/src/tools/webbrowser/browserRecovery.js +58 -0
- package/src/tools/webbrowser/browserRecovery.ts +83 -0
- package/src/tools/webbrowser/browserRunRegistry.js +35 -3
- package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
- package/src/tools/webbrowser/browserService.js +28 -2
- package/src/tools/webbrowser/browserService.ts +49 -9
- package/src/tools/webbrowser/browserStream.js +132 -33
- package/src/tools/webbrowser/browserStream.ts +224 -50
- package/src/tools/webbrowser/browserTabs.js +48 -15
- package/src/tools/webbrowser/browserTabs.ts +178 -96
- package/src/tools/webbrowser/webbrowser.js +683 -144
- package/src/tools/webbrowser/webbrowser.ts +979 -236
- package/src/tools/webfetch/preapproved.js +0 -2
- package/src/tools/webfetch/preapproved.ts +0 -2
- package/src/tools/websearch/websearch.js +129 -8
- package/src/tools/websearch/websearch.ts +138 -6
- package/src/types.ts +450 -42
- package/src/ui/App.js +377 -58
- package/src/ui/App.tsx +576 -111
- package/src/ui/LiveArea.js +14 -8
- package/src/ui/LiveArea.tsx +14 -10
- package/src/ui/MessageList.js +63 -20
- package/src/ui/MessageList.tsx +101 -16
- package/src/ui/ModelPicker.js +7 -4
- package/src/ui/ModelPicker.tsx +55 -8
- package/src/ui/hooks/useChat.js +152 -163
- package/src/ui/hooks/useChat.ts +396 -334
- package/src/ui/loginCommand.js +56 -0
- package/src/ui/loginCommand.ts +63 -0
- package/src/ui/toolProgress.js +41 -0
- package/src/ui/toolProgress.ts +44 -0
- package/src/web/browserBridge.js +20 -2
- package/src/web/browserBridge.ts +20 -2
- package/src/web/protocol.ts +1897 -194
- package/workflows/adaptive-research/workflow.mjs +86 -0
- package/workflows/e2e-capabilities/workflow.mjs +102 -0
- package/workflows/e2e-llm/workflow.mjs +52 -0
- package/workflows/e2e-smoke/workflow.mjs +59 -0
- package/workflows/e2e-vision-schema/README.md +48 -0
- package/workflows/e2e-vision-schema/workflow.mjs +149 -0
- package/workflows/e2e-write-greet/workflow.mjs +37 -0
- package/workflows/file-census/README.md +14 -0
- package/workflows/file-census/scripts/.gitkeep +2 -0
- package/workflows/file-census/workflow.mjs +110 -0
- package/workflows/goal/README.md +166 -0
- package/workflows/goal/prompts/audit.md +57 -0
- package/workflows/goal/prompts/contract.md +56 -0
- package/workflows/goal/prompts/iterate.md +37 -0
- package/workflows/goal/workflow.mjs +501 -0
- package/workflows/illustrate/README.md +90 -0
- package/workflows/illustrate/assets/engines.json +20 -0
- package/workflows/illustrate/assets/extract-baidu.js +21 -0
- package/workflows/illustrate/assets/extract-bing.js +33 -0
- package/workflows/illustrate/assets/extract-google.js +31 -0
- package/workflows/illustrate/workflow.mjs +301 -0
- package/workflows/plan/workflow.mjs +389 -0
- package/workflows/question-crops/README.md +35 -0
- package/workflows/question-crops/prompts/inventory.md +23 -0
- package/workflows/question-crops/scripts/image-ops.mjs +305 -0
- package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
- package/workflows/question-crops/workflow.mjs +172 -0
- package/workflows/ralph-loop/workflow.mjs +162 -0
- package/workflows/research/DESIGN.md +449 -0
- package/workflows/research/README.md +74 -0
- package/workflows/research/prompts/s0-goal.md +43 -0
- package/workflows/research/prompts/s1-early-exit.md +22 -0
- package/workflows/research/prompts/s1-map.md +58 -0
- package/workflows/research/prompts/s2-options.md +53 -0
- package/workflows/research/prompts/s3-deep-dive.md +56 -0
- package/workflows/research/prompts/s4-verify.md +74 -0
- package/workflows/research/prompts/s5-synthesis.md +81 -0
- package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
- package/workflows/research/prompts/s6-package.md +32 -0
- package/workflows/research/scripts/build-report.mjs +98 -0
- package/workflows/research/workflow.mjs +288 -0
- package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
- package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
- package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
- package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
- package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
- package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
- package/workflows/wechat-reading-shots/workflow.mjs +266 -0
- package/workflows/wrong-question-docx/README.md +55 -0
- package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
- package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
- package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
- package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
- package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
- package/workflows/wrong-question-docx/workflow.mjs +485 -0
- package/plugins/workflow-runner/src/agentCommon.js +0 -354
- package/plugins/workflow-runner/src/agentCommon.ts +0 -435
- package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
- package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
- package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
- package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
- package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
- package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
- package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
- package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
- package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
- package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
- package/plugins/workflow-runner/src/dslManifest.js +0 -72
- package/plugins/workflow-runner/src/dslManifest.ts +0 -127
- package/plugins/workflow-runner/src/expressions.js +0 -618
- package/plugins/workflow-runner/src/expressions.ts +0 -622
- package/plugins/workflow-runner/src/loader.js +0 -573
- package/plugins/workflow-runner/src/loader.ts +0 -721
- package/plugins/workflow-runner/src/multimodal.js +0 -38
- package/plugins/workflow-runner/src/multimodal.ts +0 -64
- package/plugins/workflow-runner/src/recovery.js +0 -119
- package/plugins/workflow-runner/src/recovery.ts +0 -149
- package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
- package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
- package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -41
- package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -50
- package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
- package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
- package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
- package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
- package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
- package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
- package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
- package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
- package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -208
- package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -256
- package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -58
- package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -68
- package/plugins/workflow-runner/src/stepPipeline.js +0 -277
- package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
- package/plugins/workflow-runner/test/agent.test.ts +0 -587
- package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
- package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
- package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
- package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -147
- package/plugins/workflow-runner/test/context-files.test.ts +0 -320
- package/plugins/workflow-runner/test/e2e.test.ts +0 -370
- package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -226
- package/plugins/workflow-runner/test/expressions.test.ts +0 -397
- package/plugins/workflow-runner/test/foundation.test.ts +0 -126
- package/plugins/workflow-runner/test/graceful.test.ts +0 -139
- package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
- package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
- package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
- package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
- package/plugins/workflow-runner/test/loader.test.ts +0 -617
- package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
- package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
- package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
- package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -87
- package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
- package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
- package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -220
- package/plugins/workflow-runner/test/recovery.test.ts +0 -265
- package/plugins/workflow-runner/test/runner.test.ts +0 -911
- package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -379
- package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
- package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -150
- package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
- package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -338
- package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -270
- package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
- package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
- package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
- package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
- package/plugins/workflow-runner/test/word.load.test.ts +0 -208
- package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
- package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
- package/src/advisorState.js +0 -22
- package/src/cli/configWizard.js +0 -293
- package/src/tools/toolProgressBridge.js +0 -48
- package/workflows/adaptive-research.yaml +0 -50
- package/workflows/book-review-short.yaml +0 -125
- package/workflows/e2e-write-greet.yaml +0 -31
- package/workflows/illustrate.yaml +0 -227
- package/workflows/plan.yaml +0 -470
- package/workflows/ppt.yaml +0 -1670
- package/workflows/ralph-loop.yaml +0 -199
- package/workflows/schema.json +0 -176
- package/workflows/webppt.yaml +0 -496
- package/workflows/wechat-reading-shots.yaml +0 -315
- package/workflows/word.yaml +0 -720
- package/workflows/youtube-shorts.yaml +0 -202
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
apiVersion: 2,
|
|
3
|
+
description:
|
|
4
|
+
'受工作流指导的 TAOR:确定性骨架 + 两处随机应变。agent 自主调研写笔记,确定性步骤失败就地自愈,最后守门校验',
|
|
5
|
+
inputs: [
|
|
6
|
+
{
|
|
7
|
+
name: 'topic',
|
|
8
|
+
required: true,
|
|
9
|
+
greedy: true,
|
|
10
|
+
description: '调研主题(可直接一句话自然语言,不会被空格拆碎)',
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
artifacts: [],
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default async function run(wf) {
|
|
17
|
+
const { values: args } = wf.input
|
|
18
|
+
const { sessionId: session, taskId: task } = wf.runtime
|
|
19
|
+
const { agent } = wf.model
|
|
20
|
+
const { call: tool } = wf.tools
|
|
21
|
+
const { shell: sh } = wf.exec
|
|
22
|
+
const { exists } = wf.fs
|
|
23
|
+
const { verify } = wf.check
|
|
24
|
+
const echo = wf.output.message
|
|
25
|
+
const declareArtifact = wf.output.artifact
|
|
26
|
+
const log = (message) => wf.output.progress({ phase: 'workflow', status: 'update', message: String(message) })
|
|
27
|
+
|
|
28
|
+
// 自 adaptive-research.yaml 迁移。三处 DSL 机制在代码形态里的对应写法:
|
|
29
|
+
// done_when: → 调用后自己 await exists() 判断,不满足就再喊一次
|
|
30
|
+
// onError: recover → try/catch + 再调一次 agent()
|
|
31
|
+
// type: verify → await verify()
|
|
32
|
+
// 引擎因此不需要 done_when / onError / recover_hint / verify 这四个概念。
|
|
33
|
+
|
|
34
|
+
const outDir = `out/adaptive-research/${session}/${task}`
|
|
35
|
+
const notesPath = `${outDir}/notes.md`
|
|
36
|
+
|
|
37
|
+
// ── 1. 开放式调研:把「怎么做」交给有界子 agent ──────────────────────
|
|
38
|
+
const RESEARCH_PROMPT = `调研主题「${args.topic}」:用你手上的工具搜集 3-5 个关键要点,
|
|
39
|
+
整理成简洁的中文 markdown,写到 ${notesPath}(目录不存在就先创建)。
|
|
40
|
+
写完后用 Read 自检文件确实写好了再收尾。`
|
|
41
|
+
|
|
42
|
+
let notes = await agent(RESEARCH_PROMPT, {
|
|
43
|
+
label: '自主调研写笔记',
|
|
44
|
+
allowedTools: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob'],
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// 「宣告要写却没写」是弱模型的典型烂尾(announce-not-do)。yaml 里这是引擎的
|
|
48
|
+
// done_when + 自动 nudge;代码形态里就是一个 if —— 而且作者能看见它、能改它。
|
|
49
|
+
for (let attempt = 1; attempt <= 2 && !(await exists(notesPath)); attempt++) {
|
|
50
|
+
log(`笔记还没落盘,第 ${attempt} 次提醒 agent 补上`)
|
|
51
|
+
notes = await agent(
|
|
52
|
+
`${notesPath} 还没有生成。请**现在就调用 Write 工具**把调研笔记写进去,不要只描述你打算做什么。`,
|
|
53
|
+
{ label: `nudge-${attempt}`, allowedTools: ['Read', 'Write', 'Bash'] },
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
declareArtifact(notesPath)
|
|
57
|
+
|
|
58
|
+
// ── 2. 确定性统计,失败就地自愈 ─────────────────────────────────────
|
|
59
|
+
// 用 sh() 而不是 tool('Bash', …):后者返回给模型看的展示文本
|
|
60
|
+
// (`<stdout>…</stdout>\n\n[exit code: 0]`),想拿行数还得自己剥壳。
|
|
61
|
+
let lineReport
|
|
62
|
+
try {
|
|
63
|
+
const r = await sh(`wc -l ${notesPath}`)
|
|
64
|
+
if (r.exitCode !== 0) throw new Error(r.stderr || `exit ${r.exitCode}`)
|
|
65
|
+
lineReport = r.stdout.trim()
|
|
66
|
+
} catch (e) {
|
|
67
|
+
// 原 yaml 的 onError:recover + recover_hint。代码形态下「救一把」就是再调一次
|
|
68
|
+
// agent 并把真实错误给它看 —— 比 DSL 声明更直白,也能看见救了什么。
|
|
69
|
+
log(`统计失败,起一个 agent 自愈:${e.message}`)
|
|
70
|
+
lineReport = await agent(
|
|
71
|
+
`执行 \`wc -l ${notesPath}\` 失败了:${e.message}\n` +
|
|
72
|
+
'请先用 Glob/Read 定位 notes.md 的真实位置,再统计它的行数,把结果说出来。',
|
|
73
|
+
{ label: 'recover-count', allowedTools: ['Read', 'Glob', 'Bash'] },
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ── 3. 守门校验:agent 说做完了不算数 ───────────────────────────────
|
|
78
|
+
const gate = await verify(`file_exists:${notesPath}`)
|
|
79
|
+
if (!gate.passed) {
|
|
80
|
+
throw new Error(`调研笔记 ${notesPath} 未生成 —— 检查调研步骤。${gate.summary}`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
echo(`✅ 调研完成 → ${notesPath}`)
|
|
84
|
+
echo(` 行数统计:${String(lineReport).trim().split('\n')[0]}`)
|
|
85
|
+
return { notes: notesPath, lineReport, summary: notes }
|
|
86
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
apiVersion: 2,
|
|
3
|
+
description:
|
|
4
|
+
'E2E:一次跑通 schema / pipeline / isolated 三项新能力(model 需本机配置,故不在此断言)',
|
|
5
|
+
inputs: [
|
|
6
|
+
{ name: 'topic', required: true, greedy: true },
|
|
7
|
+
{ name: 'items', type: 'number', default: 10 },
|
|
8
|
+
],
|
|
9
|
+
artifacts: [],
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default async function run(wf) {
|
|
13
|
+
const { values: args } = wf.input
|
|
14
|
+
const { generate: llm, agent } = wf.model
|
|
15
|
+
const log = (message) => wf.output.progress({ phase: 'workflow', status: 'update', message: String(message) })
|
|
16
|
+
const echo = wf.output.message
|
|
17
|
+
|
|
18
|
+
// 这条工作流的存在意义是「引擎自己的问题」和「模型的问题」分开:
|
|
19
|
+
// 它只用最简单的生成任务,跑不通就一定是引擎的锅。
|
|
20
|
+
// ⚠️ items 默认 10 > 并发上限 8 —— 扇出规模必须超过闸门才测得到车道分配。
|
|
21
|
+
|
|
22
|
+
const N = Number(args.items ?? 10)
|
|
23
|
+
log(`扇出 ${N} 项`)
|
|
24
|
+
|
|
25
|
+
const SCORE = {
|
|
26
|
+
type: 'object',
|
|
27
|
+
required: ['index', 'score', 'verdict'],
|
|
28
|
+
properties: {
|
|
29
|
+
index: { type: 'number' },
|
|
30
|
+
score: { type: 'number', minimum: 0, maximum: 10 },
|
|
31
|
+
verdict: { enum: ['keep', 'drop'] },
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// pipeline:每项独立走两个阶段,阶段之间无屏障。
|
|
36
|
+
// 每个 llm 都 isolated —— 逐项打分不需要看前文,产出也不该污染主线。
|
|
37
|
+
const batch = await wf.flow.pipeline(Array.from({ length: N }, (_, i) => i), {
|
|
38
|
+
label: '结构化打分',
|
|
39
|
+
errorMode: 'collect',
|
|
40
|
+
stages: [
|
|
41
|
+
// 阶段 1:结构化打分(schema 保证拿到的是对象,不是要自己 parse 的字符串)
|
|
42
|
+
(_prev, item) =>
|
|
43
|
+
llm(
|
|
44
|
+
`给「${args.topic}」的第 ${item} 个方面打分。` +
|
|
45
|
+
`只输出 JSON:{"index":${item},"score":0到10的数字,"verdict":"keep"或"drop"}`,
|
|
46
|
+
{ schema: SCORE, label: `打分 #${item}`, isolated: true },
|
|
47
|
+
),
|
|
48
|
+
|
|
49
|
+
// 阶段 2:确定性归一(纯 JS,不烧 token)
|
|
50
|
+
(s, _item, i) => ({ ...s, rank: i }),
|
|
51
|
+
]})
|
|
52
|
+
|
|
53
|
+
const ok = batch.results.filter((entry) => entry.ok).map((entry) => entry.value)
|
|
54
|
+
if (ok.length === 0) throw new Error('全部项都失败了 —— 引擎或 provider 有问题')
|
|
55
|
+
|
|
56
|
+
// 验收:schema 真的生效了吗(拿到的必须是对象且字段齐全)
|
|
57
|
+
for (const s of ok) {
|
|
58
|
+
if (typeof s !== 'object' || typeof s.score !== 'number') {
|
|
59
|
+
throw new Error(`schema 未生效:拿到 ${JSON.stringify(s)}`)
|
|
60
|
+
}
|
|
61
|
+
if (s.verdict !== 'keep' && s.verdict !== 'drop') {
|
|
62
|
+
throw new Error(`enum 校验未生效:verdict=${s.verdict}`)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const keep = ok.filter((s) => s.verdict === 'keep').length
|
|
67
|
+
|
|
68
|
+
// ── 带工具的 agent + schema(与上面的 llm 零工具路径是**两条不同的路**)────
|
|
69
|
+
// agent 的工具循环里**不能**开原生 response_format(它要求每条 assistant 消息
|
|
70
|
+
// 都是 JSON,与 tool_calls 互斥),所以引擎走「带工具干完活,再零工具整形」。
|
|
71
|
+
//
|
|
72
|
+
// 这条单独验的理由:整形轮的 history 里带着 tool_calls / tool 消息,而个别
|
|
73
|
+
// provider 会因此拒绝 response_format —— 单测用 stub 只能证明引擎的分派对,
|
|
74
|
+
// 证明不了真实 provider 认这个组合。`plan` 阶段 6 的独立验收走的正是这条路径。
|
|
75
|
+
const REPORT = {
|
|
76
|
+
type: 'object',
|
|
77
|
+
required: ['file_count', 'verdict'],
|
|
78
|
+
properties: {
|
|
79
|
+
file_count: { type: 'number', minimum: 0 },
|
|
80
|
+
verdict: { enum: ['ok', 'empty'] },
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
const report = await agent(
|
|
84
|
+
'用 Glob 查一下当前工作目录下有多少个 .md 文件(只数数量,不要读内容)。' +
|
|
85
|
+
'然后只输出 JSON:{"file_count":数字,"verdict":"ok"(有文件)或"empty"(没有)}',
|
|
86
|
+
{ label: '带工具+schema', allowedTools: ['Glob'], maxTurns: 5, schema: REPORT },
|
|
87
|
+
)
|
|
88
|
+
if (typeof report !== 'object' || typeof report.file_count !== 'number') {
|
|
89
|
+
throw new Error(`带工具路径的 schema 未生效:拿到 ${JSON.stringify(report)}`)
|
|
90
|
+
}
|
|
91
|
+
if (report.verdict !== 'ok' && report.verdict !== 'empty') {
|
|
92
|
+
throw new Error(`带工具路径的 enum 未生效:verdict=${report.verdict}`)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
echo(
|
|
96
|
+
`✅ 能力冒烟通过:${ok.length}/${N} 项打分成功(keep ${keep} / drop ${ok.length - keep}),` +
|
|
97
|
+
`schema 返回对象、pipeline 扇出、isolated 未污染主线;` +
|
|
98
|
+
`带工具的 agent+schema 也通(数到 ${report.file_count} 个 .md,verdict=${report.verdict})`,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
return { total: N, ok: ok.length, keep, toolSchema: report.verdict }
|
|
102
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
apiVersion: 2,
|
|
3
|
+
description: 'E2E:走一次 llm() 与一次 agent(),验证 LLM 路径与目标锚注入',
|
|
4
|
+
inputs: [{ name: 'topic', required: true, greedy: true }],
|
|
5
|
+
artifacts: [],
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default async function run(wf) {
|
|
9
|
+
const { values: args } = wf.input
|
|
10
|
+
const { sessionId: session, taskId: task } = wf.runtime
|
|
11
|
+
const { generate: llm, agent } = wf.model
|
|
12
|
+
const { exists } = wf.fs
|
|
13
|
+
const echo = wf.output.message
|
|
14
|
+
const declareArtifact = wf.output.artifact
|
|
15
|
+
const log = (message) => wf.output.progress({ phase: 'workflow', status: 'update', message: String(message) })
|
|
16
|
+
|
|
17
|
+
// 与 e2e-smoke 互补:那条一次 LLM 都不调(隔离引擎问题),这条专测 LLM 通路。
|
|
18
|
+
// 刻意做到最小 —— 只要能证明「调得通、拿得到文本、目标锚注入了」就够,不烧 token。
|
|
19
|
+
|
|
20
|
+
log('测试 llm() 通路')
|
|
21
|
+
|
|
22
|
+
// llm():纯文本生成,不给任何工具。弱模型也能跑。
|
|
23
|
+
const oneLiner = await llm(
|
|
24
|
+
`用一句不超过 20 个字的话概括「${args.topic}」。只输出那句话,不要任何解释。`,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if (!oneLiner || !oneLiner.trim()) {
|
|
28
|
+
throw new Error('llm() 返回空文本 —— LLM 通路有问题')
|
|
29
|
+
}
|
|
30
|
+
echo(`llm() 产出:${oneLiner.trim()}`)
|
|
31
|
+
|
|
32
|
+
// agent():可以用工具。这里只给它 Write,验证 allowedTools 收敛真的生效。
|
|
33
|
+
const outDir = `out/e2e-llm/${session}/${task}`
|
|
34
|
+
const outPath = `${outDir}/note.md`
|
|
35
|
+
|
|
36
|
+
await agent(
|
|
37
|
+
`把这句话写进文件 ${outPath}:\n\n${oneLiner.trim()}\n\n写完即可,不要做别的。`,
|
|
38
|
+
{ label: 'write-note', allowedTools: ['Write'], maxTurns: 6 },
|
|
39
|
+
)
|
|
40
|
+
declareArtifact(outPath)
|
|
41
|
+
|
|
42
|
+
// 确定性验收:agent 说做完了不算数,得文件真在
|
|
43
|
+
if (!(await exists(outPath))) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`agent 宣称写完了但 ${outPath} 不存在 —— 这正是 announce-not-do 烂尾,` +
|
|
46
|
+
'确定性验收就是为了抓它',
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
echo(`✅ LLM 通路通过 → ${outPath}`)
|
|
51
|
+
return { note: outPath }
|
|
52
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
apiVersion: 2,
|
|
3
|
+
description: 'E2E 冒烟:只走确定性路径(tool/verify/exists/echo),零 LLM 零网络',
|
|
4
|
+
inputs: [
|
|
5
|
+
{ name: 'name', required: true, greedy: true },
|
|
6
|
+
{ name: 'times', type: 'number', default: 3 },
|
|
7
|
+
],
|
|
8
|
+
// 静态声明只能写死路径;带 ${session}/${task} 的实际产物在下面用
|
|
9
|
+
// declareArtifact() 运行时登记 —— meta 是执行前静态求值的纯字面量,写不出插值。
|
|
10
|
+
artifacts: [],
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default async function run(wf) {
|
|
14
|
+
const { values: args } = wf.input
|
|
15
|
+
const { sessionId: session, taskId: task } = wf.runtime
|
|
16
|
+
const { call: tool } = wf.tools
|
|
17
|
+
const { exists } = wf.fs
|
|
18
|
+
const { verify } = wf.check
|
|
19
|
+
const echo = wf.output.message
|
|
20
|
+
const declareArtifact = wf.output.artifact
|
|
21
|
+
const log = (message) => wf.output.progress({ phase: 'workflow', status: 'update', message: String(message) })
|
|
22
|
+
|
|
23
|
+
// 这条工作流一次 LLM 都不调:把「引擎自己的问题」和「模型的问题」分开。
|
|
24
|
+
// 跑不通就一定是引擎的锅。
|
|
25
|
+
|
|
26
|
+
log('开始冒烟')
|
|
27
|
+
|
|
28
|
+
const times = Number(args.times ?? 3)
|
|
29
|
+
const lines = []
|
|
30
|
+
for (let i = 1; i <= times; i++) {
|
|
31
|
+
// 原生 for 循环 —— 代码编排取代 DSL 的地方,引擎不需要 loop 这个概念
|
|
32
|
+
lines.push(`${i}. 你好,${args.name}!`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 推荐写法:产物路径带 ${session}/${task} 两级命名空间。
|
|
36
|
+
// session 隔离并行会话,task 隔离「同一会话里换了个目标」。
|
|
37
|
+
// 不带命名空间也能跑(引擎会在换任务时先把旧产物归档进 .trash/ 再清理),
|
|
38
|
+
// 但那是安全网不是设计 —— 能命名空间就命名空间。
|
|
39
|
+
const outDir = `out/e2e-smoke/${session}/${task}`
|
|
40
|
+
const outPath = `${outDir}/greeting.md`
|
|
41
|
+
|
|
42
|
+
await tool('Write', {
|
|
43
|
+
file_path: outPath,
|
|
44
|
+
content: `# 冒烟测试\n\nsession=${session}\ntask=${task}\n\n${lines.join('\n')}\n`,
|
|
45
|
+
})
|
|
46
|
+
declareArtifact(outPath)
|
|
47
|
+
|
|
48
|
+
// 验收必须和写入锚在同一个 cwd(引擎红线)—— 这里顺带把它测到
|
|
49
|
+
if (!(await exists(outPath))) {
|
|
50
|
+
throw new Error(`写完了却查不到 ${outPath} —— 说明写入与验收的 cwd 不一致`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const v = await verify(`file_contains:${outPath}:你好`)
|
|
54
|
+
if (!v.passed) throw new Error(`内容校验失败:${v.summary}`)
|
|
55
|
+
|
|
56
|
+
echo(`✅ 冒烟通过:${times} 行 → ${outPath}`)
|
|
57
|
+
|
|
58
|
+
return { lines: times, path: outPath }
|
|
59
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# e2e-vision-schema —— 识图 + 结构化输出的组合探针
|
|
2
|
+
|
|
3
|
+
## 跑之前必须满足(否则不是引擎的问题)
|
|
4
|
+
|
|
5
|
+
1. **基座模型支持视觉**。`ConfigService.provider()` 解析出的模型 `supportsVision`
|
|
6
|
+
必须为 true,否则图片送不进去,会在「不同的图给出了完全相同的描述」那条断言上失败。
|
|
7
|
+
2. **有一个装着图片的目录**(png/jpg/jpeg,递归深度 ≤ 4)。**素材要自备** ——
|
|
8
|
+
这条工作流不附带图片,`dir` 是必填参数。
|
|
9
|
+
3. **POSIX shell 可用**(Git Bash / mac / Linux)。脚本用 `find … | sort | head`
|
|
10
|
+
列素材。⚠️ win32 上 Bash 工具找不到 Git Bash 时会**回落 cmd**,而 cmd 的 `find`
|
|
11
|
+
是搜文本的完全不同的命令 —— 那种机器上这条探针跑不了(绿色版 U 盘场景要留意)。
|
|
12
|
+
|
|
13
|
+
## 跑法
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
minimal-agent -p "/workflow e2e-vision-schema <图片目录> --input limit=10"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`dir` 是贪婪首参,所以 `limit` **必须**走 `--input limit=N`,不能当位置参数给。
|
|
20
|
+
|
|
21
|
+
⚠️ **`limit` 默认 10 是刻意的:它必须 > 并发上限 8。** 扇出规模不超过闸门时,
|
|
22
|
+
所有项同时起跑、完成顺序恰好稳定,车道分配根本没被考验到 —— 用例恒绿等于没测。
|
|
23
|
+
|
|
24
|
+
## 它锁的是什么
|
|
25
|
+
|
|
26
|
+
`illustrate` 阶段 5(逐图识图打分)依赖 `images` + `schema` + `isolated` + `pipeline`
|
|
27
|
+
四者叠加。但 `illustrate` 的阶段 1-3 靠 WebBrowser 的 eval 抓图,**需要「设置 → 浏览器」
|
|
28
|
+
里开启 Developer Mode 并把搜索站点加白名单** —— 没有那个授权就到不了阶段 5。
|
|
29
|
+
|
|
30
|
+
于是「引擎的问题」和「授权/网络的问题」会纠缠在一起:抓不到图时你没法判断
|
|
31
|
+
images+schema 到底通没通。这条探针把素材换成本地文件,**跑不通就一定是引擎或
|
|
32
|
+
provider 的锅**。改引擎的结构化输出 / 车道 / 隔离逻辑之后,直接跑它。
|
|
33
|
+
|
|
34
|
+
## 验收判据(为什么不只看「跑完没报错」)
|
|
35
|
+
|
|
36
|
+
- `schema` 生效:逐条断言字段类型、`minimum/maximum`、`enum`。
|
|
37
|
+
- **模型真看见了图**:`schema` 只能保证「形状对」—— 一个完全没收到图片的模型照样
|
|
38
|
+
能吐出合法 JSON。所以额外断言「N 张不同的图必须给出 > 1 种 subject」。
|
|
39
|
+
- `pipeline` 车道:扇出 > 并发上限,账本里每项应是独立车道 `main/p1i<下标>`。
|
|
40
|
+
|
|
41
|
+
## 实测记录
|
|
42
|
+
|
|
43
|
+
- 2026-08-19,豆包 `doubao-seed-2-1-turbo-260628`(OpenAI 格式),10 张 UI 截图:
|
|
44
|
+
10/10 成功、10 种不同描述、schema 与 enum 全部生效。
|
|
45
|
+
- 同日 resume 验证:把账本截断到 6 条(保留的是 i2/i3/i5/i6/i7 五条**不连续**车道)
|
|
46
|
+
后重跑 —— 引擎报「重放 6 次 / 上次账本 6 条」,且输出自证:那 5 项描述**逐字不变**,
|
|
47
|
+
被截断的 5 项描述全变(其中一项 `kind` 从 `screenshot` 变成 `diagram`)。
|
|
48
|
+
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
apiVersion: 2,
|
|
3
|
+
description:
|
|
4
|
+
'E2E:识图(images 通道)+ 结构化输出(schema)+ 上下文隔离(isolated)+ 并发扇出(pipeline)四者叠加是否真的能通 —— illustrate 阶段 5 依赖的正是这条组合路径',
|
|
5
|
+
inputs: [
|
|
6
|
+
{
|
|
7
|
+
name: 'dir',
|
|
8
|
+
type: 'resource',
|
|
9
|
+
required: true,
|
|
10
|
+
greedy: true,
|
|
11
|
+
allowDirectory: true,
|
|
12
|
+
allowFile: false,
|
|
13
|
+
multiple: true,
|
|
14
|
+
materialize: 'directory',
|
|
15
|
+
accepts: ['image/*'],
|
|
16
|
+
attachmentFallback: true,
|
|
17
|
+
description: '图片素材目录(递归找 png/jpg)',
|
|
18
|
+
},
|
|
19
|
+
{ name: 'limit', type: 'number', default: 10, description: '最多取几张' },
|
|
20
|
+
],
|
|
21
|
+
artifacts: [],
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default async function run(wf) {
|
|
25
|
+
const { values: args } = wf.input
|
|
26
|
+
const { generate: llm } = wf.model
|
|
27
|
+
const { shell: sh } = wf.exec
|
|
28
|
+
const echo = wf.output.message
|
|
29
|
+
const log = (message) => wf.output.progress({ phase: 'workflow', status: 'update', message: String(message) })
|
|
30
|
+
|
|
31
|
+
// ============================================================
|
|
32
|
+
// 为什么单独有这条探针,而不是直接跑 illustrate:
|
|
33
|
+
//
|
|
34
|
+
// illustrate 的阶段 1-3 靠 WebBrowser 的 eval 从搜索结果页抽图 URL,
|
|
35
|
+
// **需要「设置 → 浏览器」里开启 Developer Mode 并把站点加白名单**。
|
|
36
|
+
// 没有那个授权就到不了阶段 5 —— 而阶段 5 才是新能力所在。
|
|
37
|
+
//
|
|
38
|
+
// 于是「引擎的问题」和「授权/网络的问题」会纠缠在一起:抓不到图时你
|
|
39
|
+
// 没法判断 images+schema 到底通没通。这条探针把素材换成本地文件,
|
|
40
|
+
// 跑不通就一定是引擎或 provider 的锅。
|
|
41
|
+
//
|
|
42
|
+
// ⚠️ limit 默认 10 > 并发上限 8 —— 扇出规模必须超过闸门,否则所有项
|
|
43
|
+
// 同时起跑、顺序恰好稳定,车道分配根本没被考验到。
|
|
44
|
+
// ============================================================
|
|
45
|
+
|
|
46
|
+
const dir = String(args.dir)
|
|
47
|
+
const limit = Number(args.limit ?? 10)
|
|
48
|
+
|
|
49
|
+
// sort 是为**指纹稳定**:find 的输出顺序不保证,顺序一变图片路径就换车道,
|
|
50
|
+
// 断点续跑会整片失配。确定性纪律不只管 Date.now()。
|
|
51
|
+
const found = await sh(
|
|
52
|
+
`find "${dir}" -maxdepth 4 \\( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' \\) | sort | head -${limit}`,
|
|
53
|
+
)
|
|
54
|
+
const files = found.stdout
|
|
55
|
+
.split('\n')
|
|
56
|
+
.map((s) => s.trim())
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
|
|
59
|
+
if (files.length === 0) {
|
|
60
|
+
throw new Error(`${dir} 下没找到任何 png/jpg/jpeg(find 退出码 ${found.exitCode})`)
|
|
61
|
+
}
|
|
62
|
+
log(`素材 ${files.length} 张(并发上限 8,扇出 ${files.length} 项)`)
|
|
63
|
+
|
|
64
|
+
const VERDICT = {
|
|
65
|
+
type: 'object',
|
|
66
|
+
required: ['subject', 'has_text', 'quality', 'kind'],
|
|
67
|
+
properties: {
|
|
68
|
+
subject: { type: 'string' },
|
|
69
|
+
has_text: { type: 'boolean' },
|
|
70
|
+
quality: { type: 'number', minimum: 0, maximum: 10 },
|
|
71
|
+
kind: { enum: ['screenshot', 'photo', 'diagram', 'other'] },
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const batch = await wf.flow.pipeline(files, {
|
|
76
|
+
label: '视觉结构化识别',
|
|
77
|
+
errorMode: 'collect',
|
|
78
|
+
stages: [
|
|
79
|
+
|
|
80
|
+
// 阶段 1:识图 + 结构化。四项能力在这一个调用里全用上了。
|
|
81
|
+
(path, _item, i) =>
|
|
82
|
+
llm(
|
|
83
|
+
`下方附上一张图片。请**只看这张图**客观描述:
|
|
84
|
+
- subject:一句话说明画的是什么(中文)
|
|
85
|
+
- has_text:图里有没有可读的文字
|
|
86
|
+
- quality:0-10 的观感质量
|
|
87
|
+
- kind:screenshot / photo / diagram / other 四选一
|
|
88
|
+
|
|
89
|
+
只输出 JSON 对象本身,不要 markdown 代码块、不要解释。`,
|
|
90
|
+
{
|
|
91
|
+
label: `识图 #${i}`,
|
|
92
|
+
images: [{ source: path, detail: 'high' }],
|
|
93
|
+
schema: VERDICT,
|
|
94
|
+
isolated: true,
|
|
95
|
+
},
|
|
96
|
+
),
|
|
97
|
+
|
|
98
|
+
// 阶段 2:确定性归一(纯 JS,不烧 token)
|
|
99
|
+
(v, path, i) => ({ ...v, path, index: i }),
|
|
100
|
+
]})
|
|
101
|
+
const results = batch.results.filter((entry) => entry.ok).map((entry) => entry.value)
|
|
102
|
+
|
|
103
|
+
if (results.length === 0) {
|
|
104
|
+
throw new Error('全部识图都失败了 —— images 通道或 schema 路径有问题')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ── 逐条验收:schema 到底生效了没 ────────────────────────────────────
|
|
108
|
+
// 这几条断言是这条探针的全部意义。拿到字符串、拿到缺字段的对象、拿到
|
|
109
|
+
// enum 之外的值 —— 任何一样都说明 schema 没起作用,而**不是**模型答得不好。
|
|
110
|
+
for (const r of results) {
|
|
111
|
+
if (typeof r !== 'object') {
|
|
112
|
+
throw new Error(`schema 未生效:拿到的不是对象 —— ${JSON.stringify(r)}`)
|
|
113
|
+
}
|
|
114
|
+
if (typeof r.subject !== 'string' || r.subject.length === 0) {
|
|
115
|
+
throw new Error(`schema 未生效:subject 不是非空字符串 —— ${JSON.stringify(r)}`)
|
|
116
|
+
}
|
|
117
|
+
if (typeof r.has_text !== 'boolean') {
|
|
118
|
+
throw new Error(`schema 未生效:has_text 不是布尔 —— ${JSON.stringify(r)}`)
|
|
119
|
+
}
|
|
120
|
+
if (typeof r.quality !== 'number' || r.quality < 0 || r.quality > 10) {
|
|
121
|
+
throw new Error(`schema 的 minimum/maximum 未生效:quality=${r.quality}`)
|
|
122
|
+
}
|
|
123
|
+
if (!['screenshot', 'photo', 'diagram', 'other'].includes(r.kind)) {
|
|
124
|
+
throw new Error(`enum 未生效:kind=${r.kind}`)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ── 识图真的看见图了吗 ───────────────────────────────────────────────
|
|
129
|
+
// schema 能保证「形状对」,保证不了「模型真看见了图」—— 一个瞎猜的模型
|
|
130
|
+
// 也能吐出合法 JSON。判据:不同图片必须给出不同的 subject。全都一样
|
|
131
|
+
// 说明图片压根没送到(或送的是同一张)。
|
|
132
|
+
const subjects = new Set(results.map((r) => r.subject))
|
|
133
|
+
if (results.length > 1 && subjects.size === 1) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`${results.length} 张不同的图给出了完全相同的 subject「${results[0].subject}」—— ` +
|
|
136
|
+
'images 通道很可能没真的把图送到模型。',
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
echo(
|
|
141
|
+
`✅ 视觉 + 结构化组合通过:${results.length}/${files.length} 张识图成功,` +
|
|
142
|
+
`${subjects.size} 种不同描述(schema 校验全过、enum 生效、isolated 未污染主线)`,
|
|
143
|
+
)
|
|
144
|
+
for (const r of results) {
|
|
145
|
+
echo(` · #${r.index} [${r.kind}] ${r.has_text ? '有字' : '无字'} 质量${r.quality} — ${r.subject}`)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { total: files.length, ok: results.length, distinct: subjects.size }
|
|
149
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
apiVersion: 2,
|
|
3
|
+
description: 'E2E 极简工作流,证明 /workflow CLI 端到端通(无 LLM 无网络)',
|
|
4
|
+
inputs: [{ name: 'topic', required: true, greedy: true }],
|
|
5
|
+
artifacts: [],
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default async function run(wf) {
|
|
9
|
+
const { values: args } = wf.input
|
|
10
|
+
const { sessionId: session, taskId: task } = wf.runtime
|
|
11
|
+
const { call: tool } = wf.tools
|
|
12
|
+
const { verify } = wf.check
|
|
13
|
+
const echo = wf.output.message
|
|
14
|
+
const declareArtifact = wf.output.artifact
|
|
15
|
+
|
|
16
|
+
// 自 e2e-write-greet.yaml 迁移。原来 3 个 step(tool → verify → assert)在代码形态里
|
|
17
|
+
// 就是三行:写、查、断言。yaml 里的 capture 机制不再需要 —— tool() 直接返回值。
|
|
18
|
+
|
|
19
|
+
const outPath = `out/e2e-write-greet/${session}/${task}/note.txt`
|
|
20
|
+
|
|
21
|
+
const writeResult = await tool('Write', {
|
|
22
|
+
file_path: outPath,
|
|
23
|
+
content: `topic=${args.topic} ok`,
|
|
24
|
+
})
|
|
25
|
+
declareArtifact(outPath)
|
|
26
|
+
|
|
27
|
+
const v = await verify(`file_exists:${outPath}`)
|
|
28
|
+
if (!v.passed) throw new Error(`note.txt 未落盘:${v.summary}`)
|
|
29
|
+
|
|
30
|
+
// 原 yaml 的 assert `length(note_body) > 0` —— capture 绑的是 tool 的回执文本
|
|
31
|
+
if (!writeResult || writeResult.length === 0) {
|
|
32
|
+
throw new Error('tool(Write) 没有返回回执文本')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
echo(`✅ ${outPath}`)
|
|
36
|
+
return { path: outPath }
|
|
37
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
apiVersion: 2,
|
|
3
|
+
description: '给定一个目录路径,统计各种文件扩展名的数量,产出一份 markdown 报告',
|
|
4
|
+
|
|
5
|
+
inputs: [
|
|
6
|
+
{ name: 'dir', type: 'resource', required: true, greedy: true, allowFile: false, allowDirectory: true, multiple: true, materialize: 'directory', attachmentFallback: true, description: '要统计的目录路径或附件目录(相对工作目录)' },
|
|
7
|
+
],
|
|
8
|
+
|
|
9
|
+
artifacts: [],
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
import fs from 'node:fs'
|
|
13
|
+
import path from 'node:path'
|
|
14
|
+
|
|
15
|
+
export default async function run(wf) {
|
|
16
|
+
const { values: args } = wf.input
|
|
17
|
+
const { sessionId: session, taskId: task } = wf.runtime
|
|
18
|
+
const { call: tool } = wf.tools
|
|
19
|
+
const { exists } = wf.fs
|
|
20
|
+
const { verify } = wf.check
|
|
21
|
+
const echo = wf.output.message
|
|
22
|
+
const declareArtifact = wf.output.artifact
|
|
23
|
+
const log = (message) => wf.output.progress({ phase: 'workflow', status: 'update', message: String(message) })
|
|
24
|
+
|
|
25
|
+
// ⚠️ 目录名就是工作流名,这里不写 name。
|
|
26
|
+
// V2 是真实 ESM:确定性纯计算直接使用上面的 node:fs/node:path import。
|
|
27
|
+
// 完整能力见 skills/workflow-creator/references/api.md
|
|
28
|
+
|
|
29
|
+
const OUT = `out/file-census/${session}/${task}/report.md`
|
|
30
|
+
|
|
31
|
+
log(`统计目录:${args.dir}`)
|
|
32
|
+
|
|
33
|
+
// ── 步骤 1:确认目录存在 ─────────────────────────────────────────────
|
|
34
|
+
const dirExists = await exists(args.dir)
|
|
35
|
+
if (!dirExists) throw new Error(`目录不存在:${args.dir}`)
|
|
36
|
+
|
|
37
|
+
// ── 步骤 2:同进程原生 ESM 统计扩展名(确定性,跨平台) ──────────────
|
|
38
|
+
const root = String(args.dir);
|
|
39
|
+
const counts = {};
|
|
40
|
+
let totalFiles = 0;
|
|
41
|
+
let totalDirs = 0;
|
|
42
|
+
|
|
43
|
+
function walk(dir) {
|
|
44
|
+
let entries;
|
|
45
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch (e) { return; }
|
|
46
|
+
for (const entry of entries) {
|
|
47
|
+
if (entry.name === 'node_modules' || entry.name === '.git') continue;
|
|
48
|
+
const full = path.join(dir, entry.name);
|
|
49
|
+
if (entry.isDirectory()) { totalDirs++; walk(full); }
|
|
50
|
+
else if (entry.isFile()) {
|
|
51
|
+
totalFiles++;
|
|
52
|
+
const ext = path.extname(entry.name).toLowerCase() || '(无扩展名)';
|
|
53
|
+
counts[ext] = (counts[ext] || 0) + 1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
walk(root);
|
|
59
|
+
|
|
60
|
+
// 按数量降序
|
|
61
|
+
const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1]);
|
|
62
|
+
const stats = { totalFiles, totalDirs, sorted };
|
|
63
|
+
|
|
64
|
+
// ── 步骤 3:生成 markdown 报告 ────────────────────────────────────────
|
|
65
|
+
const lines = []
|
|
66
|
+
lines.push('# 文件扩展名统计报告')
|
|
67
|
+
lines.push('')
|
|
68
|
+
lines.push(`- **统计目录**:\`${args.dir}\``)
|
|
69
|
+
lines.push(`- **文件总数**:${stats.totalFiles}`)
|
|
70
|
+
lines.push(`- **目录总数**:${stats.totalDirs}`)
|
|
71
|
+
lines.push(`- **扩展名种类**:${stats.sorted.length}`)
|
|
72
|
+
lines.push('')
|
|
73
|
+
lines.push('## 扩展名分布')
|
|
74
|
+
lines.push('')
|
|
75
|
+
lines.push('| 扩展名 | 文件数 | 占比 |')
|
|
76
|
+
lines.push('|--------|--------|------|')
|
|
77
|
+
|
|
78
|
+
for (const [ext, count] of stats.sorted) {
|
|
79
|
+
const pct = stats.totalFiles > 0 ? ((count / stats.totalFiles) * 100).toFixed(1) + '%' : '0%'
|
|
80
|
+
lines.push(`| \`${ext}\` | ${count} | ${pct} |`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
lines.push('')
|
|
84
|
+
lines.push('> 已自动排除 `node_modules` 和 `.git` 目录。')
|
|
85
|
+
lines.push('')
|
|
86
|
+
|
|
87
|
+
const reportContent = lines.join('\n')
|
|
88
|
+
|
|
89
|
+
await tool('Write', {
|
|
90
|
+
file_path: OUT,
|
|
91
|
+
content: reportContent,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
declareArtifact(OUT)
|
|
95
|
+
|
|
96
|
+
// ── 步骤 4:确定性验收(不用 agent,直接 verify) ─────────────────────
|
|
97
|
+
const v = await verify([
|
|
98
|
+
`file_exists:${OUT}`,
|
|
99
|
+
`file_contains:${OUT}:文件扩展名统计报告`,
|
|
100
|
+
`file_contains:${OUT}:扩展名分布`,
|
|
101
|
+
])
|
|
102
|
+
if (!v.passed) throw new Error(`验收失败:${v.summary}`)
|
|
103
|
+
|
|
104
|
+
// ── 收尾:echo 是 -p 模式 result 字段的唯一来源 ──────────────────────
|
|
105
|
+
echo(`✅ 统计完成 → ${OUT}`)
|
|
106
|
+
echo(` 文件总数:${stats.totalFiles},扩展名种类:${stats.sorted.length}`)
|
|
107
|
+
echo(` 最多的扩展名:${stats.sorted[0]?.[0] ?? '无'} (${stats.sorted[0]?.[1] ?? 0} 个)`)
|
|
108
|
+
|
|
109
|
+
return { path: OUT, totalFiles: stats.totalFiles, extCount: stats.sorted.length }
|
|
110
|
+
}
|