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
package/src/ui/hooks/useChat.ts
CHANGED
|
@@ -15,50 +15,79 @@
|
|
|
15
15
|
* ============================================================
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
19
18
|
import { stat } from 'node:fs/promises';
|
|
19
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
20
20
|
|
|
21
|
+
import {
|
|
22
|
+
type AskAnswer,
|
|
23
|
+
type AskQuestionSpec,
|
|
24
|
+
type AskSource,
|
|
25
|
+
createAskCoordinator,
|
|
26
|
+
setAskHandler,
|
|
27
|
+
} from '../../askBridge.js';
|
|
21
28
|
import { getWorkingDir, setWorkingDir } from '../../bootstrap/workingDir.js';
|
|
29
|
+
import type { ComputerUseCliMode } from '../../cli/computerUse.js';
|
|
30
|
+
import {
|
|
31
|
+
createCliComputerRun,
|
|
32
|
+
createComputerUseHostGate,
|
|
33
|
+
} from '../../cli/computerUse.js';
|
|
22
34
|
import { forceCompact } from '../../context/compact.js';
|
|
35
|
+
import { acquireContextLock } from '../../context/contextLock.js';
|
|
23
36
|
import {
|
|
24
37
|
clearContext,
|
|
25
38
|
loadContext,
|
|
26
39
|
saveContext,
|
|
27
40
|
} from '../../context/persistContext.js';
|
|
28
41
|
import { resetReactiveCompactState } from '../../context/reactiveCompact.js';
|
|
29
|
-
import {
|
|
30
|
-
|
|
42
|
+
import {
|
|
43
|
+
resolveSessionFile,
|
|
44
|
+
sessionFileFor,
|
|
45
|
+
} from '../../context/sessionPath.js';
|
|
31
46
|
import {
|
|
32
47
|
getActiveSession,
|
|
48
|
+
listSessionSummaries,
|
|
33
49
|
setActiveSession,
|
|
34
50
|
updateSessionMetadata,
|
|
35
51
|
} from '../../context/sessionRegistry.js';
|
|
52
|
+
import { workspaceIndexService } from '../../context/workspaceIndex.js';
|
|
36
53
|
import {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
} from '../../
|
|
40
|
-
import { runQuery } from '../../loop.js';
|
|
41
|
-
import { buildBaseSystemPrompt, buildTransientPromptBundle } from '../../prompts/system.js';
|
|
54
|
+
HumanInterventionCoordinator,
|
|
55
|
+
type PendingHumanIntervention,
|
|
56
|
+
} from '../../humanIntervention.js';
|
|
42
57
|
import { createPromptCacheContext } from '../../llm/promptCache.js';
|
|
58
|
+
import { runQuery } from '../../loop.js';
|
|
59
|
+
import {
|
|
60
|
+
type TurnJournal,
|
|
61
|
+
startTurnJournal,
|
|
62
|
+
} from '../../memory/turnJournal.js';
|
|
63
|
+
import { createInputQueue } from '../../messageQueue.js';
|
|
64
|
+
import type { PluginEvent } from '../../plugins/pluginApi.js';
|
|
65
|
+
import { runWithPlugins } from '../../plugins/pluginRunner.js';
|
|
66
|
+
import {
|
|
67
|
+
buildBaseSystemPrompt,
|
|
68
|
+
buildTransientPromptBundle,
|
|
69
|
+
} from '../../prompts/system.js';
|
|
70
|
+
import {
|
|
71
|
+
refreshStableSystemPrompt,
|
|
72
|
+
upsertStableSystemMessage,
|
|
73
|
+
} from '../../prompts/stableSystemPrompt.js';
|
|
43
74
|
import {
|
|
44
75
|
createAgentRuntimeContext,
|
|
45
76
|
filterToolsForRuntime,
|
|
46
77
|
memoryContextFromRuntime,
|
|
47
78
|
} from '../../runtime/agentRuntimeContext.js';
|
|
48
|
-
import { startTurnJournal, type TurnJournal } from '../../memory/turnJournal.js';
|
|
49
|
-
import { ALL_TOOLS, getToolByName } from '../../tools/index.js';
|
|
50
|
-
import { createInputQueue } from '../../messageQueue.js';
|
|
51
79
|
import {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
} from '../../
|
|
58
|
-
import {
|
|
59
|
-
import {
|
|
80
|
+
getOrCreateSessionState,
|
|
81
|
+
sessionStateKey,
|
|
82
|
+
} from '../../session/sessionState.js';
|
|
83
|
+
import { filterToolsForCategories } from '../../team/toolPolicy.js';
|
|
84
|
+
import { runAdvisor } from '../../tools/advisor/advisor.js';
|
|
85
|
+
import { classifyComputerAutomationIntent } from '../../tools/computeruse/computerIntent.js';
|
|
86
|
+
import { computerUseService } from '../../tools/computeruse/computerUseService.js';
|
|
87
|
+
import { createComputerInterventionAdapter } from '../../tools/computeruse/intervention.js';
|
|
88
|
+
import type { ComputerUseRunContext } from '../../tools/computeruse/protocol.js';
|
|
89
|
+
import { ALL_TOOLS, getToolByName } from '../../tools/index.js';
|
|
60
90
|
import { clearFileState } from '../../tools/shared/fileState.js';
|
|
61
|
-
import { getOrCreateSessionState, sessionStateKey } from '../../session/sessionState.js';
|
|
62
91
|
import { hydrateSessionWorktree } from '../../tools/worktree/sessionWorktree.js';
|
|
63
92
|
import type {
|
|
64
93
|
LoopEvent,
|
|
@@ -68,23 +97,8 @@ import type {
|
|
|
68
97
|
ToolResult,
|
|
69
98
|
ToolStatusState,
|
|
70
99
|
} from '../../types.js';
|
|
71
|
-
import { runAdvisor } from '../../tools/advisor/advisor.js';
|
|
72
|
-
import type { PluginEvent } from '../../plugins/pluginApi.js';
|
|
73
|
-
import { runWithPlugins } from '../../plugins/pluginRunner.js';
|
|
74
100
|
import { dlog } from '../../utils/debugLog.js';
|
|
75
|
-
import
|
|
76
|
-
import { createCliComputerRun, createComputerUseHostGate } from '../../cli/computerUse.js';
|
|
77
|
-
import {
|
|
78
|
-
computerUseService,
|
|
79
|
-
} from '../../tools/computeruse/computerUseService.js';
|
|
80
|
-
import {
|
|
81
|
-
HumanInterventionCoordinator,
|
|
82
|
-
type PendingHumanIntervention,
|
|
83
|
-
} from '../../humanIntervention.js';
|
|
84
|
-
import { createComputerInterventionAdapter } from '../../tools/computeruse/intervention.js';
|
|
85
|
-
import type {
|
|
86
|
-
ComputerUseRunContext,
|
|
87
|
-
} from '../../tools/computeruse/protocol.js';
|
|
101
|
+
import { createAskSlot } from './askSlot.js';
|
|
88
102
|
|
|
89
103
|
export interface PluginProgressState {
|
|
90
104
|
pluginId: string;
|
|
@@ -95,7 +109,10 @@ export interface PluginProgressState {
|
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
/** loop.ts 每轮 yield 的 context_usage 事件(去掉 type 字段)。 */
|
|
98
|
-
export type ContextUsageInfo = Omit<
|
|
112
|
+
export type ContextUsageInfo = Omit<
|
|
113
|
+
Extract<LoopEvent, { type: 'context_usage' }>,
|
|
114
|
+
'type'
|
|
115
|
+
>;
|
|
99
116
|
|
|
100
117
|
export interface UseChatResult {
|
|
101
118
|
history: Message[];
|
|
@@ -285,7 +302,10 @@ function useThrottledFlush({
|
|
|
285
302
|
const append = useCallback(
|
|
286
303
|
(delta: string) => {
|
|
287
304
|
bufferRef.current += delta;
|
|
288
|
-
if (
|
|
305
|
+
if (
|
|
306
|
+
typeof maxChars === 'number' &&
|
|
307
|
+
bufferRef.current.length >= maxChars
|
|
308
|
+
) {
|
|
289
309
|
flush();
|
|
290
310
|
return;
|
|
291
311
|
}
|
|
@@ -322,21 +342,11 @@ export function useChat(args: {
|
|
|
322
342
|
const [transientError, setTransientError] = useState<string | null>(null);
|
|
323
343
|
const [interrupted, setInterrupted] = useState(false);
|
|
324
344
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
* 等 step 结束才决定丢弃 or 提升为永久红字)。
|
|
331
|
-
* handleEvent 通过 setters.workflowCtx 同步读写这个对象(pure 逻辑,测试可注入 stub)。
|
|
332
|
-
*/
|
|
333
|
-
const workflowCtxRef = useRef<{
|
|
334
|
-
activeStepId: string | null;
|
|
335
|
-
pendingLlmError: string | null;
|
|
336
|
-
}>({ activeStepId: null, pendingLlmError: null });
|
|
337
|
-
// 工作流步骤 id → 人话进度名(title)映射:start 记入、end/skipped 回查,
|
|
338
|
-
// 让 scrollback 三种进度行(▶/✓/⊘)都显示同一人话名而非 id。跨事件持 ref。
|
|
339
|
-
const stepTitlesRef = useRef<Map<string, string>>(new Map());
|
|
345
|
+
// 注:这里曾有 workflowCtxRef(activeStepId / pendingLlmError)与 stepTitlesRef,
|
|
346
|
+
// 服务于 yaml DSL 的 workflow_step_* 事件。那些事件随引擎删除后没有任何发送方,
|
|
347
|
+
// 于是 activeStepId 恒为 null、两条依赖它的暂态错误分支永远走不到 —— 一并删掉。
|
|
348
|
+
// 代码编排引擎把 llm_error / max_turns 在 api.ts 内部消化(不外泄给顶层),
|
|
349
|
+
// 不需要宿主再做这层「暂态还是永久」的裁决。
|
|
340
350
|
const [pluginProgress, setPluginProgress] =
|
|
341
351
|
useState<PluginProgressState | null>(null);
|
|
342
352
|
|
|
@@ -350,22 +360,31 @@ export function useChat(args: {
|
|
|
350
360
|
* 比 useTokenUsage 的本地估算更准;未收到过(如刚启动、纯只读问答走了只读快速
|
|
351
361
|
* 路径)时该值仍是 null,StatusLine 降级回 useTokenUsage 估算。
|
|
352
362
|
*/
|
|
353
|
-
const [contextUsage, setContextUsage] = useState<ContextUsageInfo | null>(
|
|
363
|
+
const [contextUsage, setContextUsage] = useState<ContextUsageInfo | null>(
|
|
364
|
+
null,
|
|
365
|
+
);
|
|
354
366
|
const [computerUseMode, setComputerUseMode] =
|
|
355
367
|
useState<ComputerUseCliMode>('disabled');
|
|
356
368
|
const promptToolSignatureRef = useRef('');
|
|
357
369
|
const activeComputerRunRef = useRef<ComputerUseRunContext | null>(null);
|
|
358
|
-
const [computerInterventions] = useState(
|
|
370
|
+
const [computerInterventions] = useState(
|
|
371
|
+
() => new HumanInterventionCoordinator(),
|
|
372
|
+
);
|
|
359
373
|
const [pendingComputerIntervention, setPendingComputerIntervention] =
|
|
360
374
|
useState<PendingHumanIntervention | null>(null);
|
|
361
|
-
useEffect(
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
375
|
+
useEffect(
|
|
376
|
+
() =>
|
|
377
|
+
computerInterventions.subscribe((event) => {
|
|
378
|
+
if (event.type === 'started') {
|
|
379
|
+
setPendingComputerIntervention(event.intervention);
|
|
380
|
+
} else {
|
|
381
|
+
setPendingComputerIntervention((current) =>
|
|
382
|
+
current?.id === event.resolution.intervention.id ? null : current,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
}),
|
|
386
|
+
[computerInterventions],
|
|
387
|
+
);
|
|
369
388
|
/**
|
|
370
389
|
* 工具并行执行:以 callId 为 key 保存所有运行中工具。
|
|
371
390
|
* 用 Map 是为了 O(1) 增删;对外 memo 物化成稳定数组(Map 迭代顺序 = 插入顺序,
|
|
@@ -382,8 +401,12 @@ export function useChat(args: {
|
|
|
382
401
|
|
|
383
402
|
const [inputQueue] = useState(() => createInputQueue());
|
|
384
403
|
const [queuedCount, setQueuedCount] = useState(0);
|
|
385
|
-
const [queuedItems, setQueuedItems] = useState<
|
|
386
|
-
|
|
404
|
+
const [queuedItems, setQueuedItems] = useState<
|
|
405
|
+
readonly import('../../messageQueue.js').QueuedInput[]
|
|
406
|
+
>([]);
|
|
407
|
+
const runningToolsRef = useRef<
|
|
408
|
+
Map<string, { toolName: string; isCancelable: boolean }>
|
|
409
|
+
>(new Map());
|
|
387
410
|
|
|
388
411
|
useEffect(() => {
|
|
389
412
|
return inputQueue.subscribe(() => {
|
|
@@ -398,12 +421,14 @@ export function useChat(args: {
|
|
|
398
421
|
// askSlot.ts(纯函数可单测);这里只桥接 React 状态。
|
|
399
422
|
const [pendingAsk, setPendingAsk] = useState<AskQuestionSpec[] | null>(null);
|
|
400
423
|
// 提问来源:子任务提问时 kind:'subagent' + description → AskQuestion 显示徽标。
|
|
401
|
-
const [pendingAskSource, setPendingAskSource] = useState<AskSource | null>(
|
|
424
|
+
const [pendingAskSource, setPendingAskSource] = useState<AskSource | null>(
|
|
425
|
+
null,
|
|
426
|
+
);
|
|
402
427
|
const [pendingAskQueueCount, setPendingAskQueueCount] = useState(0);
|
|
403
428
|
const [askSlot] = useState(() =>
|
|
404
429
|
createAskSlot((questions, source) => {
|
|
405
430
|
setPendingAsk(questions);
|
|
406
|
-
setPendingAskSource(questions ? source ?? null : null);
|
|
431
|
+
setPendingAskSource(questions ? (source ?? null) : null);
|
|
407
432
|
}),
|
|
408
433
|
);
|
|
409
434
|
|
|
@@ -456,7 +481,6 @@ export function useChat(args: {
|
|
|
456
481
|
setRunningToolsMap(new Map());
|
|
457
482
|
// 暂态错误是"过程级"提示,turn 结束 / 切换时一并清掉,不残留到下一轮
|
|
458
483
|
setTransientError(null);
|
|
459
|
-
workflowCtxRef.current = { activeStepId: null, pendingLlmError: null };
|
|
460
484
|
}, []);
|
|
461
485
|
|
|
462
486
|
/** turn 结束 / 中断 / 切换时一并取消所有节流 buffer 的 pending timer。 */
|
|
@@ -492,9 +516,11 @@ export function useChat(args: {
|
|
|
492
516
|
// 归属校验保证已答完提问的 abort 监听器不会清掉后来提问的槽,否则后者 promise
|
|
493
517
|
// 永不落定 → 整轮死挂,见 askSlot.ts 头注)。
|
|
494
518
|
useEffect(() => {
|
|
495
|
-
setAskHandler(
|
|
496
|
-
|
|
497
|
-
|
|
519
|
+
setAskHandler(
|
|
520
|
+
createAskCoordinator(askSlot.handler, (status) => {
|
|
521
|
+
setPendingAskQueueCount(status.queuedCount ?? 0);
|
|
522
|
+
}),
|
|
523
|
+
);
|
|
498
524
|
return () => setAskHandler(null);
|
|
499
525
|
}, [askSlot]);
|
|
500
526
|
|
|
@@ -549,37 +575,46 @@ export function useChat(args: {
|
|
|
549
575
|
const runManualAdvisor = useCallback(
|
|
550
576
|
async (note?: string): Promise<ToolResult> => {
|
|
551
577
|
if (isLoading) {
|
|
552
|
-
return {
|
|
578
|
+
return {
|
|
579
|
+
ok: false,
|
|
580
|
+
error: '当前有任务在执行;等它结束或按 ESC 中断后再咨询顾问。',
|
|
581
|
+
};
|
|
553
582
|
}
|
|
554
583
|
const callId = 'manual-advisor';
|
|
555
584
|
const ac = new AbortController();
|
|
556
585
|
abortRef.current = ac;
|
|
557
586
|
setIsLoading(true);
|
|
558
587
|
setProgressStage('tool_executing');
|
|
559
|
-
setRunningToolsMap(
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
588
|
+
setRunningToolsMap(
|
|
589
|
+
new Map([
|
|
590
|
+
[
|
|
591
|
+
callId,
|
|
592
|
+
{
|
|
593
|
+
toolName: 'Advisor',
|
|
594
|
+
argsPreview: note ?? '',
|
|
595
|
+
status: 'running' as const,
|
|
596
|
+
argsFriendly: '正在咨询顾问模型',
|
|
597
|
+
},
|
|
598
|
+
],
|
|
599
|
+
]),
|
|
600
|
+
);
|
|
565
601
|
try {
|
|
566
|
-
return await runAdvisor(
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
return new Map(prev).set(callId, { ...current, progress: message });
|
|
602
|
+
return await runAdvisor(note ? { note } : {}, ac.signal, {
|
|
603
|
+
history: historyRef.current,
|
|
604
|
+
advisorCalls: { used: 0, max: 1 },
|
|
605
|
+
advisorInvocation: 'manual',
|
|
606
|
+
reportProgress: (message) => {
|
|
607
|
+
// advisor.ts 侧已有 200ms 节流,这里直接落状态即可。
|
|
608
|
+
setRunningToolsMap((prev) => {
|
|
609
|
+
const current = prev.get(callId);
|
|
610
|
+
if (!current) return prev;
|
|
611
|
+
return new Map(prev).set(callId, {
|
|
612
|
+
...current,
|
|
613
|
+
progress: message,
|
|
579
614
|
});
|
|
580
|
-
}
|
|
615
|
+
});
|
|
581
616
|
},
|
|
582
|
-
);
|
|
617
|
+
});
|
|
583
618
|
} finally {
|
|
584
619
|
setIsLoading(false);
|
|
585
620
|
setProgressStage('idle');
|
|
@@ -590,7 +625,10 @@ export function useChat(args: {
|
|
|
590
625
|
// (见下方 consumeQueued)—— 手动咨询不走那条路径,排队的话就会静静躺着,
|
|
591
626
|
// 用户看到「排队 1 条」却永远不执行,直到下次提交才错序跑掉。
|
|
592
627
|
const queued = inputQueue.dequeue();
|
|
593
|
-
if (queued)
|
|
628
|
+
if (queued)
|
|
629
|
+
queueMicrotask(() => {
|
|
630
|
+
void submitRef.current?.(queued.value);
|
|
631
|
+
});
|
|
594
632
|
}
|
|
595
633
|
},
|
|
596
634
|
[isLoading, inputQueue],
|
|
@@ -604,7 +642,8 @@ export function useChat(args: {
|
|
|
604
642
|
if (isLoading) {
|
|
605
643
|
inputQueue.enqueue(trimmed, 'next');
|
|
606
644
|
const running = Array.from(runningToolsRef.current.values());
|
|
607
|
-
const allCancelable =
|
|
645
|
+
const allCancelable =
|
|
646
|
+
running.length > 0 && running.every((t) => t.isCancelable);
|
|
608
647
|
if (allCancelable) {
|
|
609
648
|
abortRef.current?.abort('interrupt');
|
|
610
649
|
}
|
|
@@ -623,8 +662,6 @@ export function useChat(args: {
|
|
|
623
662
|
setProgressStage('idle');
|
|
624
663
|
setReasoningPreview('');
|
|
625
664
|
setRunningToolsMap(new Map());
|
|
626
|
-
// 重置暂态错误状态机(防上一轮工作流残留)
|
|
627
|
-
workflowCtxRef.current = { activeStepId: null, pendingLlmError: null };
|
|
628
665
|
|
|
629
666
|
const ac = new AbortController();
|
|
630
667
|
abortRef.current = ac;
|
|
@@ -641,20 +678,31 @@ export function useChat(args: {
|
|
|
641
678
|
}, 10_000);
|
|
642
679
|
|
|
643
680
|
try {
|
|
644
|
-
await updateSessionMetadata(
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
681
|
+
await updateSessionMetadata(
|
|
682
|
+
getWorkingDir(),
|
|
683
|
+
activeSessionIdRef.current,
|
|
684
|
+
{
|
|
685
|
+
lastMessagePreview: trimmed,
|
|
686
|
+
},
|
|
687
|
+
).catch(() => {});
|
|
688
|
+
const activeFile = sessionFileFor(
|
|
689
|
+
getWorkingDir(),
|
|
690
|
+
activeSessionIdRef.current,
|
|
691
|
+
);
|
|
648
692
|
releaseContextLock = await acquireContextLock(activeFile, ac.signal);
|
|
649
693
|
// Gateway/Cron may have written this cwd since the TUI rendered its last frame.
|
|
650
694
|
// Reload after acquiring the cross-process lock so this turn extends the newest history.
|
|
651
695
|
const latest = await loadContext(activeFile);
|
|
652
696
|
if (latest) {
|
|
653
|
-
const ephemeral = historyRef.current.filter(
|
|
697
|
+
const ephemeral = historyRef.current.filter(
|
|
698
|
+
(message) => message.role === 'system' && message._ephemeral,
|
|
699
|
+
);
|
|
654
700
|
historyRef.current.length = 0;
|
|
655
701
|
historyRef.current.push(...latest, ...ephemeral);
|
|
656
702
|
}
|
|
657
|
-
const workspace = await workspaceIndexService
|
|
703
|
+
const workspace = await workspaceIndexService
|
|
704
|
+
.findByPath(getWorkingDir())
|
|
705
|
+
.catch(() => null);
|
|
658
706
|
const computerRun =
|
|
659
707
|
computerUseMode !== 'disabled'
|
|
660
708
|
? createCliComputerRun({
|
|
@@ -684,17 +732,25 @@ export function useChat(args: {
|
|
|
684
732
|
},
|
|
685
733
|
})
|
|
686
734
|
: undefined;
|
|
687
|
-
const toolGate = computerRun
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
735
|
+
const toolGate = computerRun
|
|
736
|
+
? createComputerUseHostGate(computerRun)
|
|
737
|
+
: undefined;
|
|
738
|
+
const turnSessionState = getOrCreateSessionState(
|
|
739
|
+
sessionStateKey({
|
|
740
|
+
surface: 'tui',
|
|
741
|
+
workspaceId: workspace?.id,
|
|
742
|
+
cwd: workspace?.id ? undefined : getWorkingDir(),
|
|
743
|
+
sessionId: activeSessionIdRef.current,
|
|
744
|
+
}),
|
|
745
|
+
);
|
|
693
746
|
await hydrateSessionWorktree({
|
|
694
|
-
sessionState: turnSessionState,
|
|
695
|
-
|
|
747
|
+
sessionState: turnSessionState,
|
|
748
|
+
workspaceId: workspace?.id,
|
|
749
|
+
sessionId: activeSessionIdRef.current,
|
|
750
|
+
cwd: getWorkingDir(),
|
|
696
751
|
});
|
|
697
|
-
const effectiveCwd =
|
|
752
|
+
const effectiveCwd =
|
|
753
|
+
turnSessionState.activeWorktree?.path ?? getWorkingDir();
|
|
698
754
|
const runtimeContext = createAgentRuntimeContext({
|
|
699
755
|
surface: 'tui',
|
|
700
756
|
profile: 'main',
|
|
@@ -705,18 +761,54 @@ export function useChat(args: {
|
|
|
705
761
|
memoryAccess: 'read-write',
|
|
706
762
|
interactiveAsk: true,
|
|
707
763
|
computer: computerRun,
|
|
764
|
+
computerIntent: classifyComputerAutomationIntent(
|
|
765
|
+
trimmed,
|
|
766
|
+
turnSessionState.computerAutomation,
|
|
767
|
+
),
|
|
708
768
|
computerIntervention,
|
|
709
769
|
toolGate,
|
|
710
770
|
});
|
|
711
|
-
const
|
|
771
|
+
const runtimeTools = filterToolsForRuntime(ALL_TOOLS, runtimeContext);
|
|
772
|
+
const sessionSummary = (
|
|
773
|
+
await listSessionSummaries(getWorkingDir())
|
|
774
|
+
).find((session) => session.id === activeSessionIdRef.current);
|
|
775
|
+
const currentProvider = providerRef.current;
|
|
776
|
+
const effectiveGatewayCategories =
|
|
777
|
+
currentProvider.source === 'gateway'
|
|
778
|
+
? [
|
|
779
|
+
...new Set(
|
|
780
|
+
(
|
|
781
|
+
sessionSummary?.onlineToolCategories ??
|
|
782
|
+
currentProvider.gatewayDefaultToolCategories ??
|
|
783
|
+
currentProvider.gatewayMaxToolCategories ??
|
|
784
|
+
[]
|
|
785
|
+
).filter(
|
|
786
|
+
(category) =>
|
|
787
|
+
currentProvider.gatewayMaxToolCategories?.includes(
|
|
788
|
+
category,
|
|
789
|
+
) ?? true,
|
|
790
|
+
),
|
|
791
|
+
),
|
|
792
|
+
]
|
|
793
|
+
: undefined;
|
|
794
|
+
const turnProvider =
|
|
795
|
+
currentProvider.source === 'gateway'
|
|
796
|
+
? {
|
|
797
|
+
...currentProvider,
|
|
798
|
+
gatewayToolCategories: effectiveGatewayCategories,
|
|
799
|
+
}
|
|
800
|
+
: currentProvider;
|
|
801
|
+
const turnTools =
|
|
802
|
+
currentProvider.source === 'gateway'
|
|
803
|
+
? filterToolsForCategories(runtimeTools, effectiveGatewayCategories)
|
|
804
|
+
: runtimeTools;
|
|
712
805
|
const toolSignature = `${effectiveCwd}\0${turnTools.map((tool) => tool.name).join(',')}`;
|
|
713
806
|
if (promptToolSignatureRef.current !== toolSignature) {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
historyRef.current.push({ role: 'system', content: stablePrompt }, ...rest);
|
|
807
|
+
await refreshStableSystemPrompt(
|
|
808
|
+
historyRef.current,
|
|
809
|
+
effectiveCwd,
|
|
810
|
+
turnTools,
|
|
811
|
+
);
|
|
720
812
|
promptToolSignatureRef.current = toolSignature;
|
|
721
813
|
}
|
|
722
814
|
// 每回合只刷新易变层;稳定层仅在实际能力目录变化时重建。
|
|
@@ -742,11 +834,12 @@ export function useChat(args: {
|
|
|
742
834
|
userInput: trimmed,
|
|
743
835
|
}).catch(() => null);
|
|
744
836
|
for await (const ev of runWithPlugins(trimmed, {
|
|
745
|
-
provider:
|
|
837
|
+
provider: turnProvider,
|
|
746
838
|
history: historyRef.current,
|
|
747
839
|
signal: ac.signal,
|
|
748
840
|
runtimeContext,
|
|
749
841
|
allowedTools: turnTools.map((tool) => tool.name),
|
|
842
|
+
availableTools: turnTools,
|
|
750
843
|
sessionState: turnSessionState,
|
|
751
844
|
parseInlineImages: true,
|
|
752
845
|
...(turnTransient ? { transientBundle: turnTransient } : {}),
|
|
@@ -781,9 +874,6 @@ export function useChat(args: {
|
|
|
781
874
|
setContextUsage,
|
|
782
875
|
// 暂态错误(工作流步内 llm_error / 重试进度)→ LiveArea 黄字
|
|
783
876
|
setTransientError,
|
|
784
|
-
workflowCtx: workflowCtxRef.current,
|
|
785
|
-
// 步骤 id→人话名映射:scrollback 进度行三态(▶/✓/⊘)统一显示 title
|
|
786
|
-
stepTitles: stepTitlesRef.current,
|
|
787
877
|
// 节流相关 —— buffer 累积 + 100ms timer flush
|
|
788
878
|
appendStreamingDelta: streamingFlush.append,
|
|
789
879
|
flushStreamingBuffer: streamingFlush.flush,
|
|
@@ -816,11 +906,16 @@ export function useChat(args: {
|
|
|
816
906
|
activeComputerRunRef.current = null;
|
|
817
907
|
runningToolsRef.current.clear();
|
|
818
908
|
// 记账失败不影响落盘与解锁(它是附加能力,不是功能)。
|
|
819
|
-
await turnJournal
|
|
909
|
+
await turnJournal
|
|
910
|
+
?.finish(historyRef.current, turnJournalStart)
|
|
911
|
+
.catch(() => undefined);
|
|
820
912
|
turnJournal = null;
|
|
821
913
|
// v2 multi-session:持久化到当前 active session 文件。
|
|
822
914
|
try {
|
|
823
|
-
await saveContext(
|
|
915
|
+
await saveContext(
|
|
916
|
+
historyRef.current,
|
|
917
|
+
sessionFileFor(getWorkingDir(), activeSessionIdRef.current),
|
|
918
|
+
);
|
|
824
919
|
} finally {
|
|
825
920
|
await releaseContextLock?.();
|
|
826
921
|
}
|
|
@@ -838,7 +933,6 @@ export function useChat(args: {
|
|
|
838
933
|
[
|
|
839
934
|
bump,
|
|
840
935
|
isLoading,
|
|
841
|
-
sessionFile,
|
|
842
936
|
streamingFlush,
|
|
843
937
|
cancelAllThrottles,
|
|
844
938
|
reasoningFlush,
|
|
@@ -867,9 +961,12 @@ export function useChat(args: {
|
|
|
867
961
|
const stopComputerUse = useCallback(async (): Promise<string> => {
|
|
868
962
|
setComputerUseMode('disabled');
|
|
869
963
|
const context = activeComputerRunRef.current;
|
|
870
|
-
if (!context)
|
|
964
|
+
if (!context)
|
|
965
|
+
return '已撤销后续回合授权;当前没有正在运行的 Computer Use。';
|
|
871
966
|
computerInterventions.abort(context);
|
|
872
|
-
const response = await computerUseService.request(context, {
|
|
967
|
+
const response = await computerUseService.request(context, {
|
|
968
|
+
action: 'stop',
|
|
969
|
+
});
|
|
873
970
|
return response.ok
|
|
874
971
|
? '已停止当前回合的 Computer Use,并撤销后续回合授权。'
|
|
875
972
|
: `已撤销后续回合授权;原生停止失败:${response.error?.message ?? '未知错误'}`;
|
|
@@ -946,7 +1043,10 @@ export function useChat(args: {
|
|
|
946
1043
|
|
|
947
1044
|
// 生成全新的 system prompt(实时扫 skills + 拼项目指令),
|
|
948
1045
|
// 与启动时 main.tsx buildInitialHistory 行为完全一致
|
|
949
|
-
const newSystemPrompt = await buildBaseSystemPrompt(
|
|
1046
|
+
const newSystemPrompt = await buildBaseSystemPrompt(
|
|
1047
|
+
getWorkingDir(),
|
|
1048
|
+
ALL_TOOLS,
|
|
1049
|
+
);
|
|
950
1050
|
historyRef.current.length = 0;
|
|
951
1051
|
historyRef.current.push({ role: 'system', content: newSystemPrompt });
|
|
952
1052
|
promptToolSignatureRef.current = '';
|
|
@@ -966,13 +1066,19 @@ export function useChat(args: {
|
|
|
966
1066
|
// 清空磁盘上的持久化文件(防止下次启动又加载损坏数据)
|
|
967
1067
|
await clearContext();
|
|
968
1068
|
// 清空 pre-read guard 状态表(防止跨 session 的 Read 记录污染新会话)
|
|
969
|
-
const workspace = await workspaceIndexService
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1069
|
+
const workspace = await workspaceIndexService
|
|
1070
|
+
.findByPath(getWorkingDir())
|
|
1071
|
+
.catch(() => null);
|
|
1072
|
+
clearFileState(
|
|
1073
|
+
getOrCreateSessionState(
|
|
1074
|
+
sessionStateKey({
|
|
1075
|
+
surface: 'tui',
|
|
1076
|
+
workspaceId: workspace?.id,
|
|
1077
|
+
cwd: workspace?.id ? undefined : getWorkingDir(),
|
|
1078
|
+
sessionId: activeSessionIdRef.current,
|
|
1079
|
+
}),
|
|
1080
|
+
).fileReads,
|
|
1081
|
+
);
|
|
976
1082
|
// 刚清空,不需要再保存一次"空历史"
|
|
977
1083
|
}, [bump, isLoading, cancelAllThrottles, resetTurnState]);
|
|
978
1084
|
|
|
@@ -993,7 +1099,9 @@ export function useChat(args: {
|
|
|
993
1099
|
let success = false;
|
|
994
1100
|
try {
|
|
995
1101
|
const cwd = getWorkingDir();
|
|
996
|
-
const workspace = await workspaceIndexService
|
|
1102
|
+
const workspace = await workspaceIndexService
|
|
1103
|
+
.findByPath(cwd)
|
|
1104
|
+
.catch(() => null);
|
|
997
1105
|
const r = await forceCompact(
|
|
998
1106
|
historyRef.current,
|
|
999
1107
|
args.provider,
|
|
@@ -1056,7 +1164,10 @@ export function useChat(args: {
|
|
|
1056
1164
|
|
|
1057
1165
|
// 1. 保住当前 session
|
|
1058
1166
|
try {
|
|
1059
|
-
await saveContext(
|
|
1167
|
+
await saveContext(
|
|
1168
|
+
historyRef.current,
|
|
1169
|
+
sessionFileFor(cwd, activeSessionIdRef.current),
|
|
1170
|
+
);
|
|
1060
1171
|
} catch {
|
|
1061
1172
|
// 保存失败不阻塞切换(用户可能就是想切走止损)
|
|
1062
1173
|
}
|
|
@@ -1102,80 +1213,104 @@ export function useChat(args: {
|
|
|
1102
1213
|
[bump, isLoading, cancelAllThrottles, resetTurnState],
|
|
1103
1214
|
);
|
|
1104
1215
|
|
|
1105
|
-
const switchWorkspace = useCallback(
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1216
|
+
const switchWorkspace = useCallback(
|
|
1217
|
+
async (cwd: string, sessionId: string) => {
|
|
1218
|
+
if (isLoading) return false;
|
|
1219
|
+
const targetCwd = cwd.trim();
|
|
1220
|
+
const targetSessionId = sessionId.trim();
|
|
1221
|
+
if (!targetCwd || !targetSessionId) return false;
|
|
1110
1222
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
bump();
|
|
1129
|
-
return false;
|
|
1130
|
-
}
|
|
1223
|
+
let loaded: Message[] | null = null;
|
|
1224
|
+
let targetExists = false;
|
|
1225
|
+
try {
|
|
1226
|
+
const targetFile = await resolveSessionFile(targetCwd, targetSessionId);
|
|
1227
|
+
try {
|
|
1228
|
+
targetExists = (await stat(targetFile)).isFile();
|
|
1229
|
+
} catch {
|
|
1230
|
+
targetExists = false;
|
|
1231
|
+
}
|
|
1232
|
+
loaded = await loadContext(targetFile);
|
|
1233
|
+
if (targetExists && loaded === null)
|
|
1234
|
+
throw new Error('目标会话历史损坏或无法读取');
|
|
1235
|
+
} catch (error) {
|
|
1236
|
+
setError(error instanceof Error ? error.message : String(error));
|
|
1237
|
+
bump();
|
|
1238
|
+
return false;
|
|
1239
|
+
}
|
|
1131
1240
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1241
|
+
let systemPrompt: string;
|
|
1242
|
+
try {
|
|
1243
|
+
systemPrompt = await buildBaseSystemPrompt(targetCwd, ALL_TOOLS);
|
|
1244
|
+
} catch (error) {
|
|
1245
|
+
setError(
|
|
1246
|
+
`无法打开工作区:${error instanceof Error ? error.message : String(error)}`,
|
|
1247
|
+
);
|
|
1248
|
+
bump();
|
|
1249
|
+
return false;
|
|
1250
|
+
}
|
|
1138
1251
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1252
|
+
const previousCwd = getWorkingDir();
|
|
1253
|
+
try {
|
|
1254
|
+
await saveContext(
|
|
1255
|
+
historyRef.current,
|
|
1256
|
+
sessionFileFor(previousCwd, activeSessionIdRef.current),
|
|
1257
|
+
);
|
|
1258
|
+
} catch {
|
|
1259
|
+
// A damaged old workspace must not trap the user in it.
|
|
1260
|
+
}
|
|
1148
1261
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1262
|
+
try {
|
|
1263
|
+
await setActiveSession(targetCwd, targetSessionId);
|
|
1264
|
+
} catch (error) {
|
|
1265
|
+
setError(
|
|
1266
|
+
`无法切换 Session:${error instanceof Error ? error.message : String(error)}`,
|
|
1267
|
+
);
|
|
1268
|
+
bump();
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
setWorkingDir(targetCwd);
|
|
1272
|
+
activeSessionIdRef.current = targetSessionId;
|
|
1273
|
+
setActiveSessionId(targetSessionId);
|
|
1155
1274
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1275
|
+
historyRef.current.length = 0;
|
|
1276
|
+
historyRef.current.push(...(loaded ?? []));
|
|
1277
|
+
upsertStableSystemMessage(historyRef.current, systemPrompt);
|
|
1278
|
+
promptToolSignatureRef.current = '';
|
|
1279
|
+
|
|
1280
|
+
const targetWorkspace = await workspaceIndexService
|
|
1281
|
+
.findByPath(targetCwd)
|
|
1282
|
+
.catch(() => null);
|
|
1283
|
+
clearFileState(
|
|
1284
|
+
getOrCreateSessionState(
|
|
1285
|
+
sessionStateKey({
|
|
1286
|
+
surface: 'tui',
|
|
1287
|
+
workspaceId: targetWorkspace?.id,
|
|
1288
|
+
cwd: targetWorkspace?.id ? undefined : targetCwd,
|
|
1289
|
+
sessionId: targetSessionId,
|
|
1290
|
+
}),
|
|
1291
|
+
).fileReads,
|
|
1292
|
+
);
|
|
1293
|
+
resetReactiveCompactState();
|
|
1294
|
+
cancelAllThrottles();
|
|
1295
|
+
setContextUsage(null);
|
|
1296
|
+
setError(null);
|
|
1297
|
+
setInterrupted(false);
|
|
1298
|
+
resetTurnState();
|
|
1299
|
+
setCompactGeneration((generation) => generation + 1);
|
|
1300
|
+
bump();
|
|
1301
|
+
return true;
|
|
1302
|
+
},
|
|
1303
|
+
[bump, isLoading, cancelAllThrottles, resetTurnState],
|
|
1304
|
+
);
|
|
1173
1305
|
|
|
1174
1306
|
// history 用 useMemo 托管:version 变化时返回 historyRef.current 的浅拷贝。
|
|
1175
1307
|
// 为什么必须 .slice():runQuery 内部 mutate 同一个数组(push 新消息),如果这里
|
|
1176
1308
|
// 返回同一引用,Ink <Static items={history}> 浅比较看不到 prop 变化 → 不 commit
|
|
1177
1309
|
// 新增 message → turn 结束 LiveArea 消失后屏幕空白,看起来像"输出被吃掉"。
|
|
1178
1310
|
// slice 后元素引用不变,只是数组容器是新的,足够让 Static 检测到 length 增长并 commit。
|
|
1311
|
+
// version is an explicit invalidation counter; the callback intentionally
|
|
1312
|
+
// reads the ref-backed history rather than the counter itself.
|
|
1313
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: version intentionally invalidates the ref-backed history snapshot
|
|
1179
1314
|
const history = useMemo(() => historyRef.current.slice(), [version]);
|
|
1180
1315
|
|
|
1181
1316
|
return {
|
|
@@ -1235,7 +1370,9 @@ export interface HandleEventSetters {
|
|
|
1235
1370
|
setProgressStage: (s: ProgressStage) => void;
|
|
1236
1371
|
setReasoningPreview: (updater: (prev: string) => string) => void;
|
|
1237
1372
|
setRunningToolsMap: (
|
|
1238
|
-
updater: (
|
|
1373
|
+
updater: (
|
|
1374
|
+
prev: Map<string, ToolStatusState>,
|
|
1375
|
+
) => Map<string, ToolStatusState>,
|
|
1239
1376
|
) => void;
|
|
1240
1377
|
/**
|
|
1241
1378
|
* 内核 context_usage 事件的落地 setter(可选——不传时该事件被静默忽略,
|
|
@@ -1255,122 +1392,31 @@ export interface HandleEventSetters {
|
|
|
1255
1392
|
cancelToolBump: () => void;
|
|
1256
1393
|
bump: () => void;
|
|
1257
1394
|
/**
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
1395
|
+
* 把一行插件进度作为持久暗色行落进 scrollback(复用 ephemeralLine)。
|
|
1396
|
+
*
|
|
1397
|
+
* 状态行是**覆盖刷新**的,只留得住最后一条;而工作流排障总发生在跑完之后
|
|
1398
|
+
* (「它停在哪一步了?」)。这条通道把每条进度也留在 scrollback 里,
|
|
1399
|
+
* 失败后仍看得见。走 ephemeral 行:只进展示,不进 history、不被持久化。
|
|
1400
|
+
* 可选:不传即关闭该行为(测试 / -p 不需要)。
|
|
1261
1401
|
*/
|
|
1262
1402
|
emitProgressLine?: (text: string) => void;
|
|
1263
1403
|
/**
|
|
1264
1404
|
* 暂态错误 setter(喂 LiveArea 黄字,可被覆盖刷新)。
|
|
1265
|
-
*
|
|
1266
|
-
* 非工作流路径行为完全不变(既有单测不传也不受影响)。
|
|
1405
|
+
* 当前用于压缩失败提示与插件重试进度;可选,不传即关闭。
|
|
1267
1406
|
*/
|
|
1268
1407
|
setTransientError?: (e: string | null) => void;
|
|
1269
|
-
/**
|
|
1270
|
-
* 暂态错误状态机的跨事件可变上下文(由 useChat 持 ref 注入)。
|
|
1271
|
-
* - activeStepId:当前正在执行的 workflow step id(null = 不在任何 step 内)
|
|
1272
|
-
* - pendingLlmError:该 step 内捕获的最近一次 llm_error 文案(暂存待裁决)
|
|
1273
|
-
* handleEvent 同步读写它;可选——不传时降级(同 setTransientError 缺省)。
|
|
1274
|
-
*/
|
|
1275
|
-
workflowCtx?: { activeStepId: string | null; pendingLlmError: string | null };
|
|
1276
|
-
/**
|
|
1277
|
-
* 工作流步骤 id → 已插值人话进度名(title)的映射(由 useChat 持 ref 注入)。
|
|
1278
|
-
* workflow_step_start 带 title 时记入,step_end / step_skipped 据 id 回查,
|
|
1279
|
-
* 让 scrollback 的 ▶/✓/✗/⊘ 三种进度行都显示同一个人话名而非 id + 块内序号。
|
|
1280
|
-
* 可选——不传时退化为「end/skipped 显示 id」(既有单测不传也不受影响)。
|
|
1281
|
-
*/
|
|
1282
|
-
stepTitles?: Map<string, string>;
|
|
1283
1408
|
}
|
|
1284
1409
|
|
|
1285
1410
|
export function handleEvent(
|
|
1286
1411
|
ev: LoopEvent | PluginEvent,
|
|
1287
1412
|
setters: HandleEventSetters,
|
|
1288
1413
|
): void {
|
|
1289
|
-
//
|
|
1290
|
-
//
|
|
1291
|
-
//
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
kind?: string;
|
|
1296
|
-
index?: number;
|
|
1297
|
-
total?: number;
|
|
1298
|
-
ok?: boolean;
|
|
1299
|
-
error?: string;
|
|
1300
|
-
reason?: string;
|
|
1301
|
-
name?: string;
|
|
1302
|
-
totalSteps?: number;
|
|
1303
|
-
title?: string;
|
|
1304
|
-
};
|
|
1305
|
-
// 据 id 回查人话进度名:声明了 title 的步走 title,否则回落 id(end/skipped 用)。
|
|
1306
|
-
const titleOrId = (id: string | undefined): string =>
|
|
1307
|
-
(id && setters.stepTitles?.get(id)) || id || '?';
|
|
1308
|
-
switch (wf.type) {
|
|
1309
|
-
case 'workflow_start':
|
|
1310
|
-
setters.emitProgressLine?.(`${figures.step} 工作流 ${wf.name} 开始(共 ${wf.totalSteps} 步)`);
|
|
1311
|
-
// 新工作流开始:清空上一条工作流残留的 title 映射,避免同名步串味。
|
|
1312
|
-
setters.stepTitles?.clear();
|
|
1313
|
-
// 工作流开始:立即刷新 token(可能已积累大量前置对话上下文)
|
|
1314
|
-
setters.bump();
|
|
1315
|
-
return;
|
|
1316
|
-
case 'workflow_step_start':
|
|
1317
|
-
// 声明了 title 的步显示人话名(与状态行一致、不显示块内相对序号——嵌套块
|
|
1318
|
-
// 的 i/total 拼在一起会被误读成"跳步");未声明 title 的步保持 legacy 格式。
|
|
1319
|
-
// ⎿ 前缀:step 行挂在「▶ 工作流 x 开始」下的层次连接符(figures.elbow 语汇,
|
|
1320
|
-
// 与工具结果/蜂群树统一)。ephemeral 是尾部追加消息,不触任何既有前缀字节。
|
|
1321
|
-
if (wf.title) {
|
|
1322
|
-
if (wf.id) setters.stepTitles?.set(wf.id, wf.title);
|
|
1323
|
-
setters.emitProgressLine?.(` ${figures.elbow} ${figures.step} ${wf.title}`);
|
|
1324
|
-
} else {
|
|
1325
|
-
setters.emitProgressLine?.(
|
|
1326
|
-
` ${figures.elbow} ${figures.step} ${(wf.index ?? 0) + 1}/${wf.total ?? '?'} ${wf.id} (${wf.kind})`,
|
|
1327
|
-
);
|
|
1328
|
-
}
|
|
1329
|
-
// 暂态错误状态机:记下当前正在执行的 step id,进入"该步内的 llm_error 暂态化"窗口。
|
|
1330
|
-
// 进新步先清掉上一步可能残留的暂态错误(上一步已 end、不应跨步显示)。
|
|
1331
|
-
if (setters.workflowCtx) {
|
|
1332
|
-
setters.workflowCtx.activeStepId = wf.id ?? null;
|
|
1333
|
-
setters.workflowCtx.pendingLlmError = null;
|
|
1334
|
-
}
|
|
1335
|
-
setters.setTransientError?.(null);
|
|
1336
|
-
return;
|
|
1337
|
-
case 'workflow_step_end':
|
|
1338
|
-
setters.emitProgressLine?.(
|
|
1339
|
-
` ${figures.elbow} ${wf.ok ? figures.ok : figures.fail} ${titleOrId(wf.id)}${wf.error ? `:${wf.error}` : ''}`,
|
|
1340
|
-
);
|
|
1341
|
-
// 暂态错误裁决(仅当 end 的是当前活跃步):
|
|
1342
|
-
// ok:true → 重试/恢复成功 → 丢弃 pending llm_error,短暂显示"已恢复"后随刷新消失。
|
|
1343
|
-
// ok:false → 该步彻底失败 → 把暂态错误提升为永久红字(chat.error,进 scrollback 上方)。
|
|
1344
|
-
if (setters.workflowCtx && setters.workflowCtx.activeStepId === wf.id) {
|
|
1345
|
-
const pending = setters.workflowCtx.pendingLlmError;
|
|
1346
|
-
if (wf.ok) {
|
|
1347
|
-
if (pending) {
|
|
1348
|
-
// 成功收回:留一条灰底"已恢复"提示,下一次状态行刷新自然覆盖消失
|
|
1349
|
-
setters.setTransientError?.(`${figures.ok} ${wf.id} 已恢复(此前 LLM 调用失败已重试成功)`);
|
|
1350
|
-
} else {
|
|
1351
|
-
setters.setTransientError?.(null);
|
|
1352
|
-
}
|
|
1353
|
-
} else {
|
|
1354
|
-
// 彻底失败:暂态升永久红字。优先用 step.error,回落到 pending llm_error。
|
|
1355
|
-
const finalMsg = wf.error ?? pending;
|
|
1356
|
-
if (finalMsg) setters.setError(finalMsg);
|
|
1357
|
-
setters.setTransientError?.(null);
|
|
1358
|
-
}
|
|
1359
|
-
setters.workflowCtx.activeStepId = null;
|
|
1360
|
-
setters.workflowCtx.pendingLlmError = null;
|
|
1361
|
-
}
|
|
1362
|
-
// 步骤完成:强制刷新 token(agent/llm 步骤可能写入大量上下文)
|
|
1363
|
-
setters.bump();
|
|
1364
|
-
return;
|
|
1365
|
-
case 'workflow_step_skipped':
|
|
1366
|
-
setters.emitProgressLine?.(` ${figures.elbow} ${figures.skip} ${titleOrId(wf.id)}:${wf.reason ?? ''}`);
|
|
1367
|
-
return;
|
|
1368
|
-
case 'workflow_done':
|
|
1369
|
-
setters.emitProgressLine?.(`${figures.ok} 工作流 ${wf.name} 完成`);
|
|
1370
|
-
// 工作流结束:最终刷新(反映完整执行后的上下文量)
|
|
1371
|
-
setters.bump();
|
|
1372
|
-
return;
|
|
1373
|
-
}
|
|
1414
|
+
// ⚠️ 这里曾有一整块 `workflow_start` / `workflow_step_start` / `workflow_step_end` /
|
|
1415
|
+
// `workflow_step_skipped` / `workflow_done` 的渲染逻辑(外加一个 activeStepId
|
|
1416
|
+
// 状态机)。那是 yaml DSL 引擎的事件,随引擎一起删除后**一个发送方都不剩**,
|
|
1417
|
+
// 只有测试自己合成它们 —— 纯死代码。
|
|
1418
|
+
//
|
|
1419
|
+
// V2 工作流发结构化 `workflow_progress`;旧插件仍可发 `plugin_progress`。
|
|
1374
1420
|
|
|
1375
1421
|
// 收口到 LoopEvent:未识别的 PluginEvent type 走 default no-op
|
|
1376
1422
|
const e = ev as LoopEvent;
|
|
@@ -1399,6 +1445,13 @@ export function handleEvent(
|
|
|
1399
1445
|
setters.setRunningToolsMap(() => new Map());
|
|
1400
1446
|
setters.bump();
|
|
1401
1447
|
break;
|
|
1448
|
+
case 'assistant_draft_discarded':
|
|
1449
|
+
setters.flushStreamingBuffer();
|
|
1450
|
+
setters.setStreamingText(() => '');
|
|
1451
|
+
setters.cancelReasoningFlush();
|
|
1452
|
+
setters.setReasoningPreview(() => '');
|
|
1453
|
+
setters.setProgressStage('thinking');
|
|
1454
|
+
break;
|
|
1402
1455
|
case 'tool_start':
|
|
1403
1456
|
// 把工具加入运行集合;并行多个工具时这里会累积。
|
|
1404
1457
|
// v2: argsFriendly 是 loop.ts 通过 LoopEvent 扩展字段传过来的人话描述
|
|
@@ -1423,7 +1476,11 @@ export function handleEvent(
|
|
|
1423
1476
|
const current = prev.get(e.toolCallId);
|
|
1424
1477
|
if (!current) return prev;
|
|
1425
1478
|
const next = new Map(prev);
|
|
1426
|
-
next.set(e.toolCallId, {
|
|
1479
|
+
next.set(e.toolCallId, {
|
|
1480
|
+
...current,
|
|
1481
|
+
progress: e.message,
|
|
1482
|
+
progressDetail: e.detail,
|
|
1483
|
+
});
|
|
1427
1484
|
return next;
|
|
1428
1485
|
});
|
|
1429
1486
|
setters.scheduleToolBump();
|
|
@@ -1482,33 +1539,12 @@ export function handleEvent(
|
|
|
1482
1539
|
setters.bump();
|
|
1483
1540
|
break;
|
|
1484
1541
|
}
|
|
1485
|
-
//
|
|
1486
|
-
//
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
setters.setTransientError
|
|
1492
|
-
) {
|
|
1493
|
-
setters.setTransientError('↻ 当前步骤达到轮数预算,正在续跑…');
|
|
1494
|
-
setters.bump();
|
|
1495
|
-
break;
|
|
1496
|
-
}
|
|
1497
|
-
// 工作流步执行中的 llm_error:暂态而非永久红字 ——
|
|
1498
|
-
// 该步通常会被重试,这里只暂存 + 喂 LiveArea 黄字,等 step_end 裁决去留。
|
|
1499
|
-
// 非工作流场景(无活跃 step,或缺 setTransientError 降级)走原有永久红字路径。
|
|
1500
|
-
if (
|
|
1501
|
-
code === 'llm_error' &&
|
|
1502
|
-
setters.workflowCtx &&
|
|
1503
|
-
setters.workflowCtx.activeStepId !== null &&
|
|
1504
|
-
setters.setTransientError
|
|
1505
|
-
) {
|
|
1506
|
-
setters.workflowCtx.pendingLlmError = e.error;
|
|
1507
|
-
setters.setTransientError(`⚠ LLM 调用失败(重试中):${e.error}`);
|
|
1508
|
-
setters.bump();
|
|
1509
|
-
break;
|
|
1510
|
-
}
|
|
1511
|
-
// 其余:顶层 halt(无 code)、非工作流 llm_error、aborted 等 → 永久红字。
|
|
1542
|
+
// 注:这里曾有两条「工作流步内的 max_turns / llm_error 降级成暂态黄字」分支,
|
|
1543
|
+
// 都以 `workflowCtx.activeStepId !== null` 为前提。那个 id 由 yaml DSL 的
|
|
1544
|
+
// workflow_step_start 事件写入,事件删除后恒为 null,两条分支永远走不到。
|
|
1545
|
+
// 代码编排引擎把这两种错误在 `api.ts` 内部就地消化(`continue`,不外泄给顶层),
|
|
1546
|
+
// 顶层根本收不到 —— 所以不是「少了个降级」,而是这层判断已无对象。
|
|
1547
|
+
// 其余:顶层 halt(无 code)、llm_error、aborted 等 → 永久红字。
|
|
1512
1548
|
setters.setError(e.error);
|
|
1513
1549
|
setters.bump();
|
|
1514
1550
|
break;
|
|
@@ -1535,6 +1571,14 @@ export function handleEvent(
|
|
|
1535
1571
|
max: e.max,
|
|
1536
1572
|
message: e.message,
|
|
1537
1573
|
});
|
|
1574
|
+
// 同时落一行进 scrollback。状态行是**覆盖刷新**的:一条二十步的工作流跑完,
|
|
1575
|
+
// 状态行只剩最后一步,前面十九步去哪了、在哪一步失败的全查不到 —— 而排障
|
|
1576
|
+
// 恰恰总发生在跑完之后。legacy 靠 workflow_step_* 事件做这件事,那套事件随
|
|
1577
|
+
// yaml 引擎删了,这里由 plugin_progress 承担同一职责。
|
|
1578
|
+
// 走 ephemeral 行:只进展示,不进 history、不被 saveContext 持久化。
|
|
1579
|
+
if (typeof e.message === 'string' && e.message.length > 0) {
|
|
1580
|
+
setters.emitProgressLine?.(e.message);
|
|
1581
|
+
}
|
|
1538
1582
|
// 重试进度也镜像到暂态行(覆盖刷新):runner 在重试时发 "↻ 重试 x N/M…"。
|
|
1539
1583
|
// 与 warning 分支互为补充(plugin_progress 文案更短,适合状态行下方一行)。
|
|
1540
1584
|
if (
|
|
@@ -1546,6 +1590,24 @@ export function handleEvent(
|
|
|
1546
1590
|
}
|
|
1547
1591
|
setters.bump();
|
|
1548
1592
|
break;
|
|
1593
|
+
case 'workflow_progress': {
|
|
1594
|
+
const indent = ' '.repeat(e.depth ?? 0);
|
|
1595
|
+
const count =
|
|
1596
|
+
e.current !== undefined && e.total !== undefined
|
|
1597
|
+
? `${e.current}/${e.total} `
|
|
1598
|
+
: '';
|
|
1599
|
+
const message = `${indent}${count}${e.message ?? e.phase}`;
|
|
1600
|
+
setters.setPluginProgress({
|
|
1601
|
+
pluginId: e.workflow,
|
|
1602
|
+
current: e.current,
|
|
1603
|
+
max: e.total,
|
|
1604
|
+
message,
|
|
1605
|
+
});
|
|
1606
|
+
setters.emitProgressLine?.(message);
|
|
1607
|
+
if (e.status === 'warning') setters.setTransientError?.(message);
|
|
1608
|
+
setters.bump();
|
|
1609
|
+
break;
|
|
1610
|
+
}
|
|
1549
1611
|
case 'reasoning':
|
|
1550
1612
|
// reasoning delta 频率跟 text delta 一样高(60+/秒),不节流的话每个 delta 立即
|
|
1551
1613
|
// setReasoningPreview → LiveArea rerender → Ink 重绘扛不住。
|