minimal-agent 0.13.0 → 0.15.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 +60 -4
- 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 +197 -206
- package/plugins/workflow-runner/src/index.ts +248 -249
- 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 +400 -489
- package/plugins/workflow-runner/src/runner.ts +488 -560
- 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 +151 -307
- package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
- 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 -211
- package/plugins/workflow-runner/src/types.ts +154 -623
- 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 +474 -802
- package/plugins/workflow-runner/src/workflowState.ts +575 -970
- 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/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 +536 -0
- package/src/advisor/advisorCoordinator.ts +693 -0
- package/src/cli/configMenu.tsx +0 -1
- package/src/cli/print.js +27 -6
- package/src/cli/print.ts +48 -4
- package/src/cli/quickModelSetup.js +12 -1
- package/src/cli/quickModelSetup.tsx +15 -3
- 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/cli/wizards/providerPresets.js +18 -8
- package/src/cli/wizards/providerPresets.ts +18 -8
- 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 +419 -74
- package/src/config/configService.ts +703 -145
- 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 +34 -5
- package/src/infra/verification.ts +39 -4
- 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 +328 -55
- package/src/loop.ts +382 -58
- 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 +139 -7
- package/src/plugins/pluginRunner.ts +173 -9
- package/src/plugins/slashFallback.js +113 -0
- package/src/plugins/slashFallback.ts +137 -0
- package/src/prompts/policyRegistry.js +12 -32
- package/src/prompts/policyRegistry.ts +15 -32
- 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 +115 -50
- package/src/tools/advisor/advisor.ts +124 -51
- 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 +22 -15
- package/src/tools/bash/bash.ts +23 -17
- 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/presentresult/presentresult.js +6 -15
- package/src/tools/presentresult/presentresult.ts +6 -15
- package/src/tools/read/read.js +62 -9
- package/src/tools/read/read.ts +63 -9
- package/src/tools/shared/fileUtils.js +1 -2
- package/src/tools/shared/fileUtils.ts +1 -2
- 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 +125 -0
- package/src/tools/toolPromptGuides.ts +146 -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 -34
- package/src/tools/webbrowser/browserControl.ts +210 -56
- 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 +679 -144
- package/src/tools/webbrowser/webbrowser.ts +975 -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 +459 -40
- 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/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 -639
- package/plugins/workflow-runner/src/expressions.ts +0 -640
- 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 -126
- package/plugins/workflow-runner/src/recovery.ts +0 -156
- 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 -42
- package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
- 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 -227
- package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
- package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
- package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
- 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 -167
- 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/e2eNewLayout.test.ts +0 -314
- package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
- package/plugins/workflow-runner/test/expressions.test.ts +0 -439
- 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 -106
- 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 -221
- package/plugins/workflow-runner/test/recovery.test.ts +0 -265
- package/plugins/workflow-runner/test/research.load.test.ts +0 -328
- package/plugins/workflow-runner/test/runner.test.ts +0 -911
- package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
- package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
- package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
- package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
- package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
- package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
- 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 -201
- package/workflows/research.yaml +0 -873
- 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
- /package/workflows/{research.md → research/DESIGN.md} +0 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { toToolParameters } from '../../utils/zodToJson.js';
|
|
3
|
+
import { runManagedAgentTask } from './agent.js';
|
|
4
|
+
import { appendAgentEvent, enqueueAgentMessage, getLiveAgentTask, listAgentRecords, loadAgentRecord, saveAgentRecord, } from './agentTaskService.js';
|
|
5
|
+
const agentId = z.string().regex(/^agent_[0-9a-f-]{36}$/i);
|
|
6
|
+
function needsContext(context) {
|
|
7
|
+
if (!context.sessionState)
|
|
8
|
+
return { ok: false, error: 'Agent 控制工具需要当前 Session 运行状态。' };
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
function snapshot(record) {
|
|
12
|
+
return {
|
|
13
|
+
agent_id: record.id,
|
|
14
|
+
status: record.status,
|
|
15
|
+
description: record.description,
|
|
16
|
+
progress: record.progress,
|
|
17
|
+
created_at: record.createdAt,
|
|
18
|
+
updated_at: record.updatedAt,
|
|
19
|
+
result: record.result
|
|
20
|
+
? record.result.ok
|
|
21
|
+
? record.result.content.slice(0, 4_000)
|
|
22
|
+
: `Error: ${record.result.error.slice(0, 4_000)}`
|
|
23
|
+
: undefined,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const messageSchema = z.object({
|
|
27
|
+
agent_id: agentId,
|
|
28
|
+
message: z.string().min(1).max(100_000),
|
|
29
|
+
});
|
|
30
|
+
export const agentMessageTool = {
|
|
31
|
+
name: 'AgentMessage',
|
|
32
|
+
description: 'Sends additional context or a correction to one running sub-agent by stable agent_id. ' +
|
|
33
|
+
'The message is inserted at the next model boundary without cancelling its current tool call. ' +
|
|
34
|
+
'Use AgentFollowup instead when the agent is already idle or completed.',
|
|
35
|
+
inputSchema: messageSchema,
|
|
36
|
+
parameters: toToolParameters(messageSchema),
|
|
37
|
+
isReadOnly: false,
|
|
38
|
+
isConcurrencySafe: true,
|
|
39
|
+
call: async () => ({
|
|
40
|
+
ok: false,
|
|
41
|
+
error: 'AgentMessage requires session context',
|
|
42
|
+
}),
|
|
43
|
+
callWithContext: async (input, _signal, context) => {
|
|
44
|
+
const missing = needsContext(context);
|
|
45
|
+
if (missing)
|
|
46
|
+
return missing;
|
|
47
|
+
const task = getLiveAgentTask(context.sessionState.agentTasks, input.agent_id);
|
|
48
|
+
if (!task || task.status !== 'running') {
|
|
49
|
+
const saved = await loadAgentRecord(context, input.agent_id);
|
|
50
|
+
return saved
|
|
51
|
+
? {
|
|
52
|
+
ok: false,
|
|
53
|
+
error: `Agent ${input.agent_id} 当前为 ${saved.status};请使用 AgentFollowup 启动后续回合。`,
|
|
54
|
+
}
|
|
55
|
+
: { ok: false, error: `当前 Session 中不存在 Agent ${input.agent_id}` };
|
|
56
|
+
}
|
|
57
|
+
enqueueAgentMessage(task, input.message);
|
|
58
|
+
await saveAgentRecord(context, task);
|
|
59
|
+
await appendAgentEvent(context, task.id, {
|
|
60
|
+
phase: 'message',
|
|
61
|
+
message: input.message,
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
ok: true,
|
|
65
|
+
content: `消息已发送给 ${task.id},将在下一个模型边界生效。`,
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const listSchema = z.object({
|
|
70
|
+
include_completed: z.boolean().optional(),
|
|
71
|
+
});
|
|
72
|
+
export const agentListTool = {
|
|
73
|
+
name: 'AgentList',
|
|
74
|
+
description: 'Lists sub-agents owned by the current Session, including stable IDs, status and latest progress.',
|
|
75
|
+
inputSchema: listSchema,
|
|
76
|
+
parameters: toToolParameters(listSchema),
|
|
77
|
+
isReadOnly: true,
|
|
78
|
+
isConcurrencySafe: true,
|
|
79
|
+
call: async () => ({
|
|
80
|
+
ok: false,
|
|
81
|
+
error: 'AgentList requires session context',
|
|
82
|
+
}),
|
|
83
|
+
callWithContext: async (input, _signal, context) => {
|
|
84
|
+
const missing = needsContext(context);
|
|
85
|
+
if (missing)
|
|
86
|
+
return missing;
|
|
87
|
+
const records = (await listAgentRecords(context)).filter((record) => input.include_completed !== false || record.status === 'running');
|
|
88
|
+
return {
|
|
89
|
+
ok: true,
|
|
90
|
+
content: records.length
|
|
91
|
+
? JSON.stringify(records.map(snapshot), null, 2)
|
|
92
|
+
: '当前 Session 没有符合条件的子 Agent。',
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
const waitSchema = z.object({
|
|
97
|
+
agent_ids: z.array(agentId).min(1).max(8),
|
|
98
|
+
timeout_ms: z.number().int().min(0).max(120_000).optional(),
|
|
99
|
+
});
|
|
100
|
+
export const agentWaitTool = {
|
|
101
|
+
name: 'AgentWait',
|
|
102
|
+
description: 'Waits efficiently until any selected running sub-agent finishes or the timeout expires, then returns fresh snapshots for all selected IDs. Do not poll repeatedly.',
|
|
103
|
+
inputSchema: waitSchema,
|
|
104
|
+
parameters: toToolParameters(waitSchema),
|
|
105
|
+
isReadOnly: true,
|
|
106
|
+
isConcurrencySafe: true,
|
|
107
|
+
interruptBehavior: () => 'cancel',
|
|
108
|
+
call: async () => ({
|
|
109
|
+
ok: false,
|
|
110
|
+
error: 'AgentWait requires session context',
|
|
111
|
+
}),
|
|
112
|
+
callWithContext: async (input, signal, context) => {
|
|
113
|
+
const missing = needsContext(context);
|
|
114
|
+
if (missing)
|
|
115
|
+
return missing;
|
|
116
|
+
const live = input.agent_ids
|
|
117
|
+
.map((id) => getLiveAgentTask(context.sessionState.agentTasks, id))
|
|
118
|
+
.filter((task) => Boolean(task?.status === 'running'));
|
|
119
|
+
const timeoutMs = input.timeout_ms ?? 30_000;
|
|
120
|
+
if (live.length && timeoutMs > 0) {
|
|
121
|
+
let timer;
|
|
122
|
+
let onAbort;
|
|
123
|
+
const timeout = new Promise((resolve) => {
|
|
124
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
125
|
+
timer.unref?.();
|
|
126
|
+
});
|
|
127
|
+
const aborted = new Promise((resolve) => {
|
|
128
|
+
if (!signal)
|
|
129
|
+
return;
|
|
130
|
+
onAbort = () => resolve();
|
|
131
|
+
if (signal.aborted)
|
|
132
|
+
resolve();
|
|
133
|
+
else
|
|
134
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
135
|
+
});
|
|
136
|
+
await Promise.race([
|
|
137
|
+
...live.map((task) => task.completion),
|
|
138
|
+
timeout,
|
|
139
|
+
aborted,
|
|
140
|
+
]);
|
|
141
|
+
if (timer)
|
|
142
|
+
clearTimeout(timer);
|
|
143
|
+
if (signal && onAbort)
|
|
144
|
+
signal.removeEventListener('abort', onAbort);
|
|
145
|
+
if (signal?.aborted)
|
|
146
|
+
return { ok: false, error: 'aborted' };
|
|
147
|
+
}
|
|
148
|
+
const records = [];
|
|
149
|
+
const missingIds = [];
|
|
150
|
+
for (const id of input.agent_ids) {
|
|
151
|
+
const record = getLiveAgentTask(context.sessionState.agentTasks, id) ??
|
|
152
|
+
(await loadAgentRecord(context, id));
|
|
153
|
+
if (record)
|
|
154
|
+
records.push(record);
|
|
155
|
+
else
|
|
156
|
+
missingIds.push(id);
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
ok: true,
|
|
160
|
+
content: JSON.stringify({ agents: records.map(snapshot), missing: missingIds }, null, 2),
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
const interruptSchema = z.object({ agent_id: agentId });
|
|
165
|
+
export const agentInterruptTool = {
|
|
166
|
+
name: 'AgentInterrupt',
|
|
167
|
+
description: 'Interrupts one running sub-agent owned by the current Session. Its private history, progress and worktree are preserved for a later AgentFollowup.',
|
|
168
|
+
inputSchema: interruptSchema,
|
|
169
|
+
parameters: toToolParameters(interruptSchema),
|
|
170
|
+
isReadOnly: false,
|
|
171
|
+
isConcurrencySafe: true,
|
|
172
|
+
call: async () => ({
|
|
173
|
+
ok: false,
|
|
174
|
+
error: 'AgentInterrupt requires session context',
|
|
175
|
+
}),
|
|
176
|
+
callWithContext: async (input, _signal, context) => {
|
|
177
|
+
const missing = needsContext(context);
|
|
178
|
+
if (missing)
|
|
179
|
+
return missing;
|
|
180
|
+
const live = getLiveAgentTask(context.sessionState.agentTasks, input.agent_id);
|
|
181
|
+
if (!live || live.status !== 'running') {
|
|
182
|
+
const saved = await loadAgentRecord(context, input.agent_id);
|
|
183
|
+
return saved
|
|
184
|
+
? {
|
|
185
|
+
ok: true,
|
|
186
|
+
content: `Agent ${input.agent_id} 已经是 ${saved.status},未执行中断。`,
|
|
187
|
+
}
|
|
188
|
+
: { ok: false, error: `当前 Session 中不存在 Agent ${input.agent_id}` };
|
|
189
|
+
}
|
|
190
|
+
const previous = live.status;
|
|
191
|
+
live.abort.abort(new Error('interrupted-by-parent-agent'));
|
|
192
|
+
await Promise.race([
|
|
193
|
+
live.completion,
|
|
194
|
+
new Promise((resolve) => setTimeout(resolve, 5_000)),
|
|
195
|
+
]);
|
|
196
|
+
return {
|
|
197
|
+
ok: true,
|
|
198
|
+
content: `已中断 ${live.id}(先前状态:${previous};当前状态:${live.status})。`,
|
|
199
|
+
};
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
const followupSchema = z.object({
|
|
203
|
+
agent_id: agentId,
|
|
204
|
+
message: z.string().min(1).max(100_000),
|
|
205
|
+
run_in_background: z.boolean().optional(),
|
|
206
|
+
});
|
|
207
|
+
export const agentFollowupTool = {
|
|
208
|
+
name: 'AgentFollowup',
|
|
209
|
+
description: 'Adds a follow-up task to a stable sub-agent. If it is running, delivers the message at the next model boundary; if idle, resumes its persisted private history and starts a new turn.',
|
|
210
|
+
inputSchema: followupSchema,
|
|
211
|
+
parameters: toToolParameters(followupSchema),
|
|
212
|
+
isReadOnly: false,
|
|
213
|
+
isConcurrencySafe: true,
|
|
214
|
+
interruptBehavior: () => 'block',
|
|
215
|
+
call: async () => ({
|
|
216
|
+
ok: false,
|
|
217
|
+
error: 'AgentFollowup requires session context',
|
|
218
|
+
}),
|
|
219
|
+
callWithContext: async (input, signal, context) => {
|
|
220
|
+
const missing = needsContext(context);
|
|
221
|
+
if (missing)
|
|
222
|
+
return missing;
|
|
223
|
+
const live = getLiveAgentTask(context.sessionState.agentTasks, input.agent_id);
|
|
224
|
+
if (live?.status === 'running') {
|
|
225
|
+
enqueueAgentMessage(live, input.message);
|
|
226
|
+
await saveAgentRecord(context, live);
|
|
227
|
+
await appendAgentEvent(context, live.id, {
|
|
228
|
+
phase: 'followup',
|
|
229
|
+
message: input.message,
|
|
230
|
+
});
|
|
231
|
+
return { ok: true, content: `后续任务已发送给运行中的 ${live.id}。` };
|
|
232
|
+
}
|
|
233
|
+
const saved = await loadAgentRecord(context, input.agent_id);
|
|
234
|
+
if (!saved)
|
|
235
|
+
return {
|
|
236
|
+
ok: false,
|
|
237
|
+
error: `当前 Session 中不存在 Agent ${input.agent_id}`,
|
|
238
|
+
};
|
|
239
|
+
return runManagedAgentTask({
|
|
240
|
+
description: saved.description,
|
|
241
|
+
prompt: input.message,
|
|
242
|
+
resume_agent_id: input.agent_id,
|
|
243
|
+
run_in_background: input.run_in_background ?? true,
|
|
244
|
+
}, signal, context);
|
|
245
|
+
},
|
|
246
|
+
};
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
import type { Tool, ToolCallContext, ToolResult } from '../../types.js';
|
|
4
|
+
import { toToolParameters } from '../../utils/zodToJson.js';
|
|
5
|
+
import { runManagedAgentTask } from './agent.js';
|
|
6
|
+
import {
|
|
7
|
+
type AgentTaskRecord,
|
|
8
|
+
appendAgentEvent,
|
|
9
|
+
enqueueAgentMessage,
|
|
10
|
+
getLiveAgentTask,
|
|
11
|
+
listAgentRecords,
|
|
12
|
+
loadAgentRecord,
|
|
13
|
+
saveAgentRecord,
|
|
14
|
+
} from './agentTaskService.js';
|
|
15
|
+
|
|
16
|
+
const agentId = z.string().regex(/^agent_[0-9a-f-]{36}$/i);
|
|
17
|
+
|
|
18
|
+
function needsContext(context: ToolCallContext): ToolResult | undefined {
|
|
19
|
+
if (!context.sessionState)
|
|
20
|
+
return { ok: false, error: 'Agent 控制工具需要当前 Session 运行状态。' };
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function snapshot(record: AgentTaskRecord) {
|
|
25
|
+
return {
|
|
26
|
+
agent_id: record.id,
|
|
27
|
+
status: record.status,
|
|
28
|
+
description: record.description,
|
|
29
|
+
progress: record.progress,
|
|
30
|
+
created_at: record.createdAt,
|
|
31
|
+
updated_at: record.updatedAt,
|
|
32
|
+
result: record.result
|
|
33
|
+
? record.result.ok
|
|
34
|
+
? record.result.content.slice(0, 4_000)
|
|
35
|
+
: `Error: ${record.result.error.slice(0, 4_000)}`
|
|
36
|
+
: undefined,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const messageSchema = z.object({
|
|
41
|
+
agent_id: agentId,
|
|
42
|
+
message: z.string().min(1).max(100_000),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const agentMessageTool: Tool<z.infer<typeof messageSchema>> = {
|
|
46
|
+
name: 'AgentMessage',
|
|
47
|
+
description:
|
|
48
|
+
'Sends additional context or a correction to one running sub-agent by stable agent_id. ' +
|
|
49
|
+
'The message is inserted at the next model boundary without cancelling its current tool call. ' +
|
|
50
|
+
'Use AgentFollowup instead when the agent is already idle or completed.',
|
|
51
|
+
inputSchema: messageSchema,
|
|
52
|
+
parameters: toToolParameters(messageSchema),
|
|
53
|
+
isReadOnly: false,
|
|
54
|
+
isConcurrencySafe: true,
|
|
55
|
+
call: async () => ({
|
|
56
|
+
ok: false,
|
|
57
|
+
error: 'AgentMessage requires session context',
|
|
58
|
+
}),
|
|
59
|
+
callWithContext: async (input, _signal, context) => {
|
|
60
|
+
const missing = needsContext(context);
|
|
61
|
+
if (missing) return missing;
|
|
62
|
+
const task = getLiveAgentTask(
|
|
63
|
+
context.sessionState!.agentTasks,
|
|
64
|
+
input.agent_id,
|
|
65
|
+
);
|
|
66
|
+
if (!task || task.status !== 'running') {
|
|
67
|
+
const saved = await loadAgentRecord(context, input.agent_id);
|
|
68
|
+
return saved
|
|
69
|
+
? {
|
|
70
|
+
ok: false,
|
|
71
|
+
error: `Agent ${input.agent_id} 当前为 ${saved.status};请使用 AgentFollowup 启动后续回合。`,
|
|
72
|
+
}
|
|
73
|
+
: { ok: false, error: `当前 Session 中不存在 Agent ${input.agent_id}` };
|
|
74
|
+
}
|
|
75
|
+
enqueueAgentMessage(task, input.message);
|
|
76
|
+
await saveAgentRecord(context, task);
|
|
77
|
+
await appendAgentEvent(context, task.id, {
|
|
78
|
+
phase: 'message',
|
|
79
|
+
message: input.message,
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
ok: true,
|
|
83
|
+
content: `消息已发送给 ${task.id},将在下一个模型边界生效。`,
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const listSchema = z.object({
|
|
89
|
+
include_completed: z.boolean().optional(),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export const agentListTool: Tool<z.infer<typeof listSchema>> = {
|
|
93
|
+
name: 'AgentList',
|
|
94
|
+
description:
|
|
95
|
+
'Lists sub-agents owned by the current Session, including stable IDs, status and latest progress.',
|
|
96
|
+
inputSchema: listSchema,
|
|
97
|
+
parameters: toToolParameters(listSchema),
|
|
98
|
+
isReadOnly: true,
|
|
99
|
+
isConcurrencySafe: true,
|
|
100
|
+
call: async () => ({
|
|
101
|
+
ok: false,
|
|
102
|
+
error: 'AgentList requires session context',
|
|
103
|
+
}),
|
|
104
|
+
callWithContext: async (input, _signal, context) => {
|
|
105
|
+
const missing = needsContext(context);
|
|
106
|
+
if (missing) return missing;
|
|
107
|
+
const records = (await listAgentRecords(context)).filter(
|
|
108
|
+
(record) =>
|
|
109
|
+
input.include_completed !== false || record.status === 'running',
|
|
110
|
+
);
|
|
111
|
+
return {
|
|
112
|
+
ok: true,
|
|
113
|
+
content: records.length
|
|
114
|
+
? JSON.stringify(records.map(snapshot), null, 2)
|
|
115
|
+
: '当前 Session 没有符合条件的子 Agent。',
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const waitSchema = z.object({
|
|
121
|
+
agent_ids: z.array(agentId).min(1).max(8),
|
|
122
|
+
timeout_ms: z.number().int().min(0).max(120_000).optional(),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
export const agentWaitTool: Tool<z.infer<typeof waitSchema>> = {
|
|
126
|
+
name: 'AgentWait',
|
|
127
|
+
description:
|
|
128
|
+
'Waits efficiently until any selected running sub-agent finishes or the timeout expires, then returns fresh snapshots for all selected IDs. Do not poll repeatedly.',
|
|
129
|
+
inputSchema: waitSchema,
|
|
130
|
+
parameters: toToolParameters(waitSchema),
|
|
131
|
+
isReadOnly: true,
|
|
132
|
+
isConcurrencySafe: true,
|
|
133
|
+
interruptBehavior: () => 'cancel',
|
|
134
|
+
call: async () => ({
|
|
135
|
+
ok: false,
|
|
136
|
+
error: 'AgentWait requires session context',
|
|
137
|
+
}),
|
|
138
|
+
callWithContext: async (input, signal, context) => {
|
|
139
|
+
const missing = needsContext(context);
|
|
140
|
+
if (missing) return missing;
|
|
141
|
+
const live = input.agent_ids
|
|
142
|
+
.map((id) => getLiveAgentTask(context.sessionState!.agentTasks, id))
|
|
143
|
+
.filter((task): task is NonNullable<typeof task> =>
|
|
144
|
+
Boolean(task?.status === 'running'),
|
|
145
|
+
);
|
|
146
|
+
const timeoutMs = input.timeout_ms ?? 30_000;
|
|
147
|
+
if (live.length && timeoutMs > 0) {
|
|
148
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
149
|
+
let onAbort: (() => void) | undefined;
|
|
150
|
+
const timeout = new Promise<void>((resolve) => {
|
|
151
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
152
|
+
timer.unref?.();
|
|
153
|
+
});
|
|
154
|
+
const aborted = new Promise<void>((resolve) => {
|
|
155
|
+
if (!signal) return;
|
|
156
|
+
onAbort = () => resolve();
|
|
157
|
+
if (signal.aborted) resolve();
|
|
158
|
+
else signal.addEventListener('abort', onAbort, { once: true });
|
|
159
|
+
});
|
|
160
|
+
await Promise.race([
|
|
161
|
+
...live.map((task) => task.completion),
|
|
162
|
+
timeout,
|
|
163
|
+
aborted,
|
|
164
|
+
]);
|
|
165
|
+
if (timer) clearTimeout(timer);
|
|
166
|
+
if (signal && onAbort) signal.removeEventListener('abort', onAbort);
|
|
167
|
+
if (signal?.aborted) return { ok: false, error: 'aborted' };
|
|
168
|
+
}
|
|
169
|
+
const records: AgentTaskRecord[] = [];
|
|
170
|
+
const missingIds: string[] = [];
|
|
171
|
+
for (const id of input.agent_ids) {
|
|
172
|
+
const record =
|
|
173
|
+
getLiveAgentTask(context.sessionState!.agentTasks, id) ??
|
|
174
|
+
(await loadAgentRecord(context, id));
|
|
175
|
+
if (record) records.push(record);
|
|
176
|
+
else missingIds.push(id);
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
ok: true,
|
|
180
|
+
content: JSON.stringify(
|
|
181
|
+
{ agents: records.map(snapshot), missing: missingIds },
|
|
182
|
+
null,
|
|
183
|
+
2,
|
|
184
|
+
),
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const interruptSchema = z.object({ agent_id: agentId });
|
|
190
|
+
|
|
191
|
+
export const agentInterruptTool: Tool<z.infer<typeof interruptSchema>> = {
|
|
192
|
+
name: 'AgentInterrupt',
|
|
193
|
+
description:
|
|
194
|
+
'Interrupts one running sub-agent owned by the current Session. Its private history, progress and worktree are preserved for a later AgentFollowup.',
|
|
195
|
+
inputSchema: interruptSchema,
|
|
196
|
+
parameters: toToolParameters(interruptSchema),
|
|
197
|
+
isReadOnly: false,
|
|
198
|
+
isConcurrencySafe: true,
|
|
199
|
+
call: async () => ({
|
|
200
|
+
ok: false,
|
|
201
|
+
error: 'AgentInterrupt requires session context',
|
|
202
|
+
}),
|
|
203
|
+
callWithContext: async (input, _signal, context) => {
|
|
204
|
+
const missing = needsContext(context);
|
|
205
|
+
if (missing) return missing;
|
|
206
|
+
const live = getLiveAgentTask(
|
|
207
|
+
context.sessionState!.agentTasks,
|
|
208
|
+
input.agent_id,
|
|
209
|
+
);
|
|
210
|
+
if (!live || live.status !== 'running') {
|
|
211
|
+
const saved = await loadAgentRecord(context, input.agent_id);
|
|
212
|
+
return saved
|
|
213
|
+
? {
|
|
214
|
+
ok: true,
|
|
215
|
+
content: `Agent ${input.agent_id} 已经是 ${saved.status},未执行中断。`,
|
|
216
|
+
}
|
|
217
|
+
: { ok: false, error: `当前 Session 中不存在 Agent ${input.agent_id}` };
|
|
218
|
+
}
|
|
219
|
+
const previous = live.status;
|
|
220
|
+
live.abort.abort(new Error('interrupted-by-parent-agent'));
|
|
221
|
+
await Promise.race([
|
|
222
|
+
live.completion,
|
|
223
|
+
new Promise<void>((resolve) => setTimeout(resolve, 5_000)),
|
|
224
|
+
]);
|
|
225
|
+
return {
|
|
226
|
+
ok: true,
|
|
227
|
+
content: `已中断 ${live.id}(先前状态:${previous};当前状态:${live.status})。`,
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const followupSchema = z.object({
|
|
233
|
+
agent_id: agentId,
|
|
234
|
+
message: z.string().min(1).max(100_000),
|
|
235
|
+
run_in_background: z.boolean().optional(),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
export const agentFollowupTool: Tool<z.infer<typeof followupSchema>> = {
|
|
239
|
+
name: 'AgentFollowup',
|
|
240
|
+
description:
|
|
241
|
+
'Adds a follow-up task to a stable sub-agent. If it is running, delivers the message at the next model boundary; if idle, resumes its persisted private history and starts a new turn.',
|
|
242
|
+
inputSchema: followupSchema,
|
|
243
|
+
parameters: toToolParameters(followupSchema),
|
|
244
|
+
isReadOnly: false,
|
|
245
|
+
isConcurrencySafe: true,
|
|
246
|
+
interruptBehavior: () => 'block',
|
|
247
|
+
call: async () => ({
|
|
248
|
+
ok: false,
|
|
249
|
+
error: 'AgentFollowup requires session context',
|
|
250
|
+
}),
|
|
251
|
+
callWithContext: async (input, signal, context) => {
|
|
252
|
+
const missing = needsContext(context);
|
|
253
|
+
if (missing) return missing;
|
|
254
|
+
const live = getLiveAgentTask(
|
|
255
|
+
context.sessionState!.agentTasks,
|
|
256
|
+
input.agent_id,
|
|
257
|
+
);
|
|
258
|
+
if (live?.status === 'running') {
|
|
259
|
+
enqueueAgentMessage(live, input.message);
|
|
260
|
+
await saveAgentRecord(context, live);
|
|
261
|
+
await appendAgentEvent(context, live.id, {
|
|
262
|
+
phase: 'followup',
|
|
263
|
+
message: input.message,
|
|
264
|
+
});
|
|
265
|
+
return { ok: true, content: `后续任务已发送给运行中的 ${live.id}。` };
|
|
266
|
+
}
|
|
267
|
+
const saved = await loadAgentRecord(context, input.agent_id);
|
|
268
|
+
if (!saved)
|
|
269
|
+
return {
|
|
270
|
+
ok: false,
|
|
271
|
+
error: `当前 Session 中不存在 Agent ${input.agent_id}`,
|
|
272
|
+
};
|
|
273
|
+
return runManagedAgentTask(
|
|
274
|
+
{
|
|
275
|
+
description: saved.description,
|
|
276
|
+
prompt: input.message,
|
|
277
|
+
resume_agent_id: input.agent_id,
|
|
278
|
+
run_in_background: input.run_in_background ?? true,
|
|
279
|
+
},
|
|
280
|
+
signal,
|
|
281
|
+
context,
|
|
282
|
+
);
|
|
283
|
+
},
|
|
284
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { appendFile, mkdir } from 'node:fs/promises';
|
|
1
|
+
import { appendFile, mkdir, readdir } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { readRuntimeJson, sessionRuntimeDir, withRuntimeFileLock, writeRuntimeJson, } from '../../session/runtimeStore.js';
|
|
4
4
|
export function createAgentTaskState() {
|
|
@@ -49,6 +49,45 @@ export async function loadAgentRecord(ctx, id) {
|
|
|
49
49
|
export function getLiveAgentTask(state, id) {
|
|
50
50
|
return state?.tasks.get(id);
|
|
51
51
|
}
|
|
52
|
+
/** List the durable tasks owned by this Session, with process-local state winning. */
|
|
53
|
+
export async function listAgentRecords(ctx) {
|
|
54
|
+
const root = join(sessionRuntimeDir(ctx), 'agents');
|
|
55
|
+
const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
|
|
56
|
+
const records = new Map();
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
if (!entry.isDirectory() || !/^agent_[0-9a-f-]{36}$/i.test(entry.name))
|
|
59
|
+
continue;
|
|
60
|
+
const record = await loadAgentRecord(ctx, entry.name);
|
|
61
|
+
if (record)
|
|
62
|
+
records.set(record.id, record);
|
|
63
|
+
}
|
|
64
|
+
for (const live of ctx.sessionState?.agentTasks.tasks.values() ?? [])
|
|
65
|
+
records.set(live.id, live);
|
|
66
|
+
return [...records.values()].sort((a, b) => b.updatedAt - a.updatedAt);
|
|
67
|
+
}
|
|
68
|
+
export function agentMessage(message) {
|
|
69
|
+
return {
|
|
70
|
+
role: 'user',
|
|
71
|
+
content: `[主 Agent 后续消息]\n${message}`,
|
|
72
|
+
timestamp: Date.now(),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** Deliver at the next model-message boundary without aborting the active turn. */
|
|
76
|
+
export function enqueueAgentMessage(task, message) {
|
|
77
|
+
if (task.history)
|
|
78
|
+
task.history.push(agentMessage(message));
|
|
79
|
+
else
|
|
80
|
+
task.inbox.push(message);
|
|
81
|
+
task.updatedAt = Date.now();
|
|
82
|
+
task.events.emit('change');
|
|
83
|
+
}
|
|
84
|
+
/** Attach the live private history and flush messages accepted during startup. */
|
|
85
|
+
export function attachAgentHistory(task, history) {
|
|
86
|
+
task.history = history;
|
|
87
|
+
for (const message of task.inbox.splice(0))
|
|
88
|
+
history.push(agentMessage(message));
|
|
89
|
+
task.events.emit('change');
|
|
90
|
+
}
|
|
52
91
|
export async function stopAllAgentTasks(state) {
|
|
53
92
|
const running = [...state.tasks.values()].filter((t) => t.status === 'running');
|
|
54
93
|
running.forEach((t) => t.abort.abort());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
-
import { appendFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { appendFile, mkdir, readdir } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import type { Message, ToolCallContext, ToolResult } from '../../types.js';
|
|
5
5
|
import type { AgentWorktree } from './worktree.js';
|
|
@@ -28,6 +28,8 @@ export interface LiveAgentTask extends AgentTaskRecord {
|
|
|
28
28
|
abort: AbortController;
|
|
29
29
|
completion: Promise<void>;
|
|
30
30
|
events: EventEmitter;
|
|
31
|
+
/** Messages accepted before the private history is ready are flushed in order. */
|
|
32
|
+
inbox: string[];
|
|
31
33
|
}
|
|
32
34
|
export interface AgentTaskState {
|
|
33
35
|
tasks: Map<string, LiveAgentTask>;
|
|
@@ -100,6 +102,47 @@ export function getLiveAgentTask(
|
|
|
100
102
|
): LiveAgentTask | undefined {
|
|
101
103
|
return state?.tasks.get(id);
|
|
102
104
|
}
|
|
105
|
+
|
|
106
|
+
/** List the durable tasks owned by this Session, with process-local state winning. */
|
|
107
|
+
export async function listAgentRecords(
|
|
108
|
+
ctx: ToolCallContext,
|
|
109
|
+
): Promise<AgentTaskRecord[]> {
|
|
110
|
+
const root = join(sessionRuntimeDir(ctx), 'agents');
|
|
111
|
+
const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
|
|
112
|
+
const records = new Map<string, AgentTaskRecord>();
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
if (!entry.isDirectory() || !/^agent_[0-9a-f-]{36}$/i.test(entry.name))
|
|
115
|
+
continue;
|
|
116
|
+
const record = await loadAgentRecord(ctx, entry.name);
|
|
117
|
+
if (record) records.set(record.id, record);
|
|
118
|
+
}
|
|
119
|
+
for (const live of ctx.sessionState?.agentTasks.tasks.values() ?? [])
|
|
120
|
+
records.set(live.id, live);
|
|
121
|
+
return [...records.values()].sort((a, b) => b.updatedAt - a.updatedAt);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function agentMessage(message: string): Message {
|
|
125
|
+
return {
|
|
126
|
+
role: 'user',
|
|
127
|
+
content: `[主 Agent 后续消息]\n${message}`,
|
|
128
|
+
timestamp: Date.now(),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Deliver at the next model-message boundary without aborting the active turn. */
|
|
133
|
+
export function enqueueAgentMessage(task: LiveAgentTask, message: string): void {
|
|
134
|
+
if (task.history) task.history.push(agentMessage(message));
|
|
135
|
+
else task.inbox.push(message);
|
|
136
|
+
task.updatedAt = Date.now();
|
|
137
|
+
task.events.emit('change');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Attach the live private history and flush messages accepted during startup. */
|
|
141
|
+
export function attachAgentHistory(task: LiveAgentTask, history: Message[]): void {
|
|
142
|
+
task.history = history;
|
|
143
|
+
for (const message of task.inbox.splice(0)) history.push(agentMessage(message));
|
|
144
|
+
task.events.emit('change');
|
|
145
|
+
}
|
|
103
146
|
export async function stopAllAgentTasks(state: AgentTaskState): Promise<void> {
|
|
104
147
|
const running = [...state.tasks.values()].filter(
|
|
105
148
|
(t) => t.status === 'running',
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* (两次规则:真实需要出现两次再议)。
|
|
14
14
|
* ============================================================
|
|
15
15
|
*/
|
|
16
|
+
import { DEFAULT_SUBAGENTS_CONFIG } from '../../config/configDefaults.js';
|
|
16
17
|
/**
|
|
17
18
|
* 任何 agent_type 都排除的工具:
|
|
18
19
|
* - Agent:防递归 fork(子 agent 再 fork 子 agent,深度失控)。
|
|
@@ -20,7 +21,13 @@
|
|
|
20
21
|
*/
|
|
21
22
|
export const SUBAGENT_EXCLUDED_TOOLS = [
|
|
22
23
|
'Agent',
|
|
24
|
+
'AgentMessage',
|
|
25
|
+
'AgentList',
|
|
26
|
+
'AgentWait',
|
|
27
|
+
'AgentInterrupt',
|
|
28
|
+
'AgentFollowup',
|
|
23
29
|
'Advisor',
|
|
30
|
+
'AdvisorDecision',
|
|
24
31
|
// 子任务只向主 Agent 汇报;正式用户交付由主 Agent 统一收口,避免重复结果卡。
|
|
25
32
|
'PresentResult',
|
|
26
33
|
'RememberMemory',
|
|
@@ -41,6 +48,8 @@ export const EXPLORE_ALLOWED_TOOLS = [
|
|
|
41
48
|
'WebSearch',
|
|
42
49
|
'WebFetch',
|
|
43
50
|
'WebBrowser',
|
|
51
|
+
'BrowserBatch',
|
|
52
|
+
'BrowserCDP',
|
|
44
53
|
'RecallMemory',
|
|
45
54
|
'ListMemories',
|
|
46
55
|
'ReviewMemories',
|
|
@@ -53,16 +62,19 @@ const EXPLORE_APPENDIX = `# 本次子任务类型:只读调研(explore)
|
|
|
53
62
|
严格使用已提供的只读工具。报告给出结论、关键证据和没查到的缺口。`;
|
|
54
63
|
const GENERAL_APPENDIX = `# 本次子任务类型:读写执行(general)
|
|
55
64
|
只做任务书范围内的修改;报告列出改动文件和验证结果。`;
|
|
65
|
+
// 轮数上限的**唯一真值**在 configDefaults.ts。这里只是「没有 subagentConfig 时」的
|
|
66
|
+
// 兜底取值,必须与那份一致 —— 曾经两边各写一份字面量(都是 200/100),
|
|
67
|
+
// 改一处漏一处就会出现「有配置时 200、没配置时 50」这种只在缺省路径显形的分裂。
|
|
56
68
|
const EXPLORE_DEF = {
|
|
57
69
|
type: 'explore',
|
|
58
70
|
resolveAllowedTools: (all) => all.filter((n) => EXPLORE_ALLOWED_TOOLS.includes(n)),
|
|
59
|
-
maxTurns:
|
|
71
|
+
maxTurns: DEFAULT_SUBAGENTS_CONFIG.exploreMaxTurns,
|
|
60
72
|
promptAppendix: EXPLORE_APPENDIX,
|
|
61
73
|
};
|
|
62
74
|
const GENERAL_DEF = {
|
|
63
75
|
type: 'general',
|
|
64
76
|
resolveAllowedTools: (all) => all.filter((n) => !SUBAGENT_EXCLUDED_TOOLS.includes(n)),
|
|
65
|
-
maxTurns:
|
|
77
|
+
maxTurns: DEFAULT_SUBAGENTS_CONFIG.generalMaxTurns,
|
|
66
78
|
promptAppendix: GENERAL_APPENDIX,
|
|
67
79
|
};
|
|
68
80
|
/** 未知/缺省一律回落 explore(最安全的默认:只读)。 */
|