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.
Files changed (472) hide show
  1. package/README.md +6 -5
  2. package/package.json +62 -5
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +204 -185
  16. package/plugins/workflow-runner/src/index.ts +249 -224
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +404 -467
  28. package/plugins/workflow-runner/src/runner.ts +491 -535
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +172 -152
  54. package/plugins/workflow-runner/src/taskIdentity.ts +233 -200
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -105
  58. package/plugins/workflow-runner/src/types.ts +155 -520
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +542 -469
  68. package/plugins/workflow-runner/src/workflowState.ts +639 -589
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/skill-creator/scripts/run_eval.py +3 -2
  92. package/skills/ui-design/SKILL.md +5 -2
  93. package/skills/ui-design/references/layout-composition.md +1 -1
  94. package/skills/workflow-creator/SKILL.md +344 -0
  95. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  96. package/skills/workflow-creator/references/api.md +216 -0
  97. package/skills/workflow-creator/references/migration.md +103 -0
  98. package/skills/workflow-creator/references/patterns.md +779 -0
  99. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  100. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  101. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  102. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  103. package/src/advisor/advisorCoordinator.js +503 -0
  104. package/src/advisor/advisorCoordinator.ts +657 -0
  105. package/src/cli/configMenu.tsx +0 -1
  106. package/src/cli/print.js +44 -6
  107. package/src/cli/print.ts +73 -4
  108. package/src/cli/streamJson.js +5 -6
  109. package/src/cli/streamJson.ts +8 -4
  110. package/src/cli/wizards/advisorWizard.js +4 -2
  111. package/src/cli/wizards/advisorWizard.tsx +8 -2
  112. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  113. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  114. package/src/collaboration/taskFlow.js +115 -0
  115. package/src/collaboration/taskFlow.ts +169 -0
  116. package/src/config/configDefaults.js +41 -1
  117. package/src/config/configDefaults.ts +43 -1
  118. package/src/config/configDiagnostics.ts +2 -2
  119. package/src/config/configFile.js +40 -9
  120. package/src/config/configFile.ts +60 -11
  121. package/src/config/configService.js +443 -74
  122. package/src/config/configService.ts +723 -142
  123. package/src/config/numericLimits.js +22 -0
  124. package/src/config/numericLimits.ts +24 -0
  125. package/src/config.js +1 -0
  126. package/src/config.ts +3 -2
  127. package/src/context/budgetPlan.js +1 -1
  128. package/src/context/budgetPlan.ts +1 -1
  129. package/src/context/compact.js +7 -2
  130. package/src/context/compact.ts +9 -2
  131. package/src/context/microCompactLite.js +212 -13
  132. package/src/context/microCompactLite.ts +261 -12
  133. package/src/context/sessionRegistry.js +8 -1
  134. package/src/context/sessionRegistry.ts +18 -5
  135. package/src/context/toolResultArchive.js +72 -0
  136. package/src/context/toolResultArchive.ts +95 -0
  137. package/src/goal/errors.js +8 -0
  138. package/src/goal/errors.ts +18 -0
  139. package/src/goal/goalRuntime.js +344 -0
  140. package/src/goal/goalRuntime.ts +466 -0
  141. package/src/goal/goalStore.js +200 -0
  142. package/src/goal/goalStore.ts +219 -0
  143. package/src/goal/index.js +4 -0
  144. package/src/goal/index.ts +4 -0
  145. package/src/goal/statusMapping.js +71 -0
  146. package/src/goal/statusMapping.ts +95 -0
  147. package/src/goal/types.js +7 -0
  148. package/src/goal/types.ts +179 -0
  149. package/src/goal/workflowController.js +306 -0
  150. package/src/goal/workflowController.ts +360 -0
  151. package/src/harness/evidenceLedger.js +2 -0
  152. package/src/harness/evidenceLedger.ts +1 -0
  153. package/src/harness/stallGuard.js +9 -3
  154. package/src/harness/stallGuard.ts +7 -3
  155. package/src/images/imageResolver.js +161 -0
  156. package/src/images/imageResolver.ts +189 -0
  157. package/src/infra/verification.js +56 -20
  158. package/src/infra/verification.ts +87 -20
  159. package/src/llm/client.js +79 -21
  160. package/src/llm/client.ts +182 -35
  161. package/src/llm/gatewayClient.js +201 -0
  162. package/src/llm/gatewayClient.ts +299 -0
  163. package/src/llm/messageProvenance.js +46 -0
  164. package/src/llm/messageProvenance.ts +58 -0
  165. package/src/llm/modelProvider.js +1 -0
  166. package/src/llm/modelProvider.ts +22 -0
  167. package/src/llm/providers/anthropicFormat.js +108 -1
  168. package/src/llm/providers/anthropicFormat.ts +115 -4
  169. package/src/llm/providers/openaiFormat.js +9 -0
  170. package/src/llm/providers/openaiFormat.ts +12 -3
  171. package/src/loop.js +319 -54
  172. package/src/loop.ts +373 -57
  173. package/src/main.js +4 -1
  174. package/src/main.tsx +4 -1
  175. package/src/managedExecution/index.js +2 -0
  176. package/src/managedExecution/index.ts +2 -0
  177. package/src/managedExecution/registry.js +15 -0
  178. package/src/managedExecution/registry.ts +20 -0
  179. package/src/managedExecution/types.js +1 -0
  180. package/src/managedExecution/types.ts +86 -0
  181. package/src/modelRef.js +9 -0
  182. package/src/modelRef.ts +31 -0
  183. package/src/multimodal.js +14 -28
  184. package/src/multimodal.ts +17 -33
  185. package/src/net/lanDiscovery.js +65 -0
  186. package/src/net/lanDiscovery.ts +82 -0
  187. package/src/plugin-sdk.js +28 -3
  188. package/src/plugin-sdk.ts +39 -6
  189. package/src/plugins/pluginApi.ts +16 -1
  190. package/src/plugins/pluginLoader.js +4 -0
  191. package/src/plugins/pluginLoader.ts +6 -0
  192. package/src/plugins/pluginRunner.js +152 -9
  193. package/src/plugins/pluginRunner.ts +186 -8
  194. package/src/plugins/slashFallback.js +113 -0
  195. package/src/plugins/slashFallback.ts +137 -0
  196. package/src/prompts/policyRegistry.js +15 -8
  197. package/src/prompts/policyRegistry.ts +18 -8
  198. package/src/prompts/promptAssembly.js +103 -12
  199. package/src/prompts/promptAssembly.ts +114 -12
  200. package/src/prompts/skillList.js +21 -3
  201. package/src/prompts/skillList.ts +27 -2
  202. package/src/prompts/stableSystemPrompt.js +18 -0
  203. package/src/prompts/stableSystemPrompt.ts +33 -0
  204. package/src/runtime/agentRuntimeContext.js +8 -2
  205. package/src/runtime/agentRuntimeContext.ts +17 -4
  206. package/src/session/runAgentTurn.js +78 -12
  207. package/src/session/runAgentTurn.ts +105 -23
  208. package/src/session/runTurn.js +10 -9
  209. package/src/session/runTurn.ts +17 -8
  210. package/src/session/sessionState.ts +2 -0
  211. package/src/team/auth.js +186 -0
  212. package/src/team/auth.ts +298 -0
  213. package/src/team/cli.js +105 -0
  214. package/src/team/cli.ts +122 -0
  215. package/src/team/onlineToolContract.js +64 -0
  216. package/src/team/onlineToolContract.ts +109 -0
  217. package/src/team/toolPolicy.js +36 -0
  218. package/src/team/toolPolicy.ts +75 -0
  219. package/src/tools/advisor/advisor.js +148 -37
  220. package/src/tools/advisor/advisor.ts +161 -38
  221. package/src/tools/advisor/advisorDecision.js +71 -0
  222. package/src/tools/advisor/advisorDecision.ts +85 -0
  223. package/src/tools/agent/agent.js +18 -5
  224. package/src/tools/agent/agent.ts +21 -7
  225. package/src/tools/agent/agentControl.js +246 -0
  226. package/src/tools/agent/agentControl.ts +284 -0
  227. package/src/tools/agent/agentTaskService.js +40 -1
  228. package/src/tools/agent/agentTaskService.ts +44 -1
  229. package/src/tools/agent/agentTypes.js +14 -2
  230. package/src/tools/agent/agentTypes.ts +15 -2
  231. package/src/tools/applypatch/applyPatch.js +362 -0
  232. package/src/tools/applypatch/applyPatch.ts +428 -0
  233. package/src/tools/bash/bash.js +70 -18
  234. package/src/tools/bash/bash.ts +75 -20
  235. package/src/tools/capabilities.js +10 -5
  236. package/src/tools/capabilities.ts +10 -5
  237. package/src/tools/computeruse/computerIntent.js +32 -0
  238. package/src/tools/computeruse/computerIntent.ts +46 -0
  239. package/src/tools/computeruse/telemetryLog.js +12 -0
  240. package/src/tools/computeruse/telemetryLog.ts +16 -0
  241. package/src/tools/computeruse/vision/telemetry.js +1 -0
  242. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  243. package/src/tools/effectiveToolSet.js +4 -0
  244. package/src/tools/effectiveToolSet.ts +4 -0
  245. package/src/tools/index.js +21 -2
  246. package/src/tools/index.ts +33 -2
  247. package/src/tools/powershell/powershell.js +18 -1
  248. package/src/tools/powershell/powershell.ts +18 -2
  249. package/src/tools/presentresult/presentresult.js +6 -15
  250. package/src/tools/presentresult/presentresult.ts +6 -15
  251. package/src/tools/read/read.js +69 -11
  252. package/src/tools/read/read.ts +70 -11
  253. package/src/tools/shared/fileUtils.js +1 -2
  254. package/src/tools/shared/fileUtils.ts +1 -2
  255. package/src/tools/shared/permanentDeleteGuard.js +34 -3
  256. package/src/tools/shared/permanentDeleteGuard.ts +43 -6
  257. package/src/tools/shared/toolOutputStore.js +23 -1
  258. package/src/tools/shared/toolOutputStore.ts +22 -1
  259. package/src/tools/skill/skill.js +9 -3
  260. package/src/tools/skill/skill.ts +8 -4
  261. package/src/tools/toolPromptGuides.js +117 -0
  262. package/src/tools/toolPromptGuides.ts +137 -0
  263. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  264. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  265. package/src/tools/webbrowser/browser.js +27 -11
  266. package/src/tools/webbrowser/browser.ts +68 -24
  267. package/src/tools/webbrowser/browserAutomation.js +329 -0
  268. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  269. package/src/tools/webbrowser/browserAxState.js +97 -0
  270. package/src/tools/webbrowser/browserAxState.ts +142 -0
  271. package/src/tools/webbrowser/browserBatch.js +1578 -0
  272. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  273. package/src/tools/webbrowser/browserCdp.js +208 -0
  274. package/src/tools/webbrowser/browserCdp.ts +255 -0
  275. package/src/tools/webbrowser/browserConditions.js +24 -0
  276. package/src/tools/webbrowser/browserConditions.ts +45 -0
  277. package/src/tools/webbrowser/browserContent.js +281 -0
  278. package/src/tools/webbrowser/browserContent.ts +438 -0
  279. package/src/tools/webbrowser/browserControl.js +131 -30
  280. package/src/tools/webbrowser/browserControl.ts +210 -50
  281. package/src/tools/webbrowser/browserDaemon.js +22 -14
  282. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  283. package/src/tools/webbrowser/browserFrames.js +47 -0
  284. package/src/tools/webbrowser/browserFrames.ts +54 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  286. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  287. package/src/tools/webbrowser/browserLocator.js +140 -0
  288. package/src/tools/webbrowser/browserLocator.ts +194 -0
  289. package/src/tools/webbrowser/browserOutcome.js +10 -17
  290. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  291. package/src/tools/webbrowser/browserRecovery.js +58 -0
  292. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  293. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  294. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  295. package/src/tools/webbrowser/browserService.js +28 -2
  296. package/src/tools/webbrowser/browserService.ts +49 -9
  297. package/src/tools/webbrowser/browserStream.js +132 -33
  298. package/src/tools/webbrowser/browserStream.ts +224 -50
  299. package/src/tools/webbrowser/browserTabs.js +48 -15
  300. package/src/tools/webbrowser/browserTabs.ts +178 -96
  301. package/src/tools/webbrowser/webbrowser.js +683 -144
  302. package/src/tools/webbrowser/webbrowser.ts +979 -236
  303. package/src/tools/webfetch/preapproved.js +0 -2
  304. package/src/tools/webfetch/preapproved.ts +0 -2
  305. package/src/tools/websearch/websearch.js +129 -8
  306. package/src/tools/websearch/websearch.ts +138 -6
  307. package/src/types.ts +450 -42
  308. package/src/ui/App.js +377 -58
  309. package/src/ui/App.tsx +576 -111
  310. package/src/ui/LiveArea.js +14 -8
  311. package/src/ui/LiveArea.tsx +14 -10
  312. package/src/ui/MessageList.js +63 -20
  313. package/src/ui/MessageList.tsx +101 -16
  314. package/src/ui/ModelPicker.js +7 -4
  315. package/src/ui/ModelPicker.tsx +55 -8
  316. package/src/ui/hooks/useChat.js +152 -163
  317. package/src/ui/hooks/useChat.ts +396 -334
  318. package/src/ui/loginCommand.js +56 -0
  319. package/src/ui/loginCommand.ts +63 -0
  320. package/src/ui/toolProgress.js +41 -0
  321. package/src/ui/toolProgress.ts +44 -0
  322. package/src/web/browserBridge.js +20 -2
  323. package/src/web/browserBridge.ts +20 -2
  324. package/src/web/protocol.ts +1897 -194
  325. package/workflows/adaptive-research/workflow.mjs +86 -0
  326. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  327. package/workflows/e2e-llm/workflow.mjs +52 -0
  328. package/workflows/e2e-smoke/workflow.mjs +59 -0
  329. package/workflows/e2e-vision-schema/README.md +48 -0
  330. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  331. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  332. package/workflows/file-census/README.md +14 -0
  333. package/workflows/file-census/scripts/.gitkeep +2 -0
  334. package/workflows/file-census/workflow.mjs +110 -0
  335. package/workflows/goal/README.md +166 -0
  336. package/workflows/goal/prompts/audit.md +57 -0
  337. package/workflows/goal/prompts/contract.md +56 -0
  338. package/workflows/goal/prompts/iterate.md +37 -0
  339. package/workflows/goal/workflow.mjs +501 -0
  340. package/workflows/illustrate/README.md +90 -0
  341. package/workflows/illustrate/assets/engines.json +20 -0
  342. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  343. package/workflows/illustrate/assets/extract-bing.js +33 -0
  344. package/workflows/illustrate/assets/extract-google.js +31 -0
  345. package/workflows/illustrate/workflow.mjs +301 -0
  346. package/workflows/plan/workflow.mjs +389 -0
  347. package/workflows/question-crops/README.md +35 -0
  348. package/workflows/question-crops/prompts/inventory.md +23 -0
  349. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  350. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  351. package/workflows/question-crops/workflow.mjs +172 -0
  352. package/workflows/ralph-loop/workflow.mjs +162 -0
  353. package/workflows/research/DESIGN.md +449 -0
  354. package/workflows/research/README.md +74 -0
  355. package/workflows/research/prompts/s0-goal.md +43 -0
  356. package/workflows/research/prompts/s1-early-exit.md +22 -0
  357. package/workflows/research/prompts/s1-map.md +58 -0
  358. package/workflows/research/prompts/s2-options.md +53 -0
  359. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  360. package/workflows/research/prompts/s4-verify.md +74 -0
  361. package/workflows/research/prompts/s5-synthesis.md +81 -0
  362. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  363. package/workflows/research/prompts/s6-package.md +32 -0
  364. package/workflows/research/scripts/build-report.mjs +98 -0
  365. package/workflows/research/workflow.mjs +288 -0
  366. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  367. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  368. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  369. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  370. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  371. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  372. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  373. package/workflows/wrong-question-docx/README.md +55 -0
  374. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  375. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  376. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  377. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  378. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  379. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  380. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  381. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  382. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  383. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  384. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  385. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  386. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  387. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  388. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  389. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  390. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  391. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  392. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  393. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  394. package/plugins/workflow-runner/src/expressions.js +0 -618
  395. package/plugins/workflow-runner/src/expressions.ts +0 -622
  396. package/plugins/workflow-runner/src/loader.js +0 -573
  397. package/plugins/workflow-runner/src/loader.ts +0 -721
  398. package/plugins/workflow-runner/src/multimodal.js +0 -38
  399. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  400. package/plugins/workflow-runner/src/recovery.js +0 -119
  401. package/plugins/workflow-runner/src/recovery.ts +0 -149
  402. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  403. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  404. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -41
  405. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -50
  406. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  407. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  408. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  409. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  410. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  411. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  412. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  413. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  414. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -208
  415. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -256
  416. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -58
  417. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -68
  418. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  419. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  420. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  421. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  422. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  423. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  424. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -147
  425. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  426. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  427. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -226
  428. package/plugins/workflow-runner/test/expressions.test.ts +0 -397
  429. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  430. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  431. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  432. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  433. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  434. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  435. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  436. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  437. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  438. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  439. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -87
  440. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  441. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  442. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -220
  443. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -379
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -150
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -338
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -270
  451. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  452. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  453. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  454. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  455. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  456. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  457. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  458. package/src/advisorState.js +0 -22
  459. package/src/cli/configWizard.js +0 -293
  460. package/src/tools/toolProgressBridge.js +0 -48
  461. package/workflows/adaptive-research.yaml +0 -50
  462. package/workflows/book-review-short.yaml +0 -125
  463. package/workflows/e2e-write-greet.yaml +0 -31
  464. package/workflows/illustrate.yaml +0 -227
  465. package/workflows/plan.yaml +0 -470
  466. package/workflows/ppt.yaml +0 -1670
  467. package/workflows/ralph-loop.yaml +0 -199
  468. package/workflows/schema.json +0 -176
  469. package/workflows/webppt.yaml +0 -496
  470. package/workflows/wechat-reading-shots.yaml +0 -315
  471. package/workflows/word.yaml +0 -720
  472. package/workflows/youtube-shorts.yaml +0 -202
