minimal-agent 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/package.json +52 -5
- package/plugins/computer_use/.claude-plugin/plugin.json +6 -0
- package/plugins/computer_use/README.md +94 -0
- package/plugins/computer_use/app/_template.md +142 -0
- package/plugins/computer_use/app/chrome.md +165 -0
- package/plugins/computer_use/app/finder.md +76 -0
- package/plugins/computer_use/app/macos-system-settings.md +81 -0
- package/plugins/computer_use/app/microsoft-excel.md +80 -0
- package/plugins/computer_use/app/microsoft-powerpoint.md +80 -0
- package/plugins/computer_use/app/microsoft-word.md +79 -0
- package/plugins/computer_use/app/wechat.md +413 -0
- package/plugins/computer_use/app/weread.md +319 -0
- package/plugins/computer_use/commands/computeruse.md +25 -0
- package/plugins/computer_use/commands/cu.md +9 -0
- package/plugins/computer_use/plugin.js +26 -0
- package/plugins/computer_use/plugin.ts +30 -0
- package/plugins/computer_use/src/capture.js +90 -0
- package/plugins/computer_use/src/capture.ts +104 -0
- package/plugins/computer_use/src/commands.js +91 -0
- package/plugins/computer_use/src/commands.ts +103 -0
- package/plugins/computer_use/src/daemon.js +134 -0
- package/plugins/computer_use/src/daemon.ts +161 -0
- package/plugins/computer_use/src/manuals.js +135 -0
- package/plugins/computer_use/src/manuals.ts +159 -0
- package/plugins/computer_use/src/verify.js +168 -0
- package/plugins/computer_use/src/verify.ts +219 -0
- package/plugins/computer_use/test/commands.test.ts +73 -0
- package/plugins/cron-runner/plugin.ts +38 -0
- package/plugins/cron-runner/src/commands.ts +373 -0
- package/plugins/cron-runner/src/cronTime.ts +155 -0
- package/plugins/cron-runner/src/lock.ts +79 -0
- package/plugins/cron-runner/src/runs.ts +99 -0
- package/plugins/cron-runner/src/scheduleEngine.ts +76 -0
- package/plugins/cron-runner/src/scheduler.ts +376 -0
- package/plugins/cron-runner/src/schema.ts +139 -0
- package/plugins/cron-runner/src/service.ts +193 -0
- package/plugins/cron-runner/src/store.ts +333 -0
- package/plugins/cron-runner/src/types.ts +141 -0
- package/plugins/cron-runner/test/cronTime.test.ts +41 -0
- package/plugins/cron-runner/test/plugin-integration.test.ts +47 -0
- package/plugins/cron-runner/test/scheduleEngine.test.ts +41 -0
- package/plugins/cron-runner/test/service.test.ts +76 -0
- package/plugins/cron-runner/test/store-and-scheduler.test.ts +501 -0
- package/plugins/workflow-runner/plugin.js +56 -2
- package/plugins/workflow-runner/plugin.ts +113 -0
- package/plugins/workflow-runner/src/agentCommon.js +43 -4
- package/plugins/workflow-runner/src/agentCommon.ts +435 -0
- package/plugins/workflow-runner/src/controlFlow/branch.js +40 -0
- package/plugins/workflow-runner/src/controlFlow/branch.ts +46 -0
- package/plugins/workflow-runner/src/controlFlow/loop.js +211 -0
- package/plugins/workflow-runner/src/controlFlow/loop.ts +248 -0
- package/plugins/workflow-runner/src/controlFlow/pause.js +129 -0
- package/plugins/workflow-runner/src/controlFlow/pause.ts +141 -0
- package/plugins/workflow-runner/src/controlFlow/signal.js +21 -0
- package/plugins/workflow-runner/src/controlFlow/signal.ts +29 -0
- package/plugins/workflow-runner/src/controlFlow/types.js +18 -0
- package/plugins/workflow-runner/src/controlFlow/types.ts +63 -0
- package/plugins/workflow-runner/src/dslManifest.ts +127 -0
- package/plugins/workflow-runner/src/expressions.ts +622 -0
- package/plugins/workflow-runner/src/index.js +13 -4
- package/plugins/workflow-runner/src/index.ts +338 -0
- package/plugins/workflow-runner/src/jsonPayload.ts +84 -0
- package/plugins/workflow-runner/src/loader.js +23 -0
- package/plugins/workflow-runner/src/loader.ts +721 -0
- package/plugins/workflow-runner/src/multimodal.js +2 -1
- package/plugins/workflow-runner/src/multimodal.ts +64 -0
- package/plugins/workflow-runner/src/recovery.ts +149 -0
- package/plugins/workflow-runner/src/runner.js +75 -659
- package/plugins/workflow-runner/src/runner.ts +604 -0
- package/plugins/workflow-runner/src/stepExecutors/agent.ts +234 -0
- package/plugins/workflow-runner/src/stepExecutors/assert.ts +50 -0
- package/plugins/workflow-runner/src/stepExecutors/echo.js +31 -0
- package/plugins/workflow-runner/src/stepExecutors/echo.ts +38 -0
- package/plugins/workflow-runner/src/stepExecutors/llm.ts +133 -0
- package/plugins/workflow-runner/src/stepExecutors/set.js +49 -0
- package/plugins/workflow-runner/src/stepExecutors/set.ts +56 -0
- package/plugins/workflow-runner/src/stepExecutors/skill.js +5 -6
- package/plugins/workflow-runner/src/stepExecutors/skill.ts +140 -0
- package/plugins/workflow-runner/src/stepExecutors/tool.js +80 -8
- package/plugins/workflow-runner/src/stepExecutors/tool.ts +256 -0
- package/plugins/workflow-runner/src/stepExecutors/verify.ts +68 -0
- package/plugins/workflow-runner/src/stepPipeline.js +277 -0
- package/plugins/workflow-runner/src/stepPipeline.ts +366 -0
- package/plugins/workflow-runner/src/taskIdentity.ts +405 -0
- package/plugins/workflow-runner/src/toolRuntime.js +48 -0
- package/plugins/workflow-runner/src/toolRuntime.ts +64 -0
- package/plugins/workflow-runner/src/types.js +37 -1
- package/plugins/workflow-runner/src/types.ts +602 -0
- package/plugins/workflow-runner/src/workflowState.ts +733 -0
- package/plugins/workflow-runner/test/agent.test.ts +587 -0
- package/plugins/workflow-runner/test/agentLlmError.test.ts +373 -0
- package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +65 -0
- package/plugins/workflow-runner/test/captureMisbind.test.ts +99 -0
- package/plugins/workflow-runner/test/cli.e2e.test.ts +147 -0
- package/plugins/workflow-runner/test/context-files.test.ts +320 -0
- package/plugins/workflow-runner/test/e2e.test.ts +370 -0
- package/plugins/workflow-runner/test/engineRobustness.test.ts +226 -0
- package/plugins/workflow-runner/test/expressions.test.ts +397 -0
- package/plugins/workflow-runner/test/foundation.test.ts +126 -0
- package/plugins/workflow-runner/test/graceful.test.ts +139 -0
- package/plugins/workflow-runner/test/greedyInputs.load.test.ts +47 -0
- package/plugins/workflow-runner/test/hostCapability.test.ts +108 -0
- package/plugins/workflow-runner/test/illustrate.load.test.ts +183 -0
- package/plugins/workflow-runner/test/jsonPayload.test.ts +83 -0
- package/plugins/workflow-runner/test/loader.test.ts +617 -0
- package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +33 -0
- package/plugins/workflow-runner/test/multimodal.test.ts +342 -0
- package/plugins/workflow-runner/test/output-schema.test.ts +213 -0
- package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +87 -0
- package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +269 -0
- package/plugins/workflow-runner/test/ppt.load.test.ts +1220 -0
- package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +220 -0
- package/plugins/workflow-runner/test/recovery.test.ts +265 -0
- package/plugins/workflow-runner/test/runner.test.ts +911 -0
- package/plugins/workflow-runner/test/runnerPreflight.test.ts +379 -0
- package/plugins/workflow-runner/test/skillTurnDone.test.ts +71 -0
- package/plugins/workflow-runner/test/stateLifecycle.test.ts +150 -0
- package/plugins/workflow-runner/test/stepPipeline.test.ts +114 -0
- package/plugins/workflow-runner/test/taskArbitration.test.ts +338 -0
- package/plugins/workflow-runner/test/taskIdentity.test.ts +237 -0
- package/plugins/workflow-runner/test/taskLifecycle.test.ts +270 -0
- package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +221 -0
- package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +29 -0
- package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +168 -0
- package/plugins/workflow-runner/test/webppt.load.test.ts +250 -0
- package/plugins/workflow-runner/test/word.load.test.ts +208 -0
- package/plugins/workflow-runner/test/workflows.smoke.test.ts +76 -0
- package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +207 -0
- package/skills/browser-automation/SKILL.md +9 -19
- package/skills/web-crawler/SKILL.md +9 -11
- package/src/askBridge.ts +249 -0
- package/src/bootstrap/cwdArg.js +10 -3
- package/src/bootstrap/cwdArg.ts +31 -0
- package/src/bootstrap/workingDir.ts +48 -0
- package/src/cli/args.js +70 -7
- package/src/cli/args.ts +146 -0
- package/src/cli/computerUse.js +185 -0
- package/src/cli/computerUse.ts +221 -0
- package/src/cli/configMenu.js +274 -202
- package/src/cli/configMenu.tsx +521 -0
- package/src/cli/memoryAccess.js +45 -0
- package/src/cli/memoryAccess.ts +53 -0
- package/src/cli/print.js +119 -5
- package/src/cli/print.ts +597 -0
- package/src/cli/quickModelSetup.js +60 -0
- package/src/cli/quickModelSetup.tsx +96 -0
- package/src/cli/streamJson.js +80 -4
- package/src/cli/streamJson.ts +433 -0
- package/src/cli/wizards/advisorWizard.js +1 -0
- package/src/cli/wizards/advisorWizard.tsx +195 -0
- package/src/cli/wizards/agentRuntimeWizard.js +84 -0
- package/src/cli/wizards/agentRuntimeWizard.tsx +134 -0
- package/src/cli/wizards/browserWizard.js +55 -0
- package/src/cli/wizards/browserWizard.tsx +77 -0
- package/src/cli/wizards/contextAdvisorWizard.js +84 -0
- package/src/cli/wizards/contextAdvisorWizard.tsx +124 -0
- package/src/cli/wizards/fieldForm.js +7 -4
- package/src/cli/wizards/fieldForm.tsx +250 -0
- package/src/cli/wizards/imageWizard.js +4 -5
- package/src/cli/wizards/imageWizard.tsx +96 -0
- package/src/cli/wizards/openRouterWizard.tsx +48 -0
- package/src/cli/wizards/providerPresets.js +1 -8
- package/src/cli/wizards/providerPresets.ts +106 -0
- package/src/cli/wizards/providerWizard.js +152 -205
- package/src/cli/wizards/providerWizard.tsx +266 -0
- package/src/cli/wizards/searchWizard.tsx +47 -0
- package/src/cli/wizards/ttsWizard.js +4 -3
- package/src/cli/wizards/ttsWizard.tsx +61 -0
- package/src/config/configDefaults.js +25 -0
- package/src/config/configDefaults.ts +33 -0
- package/src/config/configDiagnostics.js +117 -0
- package/src/config/configDiagnostics.ts +166 -0
- package/src/config/configFile.js +52 -32
- package/src/config/configFile.ts +633 -0
- package/src/config/configManagement.js +126 -0
- package/src/config/configManagement.ts +159 -0
- package/src/config/configService.js +66 -11
- package/src/config/configService.ts +554 -0
- package/src/config/numericLimits.js +61 -0
- package/src/config/numericLimits.ts +80 -0
- package/src/config.ts +109 -0
- package/src/context/agentHome.ts +11 -0
- package/src/context/archive.ts +144 -0
- package/src/context/budgetPlan.js +54 -0
- package/src/context/budgetPlan.ts +88 -0
- package/src/context/compact.js +179 -106
- package/src/context/compact.ts +584 -0
- package/src/context/contextBundle.js +119 -0
- package/src/context/contextBundle.ts +176 -0
- package/src/context/contextLock.ts +84 -0
- package/src/context/microCompactLite.ts +218 -0
- package/src/context/persistContext.ts +177 -0
- package/src/context/reactiveCompact.js +19 -4
- package/src/context/reactiveCompact.ts +240 -0
- package/src/context/recentDirs.ts +42 -0
- package/src/context/sessionPath.ts +206 -0
- package/src/context/sessionRegistry.js +8 -2
- package/src/context/sessionRegistry.ts +414 -0
- package/src/context/snipCompact.ts +163 -0
- package/src/context/tokenCounter.ts +106 -0
- package/src/context/workspaceIndex.js +2 -2
- package/src/context/workspaceIndex.ts +751 -0
- package/src/entry.compiled.tsx +20 -0
- package/src/harness/claimValidation.js +9 -0
- package/src/harness/claimValidation.ts +22 -0
- package/src/harness/evidenceLedger.js +92 -0
- package/src/harness/evidenceLedger.ts +96 -0
- package/src/harness/stallGuard.js +60 -0
- package/src/harness/stallGuard.ts +81 -0
- package/src/humanIntervention.js +129 -0
- package/src/humanIntervention.ts +216 -0
- package/src/infra/verification.ts +295 -0
- package/src/irreversible/rules.js +216 -0
- package/src/irreversible/rules.ts +261 -0
- package/src/llm/client.js +40 -3
- package/src/llm/client.ts +621 -0
- package/src/llm/promptCache.js +27 -0
- package/src/llm/promptCache.ts +41 -0
- package/src/llm/providers/anthropicFormat.js +41 -5
- package/src/llm/providers/anthropicFormat.ts +290 -0
- package/src/llm/providers/openaiFormat.js +186 -8
- package/src/llm/providers/openaiFormat.ts +428 -0
- package/src/loop.js +614 -63
- package/src/loop.ts +1454 -0
- package/src/main.js +67 -10
- package/src/main.tsx +344 -0
- package/src/memory/codec.js +204 -0
- package/src/memory/codec.ts +249 -0
- package/src/memory/constants.js +34 -0
- package/src/memory/constants.ts +50 -0
- package/src/memory/episodicMemory.js +684 -0
- package/src/memory/episodicMemory.ts +815 -0
- package/src/memory/fileStore.js +148 -0
- package/src/memory/fileStore.ts +184 -0
- package/src/memory/memoryService.js +570 -0
- package/src/memory/memoryService.ts +859 -0
- package/src/memory/migration.js +128 -0
- package/src/memory/migration.ts +160 -0
- package/src/memory/repository.js +789 -0
- package/src/memory/repository.ts +893 -0
- package/src/memory/retrieval.js +108 -0
- package/src/memory/retrieval.ts +145 -0
- package/src/memory/searchIndex.js +107 -0
- package/src/memory/searchIndex.ts +153 -0
- package/src/memory/topicView.js +82 -0
- package/src/memory/topicView.ts +95 -0
- package/src/memory/turnJournal.js +95 -0
- package/src/memory/turnJournal.ts +120 -0
- package/src/memory/types.js +2 -0
- package/src/memory/types.ts +186 -0
- package/src/messageQueue.ts +123 -0
- package/src/multimodal.js +128 -46
- package/src/multimodal.ts +349 -0
- package/src/plugin-sdk.js +21 -1
- package/src/plugin-sdk.ts +134 -0
- package/src/plugins/builtinPluginIds.js +47 -0
- package/src/plugins/builtinPluginIds.ts +51 -0
- package/src/plugins/builtinRegistry.ts +43 -0
- package/src/plugins/commandRouter.js +40 -26
- package/src/plugins/commandRouter.ts +261 -0
- package/src/plugins/hookEngine.ts +341 -0
- package/src/plugins/pluginApi.ts +133 -0
- package/src/plugins/pluginLifecycle.ts +34 -0
- package/src/plugins/pluginLoader.ts +147 -0
- package/src/plugins/pluginManifest.js +127 -0
- package/src/plugins/pluginManifest.ts +152 -0
- package/src/plugins/pluginRunner.js +47 -2
- package/src/plugins/pluginRunner.ts +207 -0
- package/src/plugins/transcript.ts +208 -0
- package/src/prompts/lint.js +169 -0
- package/src/prompts/lint.ts +220 -0
- package/src/prompts/pluginList.js +32 -16
- package/src/prompts/pluginList.ts +86 -0
- package/src/prompts/policyRegistry.js +318 -0
- package/src/prompts/policyRegistry.ts +358 -0
- package/src/prompts/projectInstructions.js +24 -0
- package/src/prompts/projectInstructions.ts +81 -0
- package/src/prompts/promptAssembly.js +311 -202
- package/src/prompts/promptAssembly.ts +510 -0
- package/src/prompts/skillList.js +106 -45
- package/src/prompts/skillList.ts +198 -0
- package/src/prompts/system.js +31 -6
- package/src/prompts/system.ts +81 -0
- package/src/runtime/agentRuntimeContext.js +53 -0
- package/src/runtime/agentRuntimeContext.ts +112 -0
- package/src/session/runAgentTurn.js +71 -12
- package/src/session/runAgentTurn.ts +181 -0
- package/src/session/runTurn.js +29 -0
- package/src/session/runTurn.ts +160 -0
- package/src/session/runtimeStore.js +149 -0
- package/src/session/runtimeStore.ts +197 -0
- package/src/session/sessionState.js +79 -3
- package/src/session/sessionState.ts +134 -0
- package/src/toolGate.ts +50 -0
- package/src/tools/advisor/advisor.js +76 -15
- package/src/tools/advisor/advisor.ts +512 -0
- package/src/tools/agent/agent.js +245 -29
- package/src/tools/agent/agent.ts +837 -0
- package/src/tools/agent/agentTaskService.js +60 -0
- package/src/tools/agent/agentTaskService.ts +113 -0
- package/src/tools/agent/agentTypes.js +20 -8
- package/src/tools/agent/agentTypes.ts +94 -0
- package/src/tools/agent/coordinator.ts +111 -0
- package/src/tools/agent/worktree.ts +296 -0
- package/src/tools/ask/ask.js +17 -0
- package/src/tools/ask/ask.ts +122 -0
- package/src/tools/bash/attachImage.js +223 -0
- package/src/tools/bash/attachImage.ts +281 -0
- package/src/tools/bash/bash.js +132 -14
- package/src/tools/bash/bash.ts +642 -0
- package/src/tools/bash/semantics.ts +103 -0
- package/src/tools/bash/warnings.js +17 -11
- package/src/tools/bash/warnings.ts +117 -0
- package/src/tools/capabilities.js +42 -0
- package/src/tools/capabilities.ts +69 -0
- package/src/tools/computeruse/accessibilityPermission.js +261 -0
- package/src/tools/computeruse/accessibilityPermission.ts +294 -0
- package/src/tools/computeruse/axSearch.js +96 -0
- package/src/tools/computeruse/axSearch.ts +120 -0
- package/src/tools/computeruse/axSnap.js +272 -0
- package/src/tools/computeruse/axSnap.ts +349 -0
- package/src/tools/computeruse/capabilityLabels.js +95 -0
- package/src/tools/computeruse/capabilityLabels.ts +115 -0
- package/src/tools/computeruse/computerUseService.js +2235 -0
- package/src/tools/computeruse/computerUseService.ts +2686 -0
- package/src/tools/computeruse/computeruse.js +2742 -0
- package/src/tools/computeruse/computeruse.ts +3265 -0
- package/src/tools/computeruse/diagnosticTrace.js +154 -0
- package/src/tools/computeruse/diagnosticTrace.ts +195 -0
- package/src/tools/computeruse/diagnostics.js +369 -0
- package/src/tools/computeruse/diagnostics.ts +453 -0
- package/src/tools/computeruse/grants.js +53 -0
- package/src/tools/computeruse/grants.ts +70 -0
- package/src/tools/computeruse/humanBoundary.js +159 -0
- package/src/tools/computeruse/humanBoundary.ts +199 -0
- package/src/tools/computeruse/intervention.js +77 -0
- package/src/tools/computeruse/intervention.ts +110 -0
- package/src/tools/computeruse/manualSchema.js +709 -0
- package/src/tools/computeruse/manualSchema.ts +916 -0
- package/src/tools/computeruse/observationImages.js +705 -0
- package/src/tools/computeruse/observationImages.ts +889 -0
- package/src/tools/computeruse/protocol.js +60 -0
- package/src/tools/computeruse/protocol.ts +515 -0
- package/src/tools/computeruse/telemetryLog.js +57 -0
- package/src/tools/computeruse/telemetryLog.ts +67 -0
- package/src/tools/computeruse/vision/appGuide.js +325 -0
- package/src/tools/computeruse/vision/appGuide.ts +482 -0
- package/src/tools/computeruse/vision/focus.js +291 -0
- package/src/tools/computeruse/vision/focus.ts +382 -0
- package/src/tools/computeruse/vision/frames.js +248 -0
- package/src/tools/computeruse/vision/frames.ts +329 -0
- package/src/tools/computeruse/vision/geometry.js +131 -0
- package/src/tools/computeruse/vision/geometry.ts +163 -0
- package/src/tools/computeruse/vision/imaging.js +201 -0
- package/src/tools/computeruse/vision/imaging.ts +281 -0
- package/src/tools/computeruse/vision/png.js +274 -0
- package/src/tools/computeruse/vision/png.ts +317 -0
- package/src/tools/computeruse/vision/raster.js +320 -0
- package/src/tools/computeruse/vision/raster.ts +408 -0
- package/src/tools/computeruse/vision/settle.js +131 -0
- package/src/tools/computeruse/vision/settle.ts +220 -0
- package/src/tools/computeruse/vision/telemetry.js +196 -0
- package/src/tools/computeruse/vision/telemetry.ts +241 -0
- package/src/tools/computeruse/visionOcr.js +115 -0
- package/src/tools/computeruse/visionOcr.ts +128 -0
- package/src/tools/computeruse/waitFor.js +237 -0
- package/src/tools/computeruse/waitFor.ts +291 -0
- package/src/tools/download/download.js +10 -6
- package/src/tools/download/download.ts +187 -0
- package/src/tools/edit/edit.js +30 -18
- package/src/tools/edit/edit.ts +349 -0
- package/src/tools/edit/multi-edit.js +25 -14
- package/src/tools/edit/multi-edit.ts +223 -0
- package/src/tools/effectiveToolSet.js +73 -0
- package/src/tools/effectiveToolSet.ts +91 -0
- package/src/tools/genimage/genimage.ts +257 -0
- package/src/tools/genspeech/genspeech.ts +83 -0
- package/src/tools/glob/glob.js +176 -29
- package/src/tools/glob/glob.ts +283 -0
- package/src/tools/grep/grep.js +61 -19
- package/src/tools/grep/grep.ts +239 -0
- package/src/tools/grep/rgPath.ts +206 -0
- package/src/tools/index.js +99 -5
- package/src/tools/index.ts +293 -0
- package/src/tools/lsp/config.js +113 -0
- package/src/tools/lsp/config.ts +113 -0
- package/src/tools/lsp/lsp.js +256 -0
- package/src/tools/lsp/lsp.ts +274 -0
- package/src/tools/lsp/service.js +303 -0
- package/src/tools/lsp/service.ts +296 -0
- package/src/tools/memory/memory.js +520 -0
- package/src/tools/memory/memory.ts +625 -0
- package/src/tools/memory/policy.js +53 -0
- package/src/tools/memory/policy.ts +72 -0
- package/src/tools/notebook/notebookEdit.js +114 -0
- package/src/tools/notebook/notebookEdit.ts +126 -0
- package/src/tools/powershell/powershell.js +210 -0
- package/src/tools/powershell/powershell.ts +239 -0
- package/src/tools/presentresult/presentresult.js +145 -0
- package/src/tools/presentresult/presentresult.ts +156 -0
- package/src/tools/read/read.js +371 -163
- package/src/tools/read/read.ts +558 -0
- package/src/tools/shared/diffSummary.js +44 -0
- package/src/tools/shared/diffSummary.ts +63 -0
- package/src/tools/shared/fileActivity.js +51 -0
- package/src/tools/shared/fileActivity.ts +66 -0
- package/src/tools/shared/fileMutationBus.js +13 -0
- package/src/tools/shared/fileMutationBus.ts +14 -0
- package/src/tools/shared/fileState.js +73 -65
- package/src/tools/shared/fileState.ts +145 -0
- package/src/tools/shared/fileUtils.js +81 -4
- package/src/tools/shared/fileUtils.ts +504 -0
- package/src/tools/shared/killTree.ts +50 -0
- package/src/tools/shared/permanentDeleteGuard.js +26 -0
- package/src/tools/shared/permanentDeleteGuard.ts +34 -0
- package/src/tools/shared/schemas.ts +20 -0
- package/src/tools/shared/toolOutputStore.js +97 -0
- package/src/tools/shared/toolOutputStore.ts +110 -0
- package/src/tools/skill/skill.js +86 -0
- package/src/tools/skill/skill.ts +94 -0
- package/src/tools/snip/snip.js +67 -0
- package/src/tools/snip/snip.ts +80 -0
- package/src/tools/tasks/backgroundTaskService.js +275 -0
- package/src/tools/tasks/backgroundTaskService.ts +369 -0
- package/src/tools/tasks/processEvidence.js +24 -0
- package/src/tools/tasks/processEvidence.ts +34 -0
- package/src/tools/tasks/taskManagement.js +163 -0
- package/src/tools/tasks/taskManagement.ts +180 -0
- package/src/tools/tasks/taskOutput.js +113 -0
- package/src/tools/tasks/taskOutput.ts +145 -0
- package/src/tools/tasks/taskStop.js +74 -0
- package/src/tools/tasks/taskStop.ts +99 -0
- package/src/tools/tasks/taskStore.js +46 -0
- package/src/tools/tasks/taskStore.ts +77 -0
- package/src/tools/terminal/terminalCapture.js +167 -0
- package/src/tools/terminal/terminalCapture.ts +179 -0
- package/src/tools/trash/trash.js +233 -0
- package/src/tools/trash/trash.ts +283 -0
- package/src/tools/types.js +1 -1
- package/src/tools/types.ts +24 -0
- package/src/tools/webbrowser/agentBrowserPath.ts +286 -0
- package/src/tools/webbrowser/browser.js +214 -11
- package/src/tools/webbrowser/browser.ts +293 -0
- package/src/tools/webbrowser/browserControl.js +153 -48
- package/src/tools/webbrowser/browserControl.ts +262 -0
- package/src/tools/webbrowser/browserDaemon.js +147 -39
- package/src/tools/webbrowser/browserDaemon.ts +270 -0
- package/src/tools/webbrowser/browserOutcome.js +273 -0
- package/src/tools/webbrowser/browserOutcome.ts +306 -0
- package/src/tools/webbrowser/browserRunRegistry.js +150 -0
- package/src/tools/webbrowser/browserRunRegistry.ts +179 -0
- package/src/tools/webbrowser/browserService.js +20 -6
- package/src/tools/webbrowser/browserService.ts +56 -0
- package/src/tools/webbrowser/browserStream.js +30 -1
- package/src/tools/webbrowser/browserStream.ts +216 -0
- package/src/tools/webbrowser/browserTabs.js +143 -0
- package/src/tools/webbrowser/browserTabs.ts +210 -0
- package/src/tools/webbrowser/webbrowser.js +831 -150
- package/src/tools/webbrowser/webbrowser.ts +1537 -0
- package/src/tools/webfetch/preapproved.ts +274 -0
- package/src/tools/webfetch/webfetch.js +24 -23
- package/src/tools/webfetch/webfetch.ts +383 -0
- package/src/tools/websearch/websearch.js +12 -11
- package/src/tools/websearch/websearch.ts +292 -0
- package/src/tools/worktree/sessionWorktree.js +128 -0
- package/src/tools/worktree/sessionWorktree.ts +158 -0
- package/src/tools/write/write.js +27 -44
- package/src/tools/write/write.ts +136 -0
- package/src/types.ts +960 -0
- package/src/ui/App.js +216 -12
- package/src/ui/App.tsx +879 -0
- package/src/ui/AskQuestion.tsx +300 -0
- package/src/ui/InputBox.js +77 -1
- package/src/ui/InputBox.tsx +567 -0
- package/src/ui/LiveArea.tsx +344 -0
- package/src/ui/MessageList.js +27 -6
- package/src/ui/MessageList.tsx +559 -0
- package/src/ui/ModelPicker.tsx +107 -0
- package/src/ui/QueuedMessagesBanner.tsx +51 -0
- package/src/ui/Root.js +6 -8
- package/src/ui/Root.tsx +100 -0
- package/src/ui/SessionPicker.tsx +169 -0
- package/src/ui/StatusLine.js +22 -1
- package/src/ui/StatusLine.tsx +145 -0
- package/src/ui/WorkspacePicker.tsx +84 -0
- package/src/ui/advisorCommand.js +54 -0
- package/src/ui/advisorCommand.ts +63 -0
- package/src/ui/computerCommand.js +19 -0
- package/src/ui/computerCommand.ts +35 -0
- package/src/ui/figures.ts +45 -0
- package/src/ui/hooks/askSlot.ts +112 -0
- package/src/ui/hooks/useChat.js +271 -7
- package/src/ui/hooks/useChat.ts +1578 -0
- package/src/ui/hooks/useInputHistory.ts +235 -0
- package/src/ui/hooks/usePasteHandler.ts +220 -0
- package/src/ui/hooks/useTerminalSize.ts +41 -0
- package/src/ui/hooks/useTextBuffer.ts +108 -0
- package/src/ui/hooks/useTokenUsage.ts +44 -0
- package/src/ui/liveViewport.ts +189 -0
- package/src/ui/markdown.ts +230 -0
- package/src/ui/textBuffer.ts +239 -0
- package/src/ui/theme.ts +35 -0
- package/src/utils/clipboardImage.js +358 -0
- package/src/utils/clipboardImage.ts +420 -0
- package/src/utils/debugLog.ts +50 -0
- package/src/utils/greenRoot.ts +35 -0
- package/src/utils/packageRoot.ts +40 -0
- package/src/utils/pathContains.js +28 -0
- package/src/utils/pathContains.ts +31 -0
- package/src/utils/resourcePaths.ts +71 -0
- package/src/utils/stripThink.ts +49 -0
- package/src/utils/zodToJson.ts +73 -0
- package/src/web/browserBridge.js +365 -66
- package/src/web/browserBridge.ts +672 -0
- package/src/web/protocol.ts +1804 -0
- package/vendor/computer-use/arm64-darwin/cu-helperd +0 -0
- package/workflows/ppt.yaml +13 -2
- package/workflows/wechat-reading-shots.yaml +315 -0
- package/workflows/word.yaml +11 -1
- package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
- /package/skills/ai-image/scripts/{generate_test.mjs → generate.selftest.mjs} +0 -0
- /package/skills/ai-image/scripts/{generate_from_plan_test.mjs → generate_from_plan.selftest.mjs} +0 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/context/persistContext.ts —— 单个会话文件的持久化读写
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 做的事:
|
|
6
|
+
* 把"上一次关闭时的对话历史"落盘到一个文件。下次启动(TUI 或 -p)
|
|
7
|
+
* 自动加载,等于无缝续上。
|
|
8
|
+
*
|
|
9
|
+
* ⚠️ 本文件本身不管"同一 cwd 下有哪些 session、怎么列出/切换/新建"——
|
|
10
|
+
* 那是 context/sessionRegistry.ts 的职责(已支持完整多 session
|
|
11
|
+
* CRUD + TUI 的 /session /sessions /resume + CLI 的 --session)。
|
|
12
|
+
* 这里只负责"给定一个具体文件路径,读/写/清空它",调用方(TUI 的
|
|
13
|
+
* useChat.ts、CLI 的 main.tsx/print.ts/streamJson.ts)决定要读写哪个
|
|
14
|
+
* session 对应的文件——不传 file 时缺省走 `default` session(向后兼容)。
|
|
15
|
+
*
|
|
16
|
+
* 文件路径:
|
|
17
|
+
* ~/.minimal-agent/sessions/<目录哈希>[--<sessionId>].json
|
|
18
|
+
* (按当前工作目录隔离;可用 MINIMAL_AGENT_CONTEXT_FILE 覆盖,给测试用)
|
|
19
|
+
*
|
|
20
|
+
* 存储格式:
|
|
21
|
+
* { updatedAt: number; messages: Message[] }
|
|
22
|
+
*
|
|
23
|
+
* 抉择:
|
|
24
|
+
* - load 出来若为空或损坏 → 当作"没历史"返回 null,调用方 fallback 到
|
|
25
|
+
* 只含 system prompt 的 fresh history。永不抛错。
|
|
26
|
+
* - save 使用唯一临时文件 + atomic rename,避免崩溃留下半截 JSON;
|
|
27
|
+
* 同一 Session 的跨进程互斥由 contextLock 负责。
|
|
28
|
+
* - 不做 system prompt 替换:调用方拿到 messages 后想替/不替自己决定。
|
|
29
|
+
* ============================================================
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { randomUUID } from 'node:crypto';
|
|
33
|
+
import { mkdir, readFile, readdir, rename, rmdir, unlink, writeFile } from 'node:fs/promises';
|
|
34
|
+
import { dirname, join } from 'node:path';
|
|
35
|
+
|
|
36
|
+
import { getWorkingDir } from '../bootstrap/workingDir.js';
|
|
37
|
+
import type { Message } from '../types.js';
|
|
38
|
+
import { archiveCurrent } from './archive.js';
|
|
39
|
+
import { sessionFileFor } from './sessionPath.js';
|
|
40
|
+
|
|
41
|
+
interface PersistedFile {
|
|
42
|
+
updatedAt: number;
|
|
43
|
+
messages: Message[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** 上下文文件路径(按工作目录隔离,可用环境变量覆盖) */
|
|
47
|
+
export function getContextPath(): string {
|
|
48
|
+
if (process.env.MINIMAL_AGENT_CONTEXT_FILE) {
|
|
49
|
+
return process.env.MINIMAL_AGENT_CONTEXT_FILE;
|
|
50
|
+
}
|
|
51
|
+
return sessionFileFor(getWorkingDir());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 加载上次的上下文。
|
|
56
|
+
* - 文件不存在 / 解析失败 / 格式不符 → 返回 null(调用方应当 fallback)
|
|
57
|
+
* - 成功 → 返回 messages 数组(可能为空数组)
|
|
58
|
+
* - 显式传入 file 时优先使用,便于 HTTP 模式按 sessionKey 隔离
|
|
59
|
+
*/
|
|
60
|
+
export async function loadContext(file?: string): Promise<Message[] | null> {
|
|
61
|
+
const target = file ?? getContextPath();
|
|
62
|
+
try {
|
|
63
|
+
const raw = await readFile(target, 'utf8');
|
|
64
|
+
const data = JSON.parse(raw) as PersistedFile;
|
|
65
|
+
if (!Array.isArray(data.messages)) return null;
|
|
66
|
+
return data.messages;
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 把 messages 数组过滤掉 _ephemeral=true 的 system 消息。
|
|
74
|
+
*
|
|
75
|
+
* v2.x 新增:UI 用 ephemeral system 消息把 slash 命令输出落进 scrollback
|
|
76
|
+
* (替代 process.stdout.write 旁路 Ink)。这种消息只供 UI 展示,不该污染
|
|
77
|
+
* 持久化历史;这里在 saveContext 之前做一次过滤。
|
|
78
|
+
*
|
|
79
|
+
* 导出供测试断言。
|
|
80
|
+
*/
|
|
81
|
+
export function filterEphemeralMessages(messages: Message[]): Message[] {
|
|
82
|
+
return messages.filter(
|
|
83
|
+
(m) => !(m.role === 'system' && (m as { _ephemeral?: true })._ephemeral === true),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 保存当前 messages 为"上下文文件",覆盖之前内容。
|
|
89
|
+
* 写失败不抛——丢一次落盘比把进程崩掉划算。
|
|
90
|
+
*
|
|
91
|
+
* v2.x 新增:写盘前过滤掉 _ephemeral=true 的 system 消息(UI 临时提示,
|
|
92
|
+
* 不应进入持久化历史)。
|
|
93
|
+
*/
|
|
94
|
+
export async function saveContext(messages: Message[], file?: string): Promise<void> {
|
|
95
|
+
const target = file ?? getContextPath();
|
|
96
|
+
const temp = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
97
|
+
try {
|
|
98
|
+
await mkdir(dirname(target), { recursive: true });
|
|
99
|
+
const persistable = filterEphemeralMessages(messages);
|
|
100
|
+
const data: PersistedFile = { updatedAt: Date.now(), messages: persistable };
|
|
101
|
+
await writeFile(temp, JSON.stringify(data), { encoding: 'utf8', mode: 0o600 });
|
|
102
|
+
await rename(temp, target);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
// 不抛(持久化失败不该影响对话本身),但要出声——磁盘满/权限问题时
|
|
105
|
+
// 用户整段会话会静默丢失;与 clearContext 的 archive 失败处理风格对齐。
|
|
106
|
+
try {
|
|
107
|
+
process.stderr.write(
|
|
108
|
+
`[minimal-agent] 会话落盘失败(本轮继续):${(e as Error).message}\n`,
|
|
109
|
+
);
|
|
110
|
+
} catch {
|
|
111
|
+
/* stderr 不可用也不阻断 */
|
|
112
|
+
}
|
|
113
|
+
} finally {
|
|
114
|
+
await unlink(temp).catch(() => {});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 清空上下文文件(/new 用)。文件不存在也算成功。
|
|
120
|
+
*
|
|
121
|
+
* 同时清理当前工作目录下所有 `.minimal-agent` / `.minimal-agent-<tag>/`
|
|
122
|
+
* 状态目录(各类插件可能在 cwd 下创建多个 sessionTag 目录)。
|
|
123
|
+
* 注意:只扫当前 cwd 的子目录,不递归、不跨工作目录,保证并行 session 不串台。
|
|
124
|
+
*/
|
|
125
|
+
export async function clearContext(file?: string): Promise<void> {
|
|
126
|
+
const target = file ?? getContextPath();
|
|
127
|
+
|
|
128
|
+
// 归档当前历史(仅含 system 的空对话会跳过);失败不阻塞 clear
|
|
129
|
+
// 显式传 file(HTTP 模式 / 测试覆盖路径)或 MINIMAL_AGENT_CONTEXT_FILE 激活时
|
|
130
|
+
// 跳过 archive:这两种语义下 caller 自管路径,不应污染默认 archive 目录
|
|
131
|
+
const skipArchive =
|
|
132
|
+
file !== undefined || !!process.env.MINIMAL_AGENT_CONTEXT_FILE;
|
|
133
|
+
if (!skipArchive) {
|
|
134
|
+
try {
|
|
135
|
+
const current = await loadContext(target);
|
|
136
|
+
if (current && current.length > 0) {
|
|
137
|
+
await archiveCurrent(current);
|
|
138
|
+
}
|
|
139
|
+
} catch (e) {
|
|
140
|
+
process.stderr.write(
|
|
141
|
+
`[minimal-agent] archive 失败(继续 clear):${(e as Error).message}\n`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
await unlink(target);
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const cwd = getWorkingDir();
|
|
152
|
+
let topEntries: string[];
|
|
153
|
+
try {
|
|
154
|
+
topEntries = await readdir(cwd);
|
|
155
|
+
} catch {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const stateDirs = topEntries.filter(
|
|
160
|
+
(name) => name === '.minimal-agent' || name.startsWith('.minimal-agent-'),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
for (const name of stateDirs) {
|
|
164
|
+
const dir = join(cwd, name);
|
|
165
|
+
try {
|
|
166
|
+
const entries = await readdir(dir);
|
|
167
|
+
for (const entry of entries) {
|
|
168
|
+
try {
|
|
169
|
+
await unlink(join(dir, entry));
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
await rmdir(dir);
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -88,8 +88,9 @@ function errorMessage(error) {
|
|
|
88
88
|
* @param error 刚刚抛出的错误
|
|
89
89
|
* @param state 可选的独立状态(默认使用进程级单例)
|
|
90
90
|
* @param signal 用户中断信号(透传给内部的 forceCompact → chat(),让"压缩中"这个阶段也能响应 ESC/Ctrl+C)
|
|
91
|
+
* @param promptCache 当前 Session 的缓存路由;压缩请求与主回合保持同一 Provider 路由。
|
|
91
92
|
*/
|
|
92
|
-
export async function reactiveCompactIfApplicable(messages, provider, error, state = defaultState, signal, dependencies = {}) {
|
|
93
|
+
export async function reactiveCompactIfApplicable(messages, provider, error, state = defaultState, signal, dependencies = {}, promptCache) {
|
|
93
94
|
// 非 prompt_too_long 错误:直接短路,不消耗计数
|
|
94
95
|
if (!isPromptTooLongError(error)) {
|
|
95
96
|
return { recovered: false, messages, reason: 'not a prompt-too-long error' };
|
|
@@ -105,18 +106,27 @@ export async function reactiveCompactIfApplicable(messages, provider, error, sta
|
|
|
105
106
|
// Step 1: 先试 LLM 全量压缩
|
|
106
107
|
try {
|
|
107
108
|
const compact = dependencies.forceCompact ?? forceCompact;
|
|
108
|
-
const r = await compact(messages, provider, signal);
|
|
109
|
+
const r = await compact(messages, provider, signal, undefined, promptCache);
|
|
109
110
|
// 救活成功 → 清零计数,让后续继续可用
|
|
110
111
|
state.consecutiveFailures = 0;
|
|
111
112
|
return {
|
|
112
113
|
recovered: true,
|
|
113
114
|
messages: r.messages,
|
|
114
|
-
reason:
|
|
115
|
+
reason: r.mode === 'snip-fallback'
|
|
116
|
+
? `LLM 摘要失败后 snip 兜底成功(${r.before} → ${r.after} tokens)`
|
|
117
|
+
: `LLM 压缩成功(${r.before} → ${r.after} tokens)`,
|
|
115
118
|
before: r.before,
|
|
116
119
|
after: r.after,
|
|
120
|
+
mode: r.mode ?? 'llm-summary',
|
|
121
|
+
degraded: r.degraded ?? false,
|
|
122
|
+
...(r.fallbackReason ? { fallbackReason: r.fallbackReason } : {}),
|
|
123
|
+
...(r.messagesRemoved !== undefined ? { messagesRemoved: r.messagesRemoved } : {}),
|
|
124
|
+
...(r.tokensFreed !== undefined ? { tokensFreed: r.tokensFreed } : {}),
|
|
117
125
|
};
|
|
118
126
|
}
|
|
119
|
-
catch {
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (signal?.aborted || error.name === 'AbortError')
|
|
129
|
+
throw error;
|
|
120
130
|
// 压缩失败 → 走 snip 兜底
|
|
121
131
|
}
|
|
122
132
|
// Step 2: snip 兜底(更激进 40%)
|
|
@@ -132,6 +142,11 @@ export async function reactiveCompactIfApplicable(messages, provider, error, sta
|
|
|
132
142
|
reason: `snip 兜底成功(删除 ${snipped.messagesRemoved} 条最老消息,释放 ~${snipped.tokensFreed} tokens)`,
|
|
133
143
|
before: beforeSnip,
|
|
134
144
|
after: afterSnip,
|
|
145
|
+
mode: 'snip-fallback',
|
|
146
|
+
degraded: true,
|
|
147
|
+
fallbackReason: 'llm-error',
|
|
148
|
+
messagesRemoved: snipped.messagesRemoved,
|
|
149
|
+
tokensFreed: snipped.tokensFreed,
|
|
135
150
|
};
|
|
136
151
|
}
|
|
137
152
|
// 两步都没救活 → 失败计数 +1
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/context/reactiveCompact.ts —— 反应式压缩(错误自救)
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 对齐 kakadeai 主项目 services/compact/reactiveCompact.ts:
|
|
6
|
+
* 当 API 返回 "prompt too long" 类错误时,自动触发压缩重试。
|
|
7
|
+
*
|
|
8
|
+
* 典型场景:
|
|
9
|
+
* 用户灌了一大段上下文 → 调 LLM → 返回 400 prompt_too_long
|
|
10
|
+
* → 系统不直接报错,而是先调 forceCompact 把上下文摘要一遍
|
|
11
|
+
* → 摘要失败再用 snipCompact 砍头兜底
|
|
12
|
+
* → 把新上下文交还给调用方,调用方重试一次 chat()
|
|
13
|
+
*
|
|
14
|
+
* 防爆约束(circuit breaker):
|
|
15
|
+
* 连续自救失败 MAX_CONSECUTIVE_REACTIVE_FAILURES 次才熔断。
|
|
16
|
+
* 任意一次自救成功(LLM 压缩或 snip 兜底)→ 计数清零,
|
|
17
|
+
* 允许后续再次触发。行为:压缩成功→继续→再溢出→再压→正常往复。
|
|
18
|
+
* 用户 /new 重启会话后 consecutiveFailures 也归零。
|
|
19
|
+
* ============================================================
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type {
|
|
23
|
+
CompactionFallbackReason,
|
|
24
|
+
CompactionMode,
|
|
25
|
+
Message,
|
|
26
|
+
PromptCacheContext,
|
|
27
|
+
Provider,
|
|
28
|
+
} from '../types.js';
|
|
29
|
+
import { forceCompact } from './compact.js';
|
|
30
|
+
import { snipCompactIfNeeded } from './snipCompact.js';
|
|
31
|
+
import { countMessagesTokens } from './tokenCounter.js';
|
|
32
|
+
|
|
33
|
+
// ==================== Session 级状态 ====================
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 反应式压缩的运行时状态。模块级 defaultState 用于单进程场景(TUI / print),
|
|
37
|
+
* 多并发场景(HTTP server per-request)调 createReactiveCompactState() 拿独立一份。
|
|
38
|
+
*
|
|
39
|
+
* consecutiveFailures:连续自救失败次数;成功一次清零,≥上限才熔断拒绝(防死循环)。
|
|
40
|
+
*/
|
|
41
|
+
export interface ReactiveCompactState {
|
|
42
|
+
consecutiveFailures: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function createReactiveCompactState(): ReactiveCompactState {
|
|
46
|
+
return { consecutiveFailures: 0 };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 连续失败几次触发熔断,拒绝继续自救 */
|
|
50
|
+
export const MAX_CONSECUTIVE_REACTIVE_FAILURES = 3;
|
|
51
|
+
|
|
52
|
+
const defaultState: ReactiveCompactState = createReactiveCompactState();
|
|
53
|
+
|
|
54
|
+
/** /new 时调用,允许下一个 session 再次自救 */
|
|
55
|
+
export function resetReactiveCompactState(
|
|
56
|
+
state: ReactiveCompactState = defaultState,
|
|
57
|
+
): void {
|
|
58
|
+
state.consecutiveFailures = 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 测试 / 调试用:查询 circuit breaker 是否已熔断(连续失败达上限)。
|
|
63
|
+
*
|
|
64
|
+
* 原签名 hasAttemptedReactiveCompact 在新语义下映射为「电路是否已断开」:
|
|
65
|
+
* 单次成功就清零,只有连续失败 ≥ MAX_CONSECUTIVE_REACTIVE_FAILURES 才返回 true。
|
|
66
|
+
* 效果等价于原先的 attempted 旗标语义的"超集"(原先=1次,新=N次)。
|
|
67
|
+
* 别名 isReactiveCircuitOpen 供新代码使用,两者完全等价。
|
|
68
|
+
*/
|
|
69
|
+
export function hasAttemptedReactiveCompact(
|
|
70
|
+
state: ReactiveCompactState = defaultState,
|
|
71
|
+
): boolean {
|
|
72
|
+
return state.consecutiveFailures >= MAX_CONSECUTIVE_REACTIVE_FAILURES;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** hasAttemptedReactiveCompact 的语义化别名 */
|
|
76
|
+
export const isReactiveCircuitOpen = hasAttemptedReactiveCompact;
|
|
77
|
+
|
|
78
|
+
// ==================== 错误识别 ====================
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 判断一个错误是否是"提示词太长"类错误。
|
|
82
|
+
*
|
|
83
|
+
* 兼容多家 provider 的错误消息格式:
|
|
84
|
+
* - OpenAI: "This model's maximum context length is X tokens..."
|
|
85
|
+
* - Anthropic: "prompt is too long"
|
|
86
|
+
* - MiniMax: "input length exceeds the context window"
|
|
87
|
+
* - DeepSeek: "context_length_exceeded"
|
|
88
|
+
* - 通用: 含 "prompt" / "context" / "token" 且含 "long"/"exceed"/"limit"
|
|
89
|
+
*/
|
|
90
|
+
export function isPromptTooLongError(error: unknown): boolean {
|
|
91
|
+
const msg = errorMessage(error).toLowerCase();
|
|
92
|
+
if (!msg) return false;
|
|
93
|
+
|
|
94
|
+
// 宽松匹配:提及 prompt/context/token 且提及 long/exceed/limit/max
|
|
95
|
+
const hasSubject = /prompt|context|token|input length/.test(msg);
|
|
96
|
+
const hasIssue = /too long|exceed|limit|maximum|over/.test(msg);
|
|
97
|
+
return hasSubject && hasIssue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function errorMessage(error: unknown): string {
|
|
101
|
+
if (typeof error === 'string') return error;
|
|
102
|
+
if (error instanceof Error) return error.message;
|
|
103
|
+
if (error && typeof error === 'object' && 'message' in error) {
|
|
104
|
+
return String((error as { message: unknown }).message ?? '');
|
|
105
|
+
}
|
|
106
|
+
return String(error ?? '');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ==================== 核心函数 ====================
|
|
110
|
+
|
|
111
|
+
export interface ReactiveCompactResult {
|
|
112
|
+
/** 是否成功自救(true 表示调用方可以拿 messages 重试 chat()) */
|
|
113
|
+
recovered: boolean;
|
|
114
|
+
/** 自救后的新历史(recovered=false 时与原数组等价) */
|
|
115
|
+
messages: Message[];
|
|
116
|
+
/** 解释发生了什么;recovered=true 时含简短说明,否则含拒绝理由 */
|
|
117
|
+
reason: string;
|
|
118
|
+
/** 压缩前的 token 数(仅 recovered=true 时填充,供 UI 展示压缩效果) */
|
|
119
|
+
before?: number;
|
|
120
|
+
/** 压缩后的 token 数(仅 recovered=true 时填充) */
|
|
121
|
+
after?: number;
|
|
122
|
+
mode?: CompactionMode;
|
|
123
|
+
degraded?: boolean;
|
|
124
|
+
fallbackReason?: CompactionFallbackReason;
|
|
125
|
+
messagesRemoved?: number;
|
|
126
|
+
tokensFreed?: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface ReactiveCompactDependencies {
|
|
130
|
+
forceCompact?: (
|
|
131
|
+
messages: Message[],
|
|
132
|
+
provider: Provider,
|
|
133
|
+
signal?: AbortSignal,
|
|
134
|
+
chatFn?: Parameters<typeof forceCompact>[3],
|
|
135
|
+
promptCache?: PromptCacheContext,
|
|
136
|
+
) => Promise<{
|
|
137
|
+
messages: Message[];
|
|
138
|
+
before: number;
|
|
139
|
+
after: number;
|
|
140
|
+
mode?: CompactionMode;
|
|
141
|
+
degraded?: boolean;
|
|
142
|
+
fallbackReason?: CompactionFallbackReason;
|
|
143
|
+
messagesRemoved?: number;
|
|
144
|
+
tokensFreed?: number;
|
|
145
|
+
}>;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 如果当前错误是 prompt_too_long 且 circuit breaker 未熔断,
|
|
150
|
+
* 执行一次"先 LLM 压缩、失败兜底 snip"的恢复流程。
|
|
151
|
+
*
|
|
152
|
+
* circuit breaker 规则:
|
|
153
|
+
* - 任意成功(LLM 压缩 or snip 兜底)→ consecutiveFailures 清零
|
|
154
|
+
* - 两个步骤都失败 → consecutiveFailures +1
|
|
155
|
+
* - consecutiveFailures ≥ MAX_CONSECUTIVE_REACTIVE_FAILURES → 熔断拒绝
|
|
156
|
+
*
|
|
157
|
+
* @param messages 当前历史(不修改)
|
|
158
|
+
* @param provider 当前 provider(用于 LLM 压缩)
|
|
159
|
+
* @param error 刚刚抛出的错误
|
|
160
|
+
* @param state 可选的独立状态(默认使用进程级单例)
|
|
161
|
+
* @param signal 用户中断信号(透传给内部的 forceCompact → chat(),让"压缩中"这个阶段也能响应 ESC/Ctrl+C)
|
|
162
|
+
* @param promptCache 当前 Session 的缓存路由;压缩请求与主回合保持同一 Provider 路由。
|
|
163
|
+
*/
|
|
164
|
+
export async function reactiveCompactIfApplicable(
|
|
165
|
+
messages: Message[],
|
|
166
|
+
provider: Provider,
|
|
167
|
+
error: unknown,
|
|
168
|
+
state: ReactiveCompactState = defaultState,
|
|
169
|
+
signal?: AbortSignal,
|
|
170
|
+
dependencies: ReactiveCompactDependencies = {},
|
|
171
|
+
promptCache?: PromptCacheContext,
|
|
172
|
+
): Promise<ReactiveCompactResult> {
|
|
173
|
+
// 非 prompt_too_long 错误:直接短路,不消耗计数
|
|
174
|
+
if (!isPromptTooLongError(error)) {
|
|
175
|
+
return { recovered: false, messages, reason: 'not a prompt-too-long error' };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 电路已熔断:连续失败达上限,拒绝继续
|
|
179
|
+
if (state.consecutiveFailures >= MAX_CONSECUTIVE_REACTIVE_FAILURES) {
|
|
180
|
+
return {
|
|
181
|
+
recovered: false,
|
|
182
|
+
messages,
|
|
183
|
+
reason: '反应式压缩已熔断(连续失败达上限)——请 /new 或手动 /compact',
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Step 1: 先试 LLM 全量压缩
|
|
188
|
+
try {
|
|
189
|
+
const compact = dependencies.forceCompact ?? forceCompact;
|
|
190
|
+
const r = await compact(messages, provider, signal, undefined, promptCache);
|
|
191
|
+
// 救活成功 → 清零计数,让后续继续可用
|
|
192
|
+
state.consecutiveFailures = 0;
|
|
193
|
+
return {
|
|
194
|
+
recovered: true,
|
|
195
|
+
messages: r.messages,
|
|
196
|
+
reason: r.mode === 'snip-fallback'
|
|
197
|
+
? `LLM 摘要失败后 snip 兜底成功(${r.before} → ${r.after} tokens)`
|
|
198
|
+
: `LLM 压缩成功(${r.before} → ${r.after} tokens)`,
|
|
199
|
+
before: r.before,
|
|
200
|
+
after: r.after,
|
|
201
|
+
mode: r.mode ?? 'llm-summary',
|
|
202
|
+
degraded: r.degraded ?? false,
|
|
203
|
+
...(r.fallbackReason ? { fallbackReason: r.fallbackReason } : {}),
|
|
204
|
+
...(r.messagesRemoved !== undefined ? { messagesRemoved: r.messagesRemoved } : {}),
|
|
205
|
+
...(r.tokensFreed !== undefined ? { tokensFreed: r.tokensFreed } : {}),
|
|
206
|
+
};
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (signal?.aborted || (error as Error).name === 'AbortError') throw error;
|
|
209
|
+
// 压缩失败 → 走 snip 兜底
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Step 2: snip 兜底(更激进 40%)
|
|
213
|
+
const beforeSnip = countMessagesTokens(messages);
|
|
214
|
+
const snipped = snipCompactIfNeeded(messages, { force: true, snipPercent: 0.4 });
|
|
215
|
+
if (snipped.messagesRemoved > 0) {
|
|
216
|
+
// snip 也算救活 → 清零计数
|
|
217
|
+
state.consecutiveFailures = 0;
|
|
218
|
+
const afterSnip = countMessagesTokens(snipped.messages);
|
|
219
|
+
return {
|
|
220
|
+
recovered: true,
|
|
221
|
+
messages: snipped.messages,
|
|
222
|
+
reason: `snip 兜底成功(删除 ${snipped.messagesRemoved} 条最老消息,释放 ~${snipped.tokensFreed} tokens)`,
|
|
223
|
+
before: beforeSnip,
|
|
224
|
+
after: afterSnip,
|
|
225
|
+
mode: 'snip-fallback',
|
|
226
|
+
degraded: true,
|
|
227
|
+
fallbackReason: 'llm-error',
|
|
228
|
+
messagesRemoved: snipped.messagesRemoved,
|
|
229
|
+
tokensFreed: snipped.tokensFreed,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// 两步都没救活 → 失败计数 +1
|
|
234
|
+
state.consecutiveFailures++;
|
|
235
|
+
return {
|
|
236
|
+
recovered: false,
|
|
237
|
+
messages,
|
|
238
|
+
reason: '反应式压缩失败:LLM 压缩抛错且 snip 也没东西可砍',
|
|
239
|
+
};
|
|
240
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Compatibility facade over the authoritative Workspace Index. */
|
|
2
|
+
import { workspaceIndexService } from './workspaceIndex.js';
|
|
3
|
+
|
|
4
|
+
export interface RecentDirEntry {
|
|
5
|
+
path: string;
|
|
6
|
+
name: string;
|
|
7
|
+
lastUsedAt: number;
|
|
8
|
+
title?: string;
|
|
9
|
+
/** Legacy v1 hint. It is never used as an existence check. */
|
|
10
|
+
sessionFile?: string;
|
|
11
|
+
available?: boolean;
|
|
12
|
+
workspaceId?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function asRecent(workspace: Awaited<ReturnType<typeof workspaceIndexService.list>>[number]): RecentDirEntry {
|
|
16
|
+
const latest = [...workspace.sessions].sort((a, b) => b.updatedAt - a.updatedAt)[0];
|
|
17
|
+
return {
|
|
18
|
+
path: workspace.displayPath,
|
|
19
|
+
name: workspace.displayName,
|
|
20
|
+
lastUsedAt: workspace.lastActiveAt,
|
|
21
|
+
...(latest?.title ? { title: latest.title } : {}),
|
|
22
|
+
available: workspace.available,
|
|
23
|
+
workspaceId: workspace.id,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function listRecentDirs(): Promise<RecentDirEntry[]> {
|
|
28
|
+
return (await workspaceIndexService.list()).map(asRecent);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function upsertRecentDir(cwd: string, title?: string): Promise<RecentDirEntry> {
|
|
32
|
+
return asRecent(await workspaceIndexService.register(cwd, title));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Best-effort CLI hook: index failure must not fail an Agent turn. */
|
|
36
|
+
export async function recordRecentDir(cwd: string, title?: string): Promise<void> {
|
|
37
|
+
await workspaceIndexService.register(cwd, title).then(() => undefined, () => undefined);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function removeRecentDir(cwd: string): Promise<void> {
|
|
41
|
+
await workspaceIndexService.removeWorkspace(cwd);
|
|
42
|
+
}
|