@@ -104,8 +104,6 @@ const PREAPPROVED_HOSTS = new Set([
104
104
  'dev.mysql.com',
105
105
  'docs.mongodb.com',
106
106
  'www.mongodb.com',
107
- 'sqlite.org',
108
- 'www.sqlite.org',
109
107
  // 工具类
110
108
  'regex101.com',
111
109
  'ihateregex.io',
@@ -105,8 +105,6 @@ const PREAPPROVED_HOSTS = new Set<string>([
105
105
  'dev.mysql.com',
106
106
  'docs.mongodb.com',
107
107
  'www.mongodb.com',
108
- 'sqlite.org',
109
- 'www.sqlite.org',
110
108
  // 工具类
111
109
  'regex101.com',
112
110
  'ihateregex.io',
@@ -21,6 +21,9 @@
21
21
  * max_results 可选,默认 5(Tavily 上限 20)
22
22
  * search_depth 可选 'basic' | 'advanced',默认 basic
23
23
  * topic 可选 'general' | 'news',默认 general
24
+ * recency 可选自动/相对/本年时间窗口
25
+ * start_date 可选 YYYY-MM-DD 绝对起始日期
26
+ * end_date 可选 YYYY-MM-DD 绝对结束日期
24
27
  *
25
28
  * 输出:
26
29
  * 每条结果一段:
@@ -35,6 +38,16 @@ import { configService } from '../../config/configService.js';
35
38
  import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
36
39
  import { toToolParameters } from '../../utils/zodToJson.js';
37
40
  // ---------------- 1. Zod 输入 schema ----------------
41
+ const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
42
+ function isValidIsoDate(value) {
43
+ if (!ISO_DATE.test(value))
44
+ return false;
45
+ const [year, month, day] = value.split('-').map(Number);
46
+ const date = new Date(Date.UTC(year, month - 1, day));
47
+ return date.getUTCFullYear() === year
48
+ && date.getUTCMonth() === month - 1
49
+ && date.getUTCDate() === day;
50
+ }
38
51
  const inputSchema = z.object({
39
52
  query: z
40
53
  .string()
@@ -56,6 +69,27 @@ const inputSchema = z.object({
56
69
  .enum(['general', 'news'])
57
70
  .optional()
58
71
  .describe('general=通用网页;news=偏新闻源;默认 general'),
72
+ recency: z
73
+ .enum(['auto', 'none', 'day', 'week', 'month', 'year', 'current_year'])
74
+ .optional()
75
+ .describe('时效范围:auto 根据查询识别;none 不限时间;day/week/month/year 为相对窗口;current_year 今年优先且结果不足时扩展到去年'),
76
+ start_date: z
77
+ .string()
78
+ .refine(isValidIsoDate, 'start_date 必须是有效的 YYYY-MM-DD 日期')
79
+ .optional()
80
+ .describe('只返回该日期之后发布或更新的结果;与 end_date 配合使用'),
81
+ end_date: z
82
+ .string()
83
+ .refine(isValidIsoDate, 'end_date 必须是有效的 YYYY-MM-DD 日期')
84
+ .optional()
85
+ .describe('只返回该日期之前发布或更新的结果;与 start_date 配合使用'),
86
+ }).superRefine((input, ctx) => {
87
+ if (input.start_date && input.end_date && input.start_date > input.end_date) {
88
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['end_date'], message: 'end_date 不能早于 start_date' });
89
+ }
90
+ if ((input.start_date || input.end_date) && input.recency && !['auto', 'none'].includes(input.recency)) {
91
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['recency'], message: '绝对日期范围与相对 recency 不能同时使用' });
92
+ }
59
93
  });
60
94
  // ---------------- 2. JSON Schema(由 Zod 自动派生) ----------------
61
95
  const parameters = toToolParameters(inputSchema);
@@ -65,9 +99,62 @@ const description = `Searches the public web through Tavily and returns structur
65
99
  - It does not open or operate a browser. Use returned URLs with WebFetch when full source text is needed.
66
100
  - Results contain title, URL and a text snippet. They are discovery evidence, not a substitute for reading a high-value source in full.
67
101
  - Keep each query focused on one sub-question. When another search is needed, change the keywords, source, or angle instead of repeating the same query.
68
- - Add an explicit date or year only when recency matters; stable concepts and exact names should remain exact.
102
+ - Stable concepts and explicit historical queries remain unfiltered. Use recency="day" for today, and recency="current_year" for current/latest/this-year facts; current-year searches widen to the previous year only when the current-year result set is sparse. recency="auto" is a convenience classifier when the query still contains its temporal wording.
103
+ - Use recency="none" to explicitly disable automatic freshness, or start_date/end_date for an exact historical range.
69
104
  - \`search_depth: "advanced"\` is slower but can return a synthesized answer; \`topic: "news"\` favors news sources.
70
105
  - Requires a configured Tavily API key.`;
106
+ function localIsoDate(now) {
107
+ const parts = new Intl.DateTimeFormat('en-CA', {
108
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
109
+ year: 'numeric', month: '2-digit', day: '2-digit',
110
+ }).formatToParts(now);
111
+ const part = (type) => parts.find((item) => item.type === type)?.value ?? '';
112
+ return `${part('year')}-${part('month')}-${part('day')}`;
113
+ }
114
+ function resolveSearchWindow(input, now) {
115
+ if (input.start_date || input.end_date) {
116
+ return {
117
+ ...(input.start_date ? { startDate: input.start_date } : {}),
118
+ ...(input.end_date ? { endDate: input.end_date } : {}),
119
+ label: `${input.start_date ?? '最早'} 至 ${input.end_date ?? '今天'}`,
120
+ source: 'explicit',
121
+ };
122
+ }
123
+ const requested = input.recency ?? 'auto';
124
+ if (requested === 'none')
125
+ return { source: 'none' };
126
+ const today = localIsoDate(now);
127
+ const year = Number(today.slice(0, 4));
128
+ const makeCurrentYear = (source) => ({
129
+ startDate: `${year}-01-01`, endDate: today,
130
+ currentYearFallback: { expandedStartDate: `${year - 1}-01-01`, minimumResults: 3 },
131
+ label: `${year}-01-01 至 ${today}`,
132
+ source,
133
+ });
134
+ if (requested === 'current_year')
135
+ return makeCurrentYear('explicit');
136
+ const relativeLabel = (range) => ({
137
+ day: '最近一天', week: '最近一周', month: '最近一个月', year: '最近一年',
138
+ })[range];
139
+ if (requested !== 'auto')
140
+ return { timeRange: requested, label: relativeLabel(requested), source: 'explicit' };
141
+ const query = input.query.toLowerCase();
142
+ // An explicit past year means the user is asking about history; do not let a
143
+ // nearby word such as "current comparison" erase that requested period.
144
+ const explicitYears = [...query.matchAll(/(?:19|20)\d{2}/g)].map((match) => Number(match[0]));
145
+ if (explicitYears.some((value) => value !== year))
146
+ return { source: 'none' };
147
+ if (/(?:今天|今日|当天|\btoday\b)/i.test(query))
148
+ return { timeRange: 'day', label: relativeLabel('day'), source: 'auto' };
149
+ if (/(?:本周|这周|最近一周|\bthis week\b|\bpast week\b)/i.test(query))
150
+ return { timeRange: 'week', label: relativeLabel('week'), source: 'auto' };
151
+ if (/(?:本月|这个月|最近一个月|近期|\bthis month\b|\bpast month\b|\brecent(?:ly)?\b)/i.test(query))
152
+ return { timeRange: 'month', label: relativeLabel('month'), source: 'auto' };
153
+ if (/(?:今年|本年|当前|目前|现任|最新|最新版|实时|截至现在|\bthis year\b|\bcurrent\b|\blatest\b|\bnewest\b|\bup[- ]to[- ]date\b)/i.test(query)) {
154
+ return makeCurrentYear('auto');
155
+ }
156
+ return { source: 'none' };
157
+ }
71
158
  // ---------------- 4b. 退避重试 ----------------
72
159
  //
73
160
  // 为什么需要(与单发 fetch 零重试的旧行为对比):WebSearch 是 isConcurrencySafe 工具,
@@ -180,7 +267,7 @@ async function fetchTavilyWithRetry(body, signal) {
180
267
  };
181
268
  }
182
269
  // ---------------- 5. call() ----------------
183
- async function call(input, signal, getApiKey = async () => (await configService.tool('webSearch'))?.apiKey) {
270
+ async function call(input, signal, getApiKey = async () => (await configService.tool('webSearch'))?.apiKey, now = () => new Date()) {
184
271
  // 5a. 取 key
185
272
  const apiKey = await getApiKey();
186
273
  if (!apiKey) {
@@ -190,7 +277,8 @@ async function call(input, signal, getApiKey = async () => (await configService.
190
277
  '请在 KakadeAI 设置 → 工具 → 联网搜索中配置,或在 env 模式提供 TAVILY_API_KEY。',
191
278
  };
192
279
  }
193
- const body = {
280
+ const window = resolveSearchWindow(input, now());
281
+ const baseBody = {
194
282
  api_key: apiKey,
195
283
  // Preserve the exact research query. The prompt layer adds a date only
196
284
  // when recency matters; unconditional mutation hurts exact names,
@@ -202,21 +290,53 @@ async function call(input, signal, getApiKey = async () => (await configService.
202
290
  // 让 advanced 模式自动给 answer;basic 不会有
203
291
  include_answer: input.search_depth === 'advanced',
204
292
  };
293
+ const buildBody = (selected) => ({
294
+ ...baseBody,
295
+ ...(selected.timeRange ? { time_range: selected.timeRange } : {}),
296
+ ...(selected.startDate ? { start_date: selected.startDate } : {}),
297
+ ...(selected.endDate ? { end_date: selected.endDate } : {}),
298
+ });
205
299
  // 5c. 发请求(带退避重试,吸收 dev/免费 key 在并发突发下的 socket 切断 + 429/5xx)
206
- const fetched = await fetchTavilyWithRetry(body, signal);
300
+ const fetched = await fetchTavilyWithRetry(buildBody(window), signal);
207
301
  if (!fetched.ok)
208
302
  return { ok: false, error: fetched.error };
209
- const data = fetched.data;
303
+ let data = fetched.data;
304
+ let effectiveWindow = window;
305
+ let fallbackNote = '';
306
+ const fallback = window.currentYearFallback;
307
+ const minimumResults = Math.min(fallback?.minimumResults ?? 0, input.max_results ?? 5);
308
+ if (fallback && (data.results?.length ?? 0) < minimumResults) {
309
+ const expanded = {
310
+ ...window,
311
+ startDate: fallback.expandedStartDate,
312
+ label: `${fallback.expandedStartDate} 至 ${window.endDate}`,
313
+ };
314
+ const wider = await fetchTavilyWithRetry(buildBody(expanded), signal);
315
+ if (wider.ok) {
316
+ data = wider.data;
317
+ effectiveWindow = expanded;
318
+ fallbackNote = `今年结果不足 ${minimumResults} 条,已自动扩展到上一年。`;
319
+ }
320
+ else if ((data.results?.length ?? 0) === 0) {
321
+ return { ok: false, error: wider.error };
322
+ }
323
+ else {
324
+ fallbackNote = `今年结果不足 ${minimumResults} 条;扩展到上一年的检索失败,以下保留今年结果。`;
325
+ }
326
+ }
210
327
  // 5d. 取结果
211
328
  const results = data.results ?? [];
212
329
  if (results.length === 0) {
213
330
  return {
214
331
  ok: true,
215
- content: `(no results for "${input.query}")`,
332
+ content: `${effectiveWindow.label ? `【检索时间范围】${effectiveWindow.label}\n` : ''}(no results for "${input.query}")`,
216
333
  };
217
334
  }
218
335
  // 5e. 拼输出
219
336
  const parts = [];
337
+ if (effectiveWindow.label) {
338
+ parts.push(`【检索时间范围】${effectiveWindow.label}${fallbackNote ? `;${fallbackNote}` : ''}`);
339
+ }
220
340
  if (data.answer) {
221
341
  parts.push(`【综合回答】\n${data.answer}\n`);
222
342
  }
@@ -234,12 +354,13 @@ async function call(input, signal, getApiKey = async () => (await configService.
234
354
  return { ok: true, content };
235
355
  }
236
356
  // ---------------- 6. 导出 ----------------
237
- export function createWebSearchTool(getApiKey = async () => (await configService.tool('webSearch'))?.apiKey) {
357
+ export function createWebSearchTool(getApiKey = async () => (await configService.tool('webSearch'))?.apiKey, now = () => new Date()) {
238
358
  return {
239
359
  name: 'WebSearch', description, inputSchema, parameters, isReadOnly: true,
240
360
  isConcurrencySafe: true, maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
241
361
  interruptBehavior: () => 'cancel',
242
- call: (input, signal) => call(input, signal, getApiKey),
362
+ call: (input, signal) => call(input, signal, getApiKey, now),
243
363
  };
244
364
  }
245
365
  export const webSearchTool = createWebSearchTool();
366
+ export { resolveSearchWindow as _resolveSearchWindow };
@@ -21,6 +21,9 @@
21
21
  * max_results 可选,默认 5(Tavily 上限 20)
22
22
  * search_depth 可选 'basic' | 'advanced',默认 basic
23
23
  * topic 可选 'general' | 'news',默认 general
24
+ * recency 可选自动/相对/本年时间窗口
25
+ * start_date 可选 YYYY-MM-DD 绝对起始日期
26
+ * end_date 可选 YYYY-MM-DD 绝对结束日期
24
27
  *
25
28
  * 输出:
26
29
  * 每条结果一段:
@@ -39,6 +42,17 @@ import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
39
42
  import { toToolParameters } from '../../utils/zodToJson.js';
40
43
 
41
44
  // ---------------- 1. Zod 输入 schema ----------------
45
+ const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
46
+
47
+ function isValidIsoDate(value: string): boolean {
48
+ if (!ISO_DATE.test(value)) return false;
49
+ const [year, month, day] = value.split('-').map(Number);
50
+ const date = new Date(Date.UTC(year!, month! - 1, day));
51
+ return date.getUTCFullYear() === year
52
+ && date.getUTCMonth() === month! - 1
53
+ && date.getUTCDate() === day;
54
+ }
55
+
42
56
  const inputSchema = z.object({
43
57
  query: z
44
58
  .string()
@@ -60,6 +74,27 @@ const inputSchema = z.object({
60
74
  .enum(['general', 'news'])
61
75
  .optional()
62
76
  .describe('general=通用网页;news=偏新闻源;默认 general'),
77
+ recency: z
78
+ .enum(['auto', 'none', 'day', 'week', 'month', 'year', 'current_year'])
79
+ .optional()
80
+ .describe('时效范围:auto 根据查询识别;none 不限时间;day/week/month/year 为相对窗口;current_year 今年优先且结果不足时扩展到去年'),
81
+ start_date: z
82
+ .string()
83
+ .refine(isValidIsoDate, 'start_date 必须是有效的 YYYY-MM-DD 日期')
84
+ .optional()
85
+ .describe('只返回该日期之后发布或更新的结果;与 end_date 配合使用'),
86
+ end_date: z
87
+ .string()
88
+ .refine(isValidIsoDate, 'end_date 必须是有效的 YYYY-MM-DD 日期')
89
+ .optional()
90
+ .describe('只返回该日期之前发布或更新的结果;与 start_date 配合使用'),
91
+ }).superRefine((input, ctx) => {
92
+ if (input.start_date && input.end_date && input.start_date > input.end_date) {
93
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['end_date'], message: 'end_date 不能早于 start_date' });
94
+ }
95
+ if ((input.start_date || input.end_date) && input.recency && !['auto', 'none'].includes(input.recency)) {
96
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['recency'], message: '绝对日期范围与相对 recency 不能同时使用' });
97
+ }
63
98
  });
64
99
  type WebSearchInput = z.infer<typeof inputSchema>;
65
100
 
@@ -72,7 +107,8 @@ const description = `Searches the public web through Tavily and returns structur
72
107
  - It does not open or operate a browser. Use returned URLs with WebFetch when full source text is needed.
73
108
  - Results contain title, URL and a text snippet. They are discovery evidence, not a substitute for reading a high-value source in full.
74
109
  - Keep each query focused on one sub-question. When another search is needed, change the keywords, source, or angle instead of repeating the same query.
75
- - Add an explicit date or year only when recency matters; stable concepts and exact names should remain exact.
110
+ - Stable concepts and explicit historical queries remain unfiltered. Use recency="day" for today, and recency="current_year" for current/latest/this-year facts; current-year searches widen to the previous year only when the current-year result set is sparse. recency="auto" is a convenience classifier when the query still contains its temporal wording.
111
+ - Use recency="none" to explicitly disable automatic freshness, or start_date/end_date for an exact historical range.
76
112
  - \`search_depth: "advanced"\` is slower but can return a synthesized answer; \`topic: "news"\` favors news sources.
77
113
  - Requires a configured Tavily API key.`;
78
114
 
@@ -90,6 +126,65 @@ interface TavilyResponse {
90
126
  results?: TavilyResult[];
91
127
  }
92
128
 
129
+ type RelativeRange = 'day' | 'week' | 'month' | 'year';
130
+ type SearchWindow = {
131
+ timeRange?: RelativeRange;
132
+ startDate?: string;
133
+ endDate?: string;
134
+ currentYearFallback?: { expandedStartDate: string; minimumResults: number };
135
+ label?: string;
136
+ source: 'none' | 'auto' | 'explicit';
137
+ };
138
+
139
+ function localIsoDate(now: Date): string {
140
+ const parts = new Intl.DateTimeFormat('en-CA', {
141
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
142
+ year: 'numeric', month: '2-digit', day: '2-digit',
143
+ }).formatToParts(now);
144
+ const part = (type: Intl.DateTimeFormatPartTypes): string =>
145
+ parts.find((item) => item.type === type)?.value ?? '';
146
+ return `${part('year')}-${part('month')}-${part('day')}`;
147
+ }
148
+
149
+ function resolveSearchWindow(input: WebSearchInput, now: Date): SearchWindow {
150
+ if (input.start_date || input.end_date) {
151
+ return {
152
+ ...(input.start_date ? { startDate: input.start_date } : {}),
153
+ ...(input.end_date ? { endDate: input.end_date } : {}),
154
+ label: `${input.start_date ?? '最早'} 至 ${input.end_date ?? '今天'}`,
155
+ source: 'explicit',
156
+ };
157
+ }
158
+ const requested = input.recency ?? 'auto';
159
+ if (requested === 'none') return { source: 'none' };
160
+ const today = localIsoDate(now);
161
+ const year = Number(today.slice(0, 4));
162
+ const makeCurrentYear = (source: SearchWindow['source']): SearchWindow => ({
163
+ startDate: `${year}-01-01`, endDate: today,
164
+ currentYearFallback: { expandedStartDate: `${year - 1}-01-01`, minimumResults: 3 },
165
+ label: `${year}-01-01 至 ${today}`,
166
+ source,
167
+ });
168
+ if (requested === 'current_year') return makeCurrentYear('explicit');
169
+ const relativeLabel = (range: RelativeRange): string => ({
170
+ day: '最近一天', week: '最近一周', month: '最近一个月', year: '最近一年',
171
+ })[range];
172
+ if (requested !== 'auto') return { timeRange: requested, label: relativeLabel(requested), source: 'explicit' };
173
+
174
+ const query = input.query.toLowerCase();
175
+ // An explicit past year means the user is asking about history; do not let a
176
+ // nearby word such as "current comparison" erase that requested period.
177
+ const explicitYears = [...query.matchAll(/(?:19|20)\d{2}/g)].map((match) => Number(match[0]));
178
+ if (explicitYears.some((value) => value !== year)) return { source: 'none' };
179
+ if (/(?:今天|今日|当天|\btoday\b)/i.test(query)) return { timeRange: 'day', label: relativeLabel('day'), source: 'auto' };
180
+ if (/(?:本周|这周|最近一周|\bthis week\b|\bpast week\b)/i.test(query)) return { timeRange: 'week', label: relativeLabel('week'), source: 'auto' };
181
+ if (/(?:本月|这个月|最近一个月|近期|\bthis month\b|\bpast month\b|\brecent(?:ly)?\b)/i.test(query)) return { timeRange: 'month', label: relativeLabel('month'), source: 'auto' };
182
+ if (/(?:今年|本年|当前|目前|现任|最新|最新版|实时|截至现在|\bthis year\b|\bcurrent\b|\blatest\b|\bnewest\b|\bup[- ]to[- ]date\b)/i.test(query)) {
183
+ return makeCurrentYear('auto');
184
+ }
185
+ return { source: 'none' };
186
+ }
187
+
93
188
  // ---------------- 4b. 退避重试 ----------------
94
189
  //
95
190
  // 为什么需要(与单发 fetch 零重试的旧行为对比):WebSearch 是 isConcurrencySafe 工具,
@@ -215,6 +310,7 @@ async function call(
215
310
  input: WebSearchInput,
216
311
  signal?: AbortSignal,
217
312
  getApiKey: () => Promise<string | undefined> = async () => (await configService.tool('webSearch'))?.apiKey,
313
+ now: () => Date = () => new Date(),
218
314
  ): Promise<ToolResult> {
219
315
  // 5a. 取 key
220
316
  const apiKey = await getApiKey();
@@ -227,7 +323,8 @@ async function call(
227
323
  };
228
324
  }
229
325
 
230
- const body = {
326
+ const window = resolveSearchWindow(input, now());
327
+ const baseBody = {
231
328
  api_key: apiKey,
232
329
  // Preserve the exact research query. The prompt layer adds a date only
233
330
  // when recency matters; unconditional mutation hurts exact names,
@@ -240,22 +337,54 @@ async function call(
240
337
  include_answer: input.search_depth === 'advanced',
241
338
  };
242
339
 
340
+ const buildBody = (selected: SearchWindow): Record<string, unknown> => ({
341
+ ...baseBody,
342
+ ...(selected.timeRange ? { time_range: selected.timeRange } : {}),
343
+ ...(selected.startDate ? { start_date: selected.startDate } : {}),
344
+ ...(selected.endDate ? { end_date: selected.endDate } : {}),
345
+ });
346
+
243
347
  // 5c. 发请求(带退避重试,吸收 dev/免费 key 在并发突发下的 socket 切断 + 429/5xx)
244
- const fetched = await fetchTavilyWithRetry(body, signal);
348
+ const fetched = await fetchTavilyWithRetry(buildBody(window), signal);
245
349
  if (!fetched.ok) return { ok: false, error: fetched.error };
246
- const data = fetched.data;
350
+ let data = fetched.data;
351
+ let effectiveWindow = window;
352
+ let fallbackNote = '';
353
+
354
+ const fallback = window.currentYearFallback;
355
+ const minimumResults = Math.min(fallback?.minimumResults ?? 0, input.max_results ?? 5);
356
+ if (fallback && (data.results?.length ?? 0) < minimumResults) {
357
+ const expanded: SearchWindow = {
358
+ ...window,
359
+ startDate: fallback.expandedStartDate,
360
+ label: `${fallback.expandedStartDate} 至 ${window.endDate}`,
361
+ };
362
+ const wider = await fetchTavilyWithRetry(buildBody(expanded), signal);
363
+ if (wider.ok) {
364
+ data = wider.data;
365
+ effectiveWindow = expanded;
366
+ fallbackNote = `今年结果不足 ${minimumResults} 条,已自动扩展到上一年。`;
367
+ } else if ((data.results?.length ?? 0) === 0) {
368
+ return { ok: false, error: wider.error };
369
+ } else {
370
+ fallbackNote = `今年结果不足 ${minimumResults} 条;扩展到上一年的检索失败,以下保留今年结果。`;
371
+ }
372
+ }
247
373
 
248
374
  // 5d. 取结果
249
375
  const results = data.results ?? [];
250
376
  if (results.length === 0) {
251
377
  return {
252
378
  ok: true,
253
- content: `(no results for "${input.query}")`,
379
+ content: `${effectiveWindow.label ? `【检索时间范围】${effectiveWindow.label}\n` : ''}(no results for "${input.query}")`,
254
380
  };
255
381
  }
256
382
 
257
383
  // 5e. 拼输出
258
384
  const parts: string[] = [];
385
+ if (effectiveWindow.label) {
386
+ parts.push(`【检索时间范围】${effectiveWindow.label}${fallbackNote ? `;${fallbackNote}` : ''}`);
387
+ }
259
388
  if (data.answer) {
260
389
  parts.push(`【综合回答】\n${data.answer}\n`);
261
390
  }
@@ -280,13 +409,16 @@ async function call(
280
409
  // ---------------- 6. 导出 ----------------
281
410
  export function createWebSearchTool(
282
411
  getApiKey: () => Promise<string | undefined> = async () => (await configService.tool('webSearch'))?.apiKey,
412
+ now: () => Date = () => new Date(),
283
413
  ): Tool<WebSearchInput> {
284
414
  return {
285
415
  name: 'WebSearch', description, inputSchema, parameters, isReadOnly: true,
286
416
  isConcurrencySafe: true, maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
287
417
  interruptBehavior: () => 'cancel',
288
- call: (input, signal) => call(input, signal, getApiKey),
418
+ call: (input, signal) => call(input, signal, getApiKey, now),
289
419
  };
290
420
  }
291
421
 
292
422
  export const webSearchTool = createWebSearchTool();
423
+
424
+ export { resolveSearchWindow as _resolveSearchWindow };