minimal-agent 0.18.13 → 0.18.14

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 (174) hide show
  1. package/package.json +1 -3
  2. package/plugins/workflow-runner/src/runtime/context.js +1 -1
  3. package/plugins/workflow-runner/src/runtime/context.ts +1 -1
  4. package/plugins/workflow-runner/test/embeddedExecution.test.ts +2 -5
  5. package/plugins/workflow-runner/test/execLifetime.test.ts +15 -2
  6. package/skills/ssh-remote-dev/SKILL.md +61 -0
  7. package/skills/ssh-remote-dev/agents/openai.yaml +4 -0
  8. package/src/advisor/README.md +62 -24
  9. package/src/advisor/advisorNudge.js +199 -0
  10. package/src/advisor/advisorNudge.ts +232 -0
  11. package/src/advisor/deliveryReview.js +35 -12
  12. package/src/advisor/deliveryReview.ts +35 -11
  13. package/src/advisor/presentation.js +7 -10
  14. package/src/advisor/presentation.ts +10 -13
  15. package/src/advisor/reviewContext.js +22 -58
  16. package/src/advisor/reviewContext.ts +24 -67
  17. package/src/cli/configMenu.js +17 -128
  18. package/src/cli/configMenu.tsx +17 -193
  19. package/src/cli/print.js +2 -0
  20. package/src/cli/print.ts +2 -0
  21. package/src/cli/streamJson.js +2 -0
  22. package/src/cli/streamJson.ts +2 -0
  23. package/src/cli/wizards/advisorWizard.js +9 -7
  24. package/src/cli/wizards/advisorWizard.tsx +9 -7
  25. package/src/cli/wizards/contextAdvisorWizard.js +9 -7
  26. package/src/cli/wizards/contextAdvisorWizard.tsx +9 -7
  27. package/src/cli/wizards/providerPresets.js +27 -1
  28. package/src/cli/wizards/providerPresets.ts +44 -2
  29. package/src/cli/wizards/providerWizard.js +51 -10
  30. package/src/cli/wizards/providerWizard.tsx +59 -9
  31. package/src/config/configDefaults.js +1 -1
  32. package/src/config/configDefaults.ts +1 -1
  33. package/src/config/configDiagnostics.js +1 -21
  34. package/src/config/configDiagnostics.ts +3 -23
  35. package/src/config/configFile.js +11 -4
  36. package/src/config/configFile.ts +27 -7
  37. package/src/config/configManagement.js +1 -0
  38. package/src/config/configManagement.ts +2 -0
  39. package/src/config/configService.js +12 -8
  40. package/src/config/configService.ts +16 -11
  41. package/src/config/numericLimits.js +0 -4
  42. package/src/config/numericLimits.ts +0 -4
  43. package/src/config/reasoningEffort.js +16 -0
  44. package/src/config/reasoningEffort.ts +18 -0
  45. package/src/context/budgetPlan.js +1 -1
  46. package/src/context/budgetPlan.ts +1 -1
  47. package/src/context/optimizeConversation.js +1 -1
  48. package/src/context/optimizeConversation.ts +1 -1
  49. package/src/harness/stallGuard.js +8 -13
  50. package/src/harness/stallGuard.ts +8 -12
  51. package/src/llm/client.js +64 -17
  52. package/src/llm/client.ts +62 -7
  53. package/src/llm/providers/openaiFormat.js +14 -3
  54. package/src/llm/providers/openaiFormat.ts +17 -3
  55. package/src/llm/providers/responsesFormat.js +275 -0
  56. package/src/llm/providers/responsesFormat.ts +306 -0
  57. package/src/loop/README.md +18 -3
  58. package/src/loop/liveDiagramGate.js +63 -0
  59. package/src/loop/liveDiagramGate.ts +61 -0
  60. package/src/loop/messages.js +12 -0
  61. package/src/loop/messages.ts +13 -0
  62. package/src/loop/options.ts +7 -2
  63. package/src/loop/toolBatch.js +0 -1
  64. package/src/loop/toolBatch.ts +0 -1
  65. package/src/loop/toolExecutor.js +11 -46
  66. package/src/loop/toolExecutor.ts +12 -55
  67. package/src/loop/toolPresentation.js +2 -13
  68. package/src/loop/toolPresentation.ts +2 -13
  69. package/src/loop/toolSemantics.js +3 -4
  70. package/src/loop/toolSemantics.ts +4 -6
  71. package/src/loop.js +222 -214
  72. package/src/loop.ts +226 -232
  73. package/src/memory/dependencies.js +11 -3
  74. package/src/memory/dependencies.ts +11 -3
  75. package/src/memory/episodicMemory.js +59 -18
  76. package/src/memory/episodicMemory.ts +58 -18
  77. package/src/memory/experienceStore.js +4 -3
  78. package/src/memory/experienceStore.ts +4 -3
  79. package/src/memory/factCandidates.js +53 -1
  80. package/src/memory/factCandidates.ts +54 -1
  81. package/src/memory/factLearning.js +2 -2
  82. package/src/memory/factLearning.ts +2 -2
  83. package/src/memory/jobPolicy.js +24 -5
  84. package/src/memory/jobPolicy.ts +25 -5
  85. package/src/memory/learning.js +2 -2
  86. package/src/memory/learning.ts +2 -2
  87. package/src/memory/learningModel.js +7 -0
  88. package/src/memory/learningModel.ts +7 -0
  89. package/src/memory/managementService.js +8 -7
  90. package/src/memory/managementService.ts +16 -8
  91. package/src/memory/memoryService.js +104 -33
  92. package/src/memory/memoryService.ts +132 -28
  93. package/src/memory/projectKnowledge.js +39 -3
  94. package/src/memory/projectKnowledge.ts +45 -3
  95. package/src/memory/recallQuery.js +56 -0
  96. package/src/memory/recallQuery.ts +58 -0
  97. package/src/memory/retrieval.js +39 -10
  98. package/src/memory/retrieval.ts +46 -11
  99. package/src/memory/turnJournal.js +75 -10
  100. package/src/memory/turnJournal.ts +66 -10
  101. package/src/memory/types.ts +7 -1
  102. package/src/prompts/delegation.js +2 -1
  103. package/src/prompts/delegation.ts +3 -1
  104. package/src/prompts/policyRegistry.js +9 -12
  105. package/src/prompts/policyRegistry.ts +9 -12
  106. package/src/prompts/promptAssembly.js +6 -5
  107. package/src/prompts/promptAssembly.ts +8 -6
  108. package/src/prompts/visualPresentation.js +39 -10
  109. package/src/prompts/visualPresentation.ts +38 -9
  110. package/src/runtime/answerPreparation.js +1 -1
  111. package/src/runtime/answerPreparation.ts +1 -1
  112. package/src/runtime/fileLock.js +19 -3
  113. package/src/runtime/fileLock.ts +19 -3
  114. package/src/runtime/invocationPolicy.js +1 -1
  115. package/src/runtime/invocationPolicy.ts +1 -1
  116. package/src/runtime/outputContract.js +0 -4
  117. package/src/runtime/outputContract.ts +0 -7
  118. package/src/session/runAgentTurn.js +3 -0
  119. package/src/session/runAgentTurn.ts +3 -0
  120. package/src/team/onlineToolContract.js +0 -1
  121. package/src/team/onlineToolContract.ts +0 -1
  122. package/src/tools/advisor/advisor.js +207 -365
  123. package/src/tools/advisor/advisor.ts +211 -383
  124. package/src/tools/agent/agentTypes.js +0 -1
  125. package/src/tools/agent/agentTypes.ts +0 -1
  126. package/src/tools/agent/coordinator.js +4 -1
  127. package/src/tools/agent/coordinator.ts +4 -1
  128. package/src/tools/bash/semantics.js +4 -5
  129. package/src/tools/bash/semantics.ts +4 -5
  130. package/src/tools/capabilities.js +2 -3
  131. package/src/tools/capabilities.ts +2 -4
  132. package/src/tools/index.js +0 -16
  133. package/src/tools/index.ts +0 -16
  134. package/src/tools/memory/maintenance.js +8 -9
  135. package/src/tools/memory/maintenance.ts +13 -11
  136. package/src/tools/memory/memory.js +5 -1
  137. package/src/tools/memory/memory.ts +5 -0
  138. package/src/tools/optimizeConversation/README.md +4 -6
  139. package/src/tools/toolPromptGuides.js +2 -9
  140. package/src/tools/toolPromptGuides.ts +2 -9
  141. package/src/types.ts +28 -105
  142. package/src/ui/App.js +2 -0
  143. package/src/ui/App.tsx +1 -0
  144. package/src/ui/MessageList.js +8 -44
  145. package/src/ui/MessageList.tsx +3 -81
  146. package/src/ui/hooks/useChat.js +2 -0
  147. package/src/ui/hooks/useChat.ts +2 -0
  148. package/src/ui/toolProgress.js +1 -1
  149. package/src/ui/toolProgress.ts +1 -1
  150. package/src/web/protocol.ts +10 -3
  151. package/src/advisor/advisorCoordinator.js +0 -734
  152. package/src/advisor/advisorCoordinator.ts +0 -825
  153. package/src/cli/wizards/sshHostWizard.js +0 -156
  154. package/src/cli/wizards/sshHostWizard.tsx +0 -214
  155. package/src/context/sshHosts.js +0 -290
  156. package/src/context/sshHosts.ts +0 -312
  157. package/src/loop/publication.js +0 -94
  158. package/src/loop/publication.ts +0 -124
  159. package/src/runtime/finalAnswer.js +0 -9
  160. package/src/runtime/finalAnswer.ts +0 -13
  161. package/src/tools/advisor/advisorDecision.js +0 -79
  162. package/src/tools/advisor/advisorDecision.ts +0 -92
  163. package/src/tools/ssh/ssh.js +0 -152
  164. package/src/tools/ssh/ssh.ts +0 -167
  165. package/src/tools/ssh/sshAvailability.js +0 -35
  166. package/src/tools/ssh/sshAvailability.ts +0 -39
  167. package/src/tools/ssh/sshClient.js +0 -177
  168. package/src/tools/ssh/sshClient.ts +0 -189
  169. package/src/tools/ssh/sshDownload.js +0 -77
  170. package/src/tools/ssh/sshDownload.ts +0 -92
  171. package/src/tools/ssh/sshHostsTool.js +0 -36
  172. package/src/tools/ssh/sshHostsTool.ts +0 -48
  173. package/src/tools/ssh/sshUpload.js +0 -72
  174. package/src/tools/ssh/sshUpload.ts +0 -85
@@ -28,7 +28,6 @@ export const SUBAGENT_EXCLUDED_TOOLS = [
28
28
  'AgentFollowup',
29
29
  'AgentResolve',
30
30
  'Advisor',
31
- 'AdvisorDecision',
32
31
  // 子任务只向主 Agent 汇报;正式用户交付由主 Agent 统一收口,避免重复结果卡。
33
32
  'PresentResult',
34
33
  'RememberMemory',
@@ -46,7 +46,6 @@ export const SUBAGENT_EXCLUDED_TOOLS: readonly string[] = [
46
46
  'AgentFollowup',
47
47
  'AgentResolve',
48
48
  'Advisor',
49
- 'AdvisorDecision',
50
49
  // 子任务只向主 Agent 汇报;正式用户交付由主 Agent 统一收口,避免重复结果卡。
51
50
  'PresentResult',
52
51
  'RememberMemory',
@@ -1,5 +1,6 @@
1
1
  import { realpath } from 'node:fs/promises';
2
2
  import { isAbsolute, relative, resolve, sep } from 'node:path';
3
+ import { CONFIG_LIMITS } from '../../config/numericLimits.js';
3
4
  const active = [];
4
5
  const waiters = [];
5
6
  let running = 0;
@@ -87,7 +88,9 @@ export async function normalizeWriteScopes(cwd, rawScopes) {
87
88
  return [...normalized].sort();
88
89
  }
89
90
  export async function acquireSubagentLease(cwd, scopes, maxConcurrent = 3, options = {}) {
90
- const safeMax = Math.max(1, Math.min(8, maxConcurrent));
91
+ // The configured ceiling is the only bound (numericLimits.ts); a second
92
+ // hard-coded cap silently ignored values the settings page accepts.
93
+ const safeMax = Math.max(1, Math.min(CONFIG_LIMITS.subagentMaxConcurrent.max, maxConcurrent));
91
94
  return new Promise((resolveLease, reject) => {
92
95
  if (options.signal?.aborted)
93
96
  return reject(new DOMException('Aborted', 'AbortError'));
@@ -1,5 +1,6 @@
1
1
  import { realpath } from 'node:fs/promises';
2
2
  import { isAbsolute, relative, resolve, sep } from 'node:path';
3
+ import { CONFIG_LIMITS } from '../../config/numericLimits.js';
3
4
 
4
5
  interface Waiter {
5
6
  owner: string;
@@ -104,7 +105,9 @@ export async function acquireSubagentLease(
104
105
  maxConcurrent = 3,
105
106
  options: { signal?: AbortSignal; onStatus?: (status: LeaseStatus) => void; owner?: string } = {},
106
107
  ): Promise<() => void> {
107
- const safeMax = Math.max(1, Math.min(8, maxConcurrent));
108
+ // The configured ceiling is the only bound (numericLimits.ts); a second
109
+ // hard-coded cap silently ignored values the settings page accepts.
110
+ const safeMax = Math.max(1, Math.min(CONFIG_LIMITS.subagentMaxConcurrent.max, maxConcurrent));
108
111
  return new Promise((resolveLease, reject) => {
109
112
  if (options.signal?.aborted) return reject(new DOMException('Aborted', 'AbortError'));
110
113
  const waiter: Waiter = { owner: options.owner ?? cwd, cwd, scopes, maxConcurrent: safeMax, onStatus: options.onStatus, signal: options.signal, resolve: resolveLease, reject };
@@ -200,11 +200,10 @@ export function isReadOnlyShellCommand(command) {
200
200
  * Advisor 专用信号,别处不要复用:命令是否只是"检查现状"(跑测试/构建/lint/
201
201
  * 类型检查),而不是开始实施改动。跟 isReadOnlyShellCommand 是两个不同的问题——
202
202
  * 后者要回答"能不能安全并行/算不算并发写",这类命令往往会写构建产物/缓存/
203
- * 日志,答案本该是 false,改不得;但 advisorCoordinator 拿 isReadOnlyShellCommand
204
- * 的结果去判定"这是不是本任务版本的首次实质写入"时,会把纯验证型命令
205
- * (如 `cd frontend && npm run build` 核对现状)误判成"开始写代码",白白
206
- * 烧掉本该留给真正改动的那次检查点。真实事故:一次只读验证的 `npm run build`
207
- * 直接把 pre-execution 检查点触发了。
203
+ * 日志,答案本该是 false,改不得;但顾问提醒(advisorNudge)拿 isReadOnlyShellCommand
204
+ * 的结果去判定"这是不是开始实施改动"时,会把纯验证型命令
205
+ * (如 `cd frontend && npm run build` 核对现状)误判成"开始写代码",
206
+ * 于是过早提醒"动手前先咨询"。
208
207
  *
209
208
  * 宁可漏判(仍照旧触发一次检查点,是现状,不算回退)也不误判(放过真正的写):
210
209
  * 每个分段要么落在 isReadOnlyShellCommand 的白名单里,要么命中下面这份
@@ -216,11 +216,10 @@ export function isReadOnlyShellCommand(command: string): boolean {
216
216
  * Advisor 专用信号,别处不要复用:命令是否只是"检查现状"(跑测试/构建/lint/
217
217
  * 类型检查),而不是开始实施改动。跟 isReadOnlyShellCommand 是两个不同的问题——
218
218
  * 后者要回答"能不能安全并行/算不算并发写",这类命令往往会写构建产物/缓存/
219
- * 日志,答案本该是 false,改不得;但 advisorCoordinator 拿 isReadOnlyShellCommand
220
- * 的结果去判定"这是不是本任务版本的首次实质写入"时,会把纯验证型命令
221
- * (如 `cd frontend && npm run build` 核对现状)误判成"开始写代码",白白
222
- * 烧掉本该留给真正改动的那次检查点。真实事故:一次只读验证的 `npm run build`
223
- * 直接把 pre-execution 检查点触发了。
219
+ * 日志,答案本该是 false,改不得;但顾问提醒(advisorNudge)拿 isReadOnlyShellCommand
220
+ * 的结果去判定"这是不是开始实施改动"时,会把纯验证型命令
221
+ * (如 `cd frontend && npm run build` 核对现状)误判成"开始写代码",
222
+ * 于是过早提醒"动手前先咨询"。
224
223
  *
225
224
  * 宁可漏判(仍照旧触发一次检查点,是现状,不算回退)也不误判(放过真正的写):
226
225
  * 每个分段要么落在 isReadOnlyShellCommand 的白名单里,要么命中下面这份
@@ -4,7 +4,6 @@ const TOOL_CAPABILITIES = Object.freeze({
4
4
  Edit: 'files.write', MultiEdit: 'files.write', Write: 'files.write', ApplyPatch: 'files.write',
5
5
  Bash: 'shell',
6
6
  PowerShell: 'shell', TaskOutput: 'background.process', TaskStop: 'background.process',
7
- SSH: 'shell.remote', SSHUpload: 'shell.remote', SSHDownload: 'shell.remote', SSHHosts: 'shell.remote',
8
7
  Trash: 'files.trash',
9
8
  TaskCreate: 'task.management', TaskGet: 'task.management', TaskUpdate: 'task.management', TaskList: 'task.management',
10
9
  Skill: 'skill.invoke', SearchSkills: 'skill.invoke', EnterWorktree: 'worktree.session', ExitWorktree: 'worktree.session',
@@ -12,7 +11,7 @@ const TOOL_CAPABILITIES = Object.freeze({
12
11
  LSP: 'code.intelligence', NotebookEdit: 'files.write',
13
12
  WebSearch: 'web.search', WebFetch: 'web.fetch', WebBrowser: 'web.browser', BrowserBatch: 'web.browser', BrowserCDP: 'web.browser',
14
13
  Download: 'network.download',
15
- ComputerUse: 'computer.use', AskUserQuestion: 'ask', Advisor: 'advisor', AdvisorDecision: 'advisor',
14
+ ComputerUse: 'computer.use', AskUserQuestion: 'ask', Advisor: 'advisor',
16
15
  Agent: 'subagent', AgentMessage: 'subagent', AgentList: 'subagent', AgentWait: 'subagent',
17
16
  AgentInterrupt: 'subagent', AgentFollowup: 'subagent', AgentReport: 'subagent', AgentResolve: 'subagent',
18
17
  PresentResult: 'delivery', GenerateImage: 'media', GenerateSpeech: 'media',
@@ -27,7 +26,7 @@ const CORE_TOOLS = new Set([
27
26
  'Read', 'Glob', 'Grep', 'Edit', 'MultiEdit', 'Write', 'ApplyPatch', 'NotebookEdit', 'Bash',
28
27
  ]);
29
28
  const AUXILIARY_TOOLS = new Set([
30
- 'Advisor', 'AdvisorDecision', 'Agent', 'AgentMessage', 'AgentList',
29
+ 'Advisor', 'Agent', 'AgentMessage', 'AgentList',
31
30
  'AgentWait', 'AgentInterrupt', 'AgentFollowup', 'OptimizeConversation',
32
31
  ]);
33
32
  export function budgetClassForToolName(name) {
@@ -20,7 +20,6 @@ export type CapabilityId =
20
20
  | 'skill.invoke'
21
21
  | 'worktree.session'
22
22
  | 'terminal.capture'
23
- | 'shell.remote'
24
23
  | 'context.optimize';
25
24
 
26
25
  export type ToolBudgetClass = 'core' | 'task' | 'auxiliary';
@@ -31,7 +30,6 @@ const TOOL_CAPABILITIES: Readonly<Record<string, CapabilityId>> = Object.freeze(
31
30
  Edit: 'files.write', MultiEdit: 'files.write', Write: 'files.write', ApplyPatch: 'files.write',
32
31
  Bash: 'shell',
33
32
  PowerShell: 'shell', TaskOutput: 'background.process', TaskStop: 'background.process',
34
- SSH: 'shell.remote', SSHUpload: 'shell.remote', SSHDownload: 'shell.remote', SSHHosts: 'shell.remote',
35
33
  Trash: 'files.trash',
36
34
  TaskCreate: 'task.management', TaskGet: 'task.management', TaskUpdate: 'task.management', TaskList: 'task.management',
37
35
  Skill: 'skill.invoke', SearchSkills: 'skill.invoke', EnterWorktree: 'worktree.session', ExitWorktree: 'worktree.session',
@@ -39,7 +37,7 @@ const TOOL_CAPABILITIES: Readonly<Record<string, CapabilityId>> = Object.freeze(
39
37
  LSP: 'code.intelligence', NotebookEdit: 'files.write',
40
38
  WebSearch: 'web.search', WebFetch: 'web.fetch', WebBrowser: 'web.browser', BrowserBatch: 'web.browser', BrowserCDP: 'web.browser',
41
39
  Download: 'network.download',
42
- ComputerUse: 'computer.use', AskUserQuestion: 'ask', Advisor: 'advisor', AdvisorDecision: 'advisor',
40
+ ComputerUse: 'computer.use', AskUserQuestion: 'ask', Advisor: 'advisor',
43
41
  Agent: 'subagent', AgentMessage: 'subagent', AgentList: 'subagent', AgentWait: 'subagent',
44
42
  AgentInterrupt: 'subagent', AgentFollowup: 'subagent', AgentReport: 'subagent', AgentResolve: 'subagent',
45
43
  PresentResult: 'delivery', GenerateImage: 'media', GenerateSpeech: 'media',
@@ -55,7 +53,7 @@ const CORE_TOOLS = new Set([
55
53
  'Read', 'Glob', 'Grep', 'Edit', 'MultiEdit', 'Write', 'ApplyPatch', 'NotebookEdit', 'Bash',
56
54
  ]);
57
55
  const AUXILIARY_TOOLS = new Set([
58
- 'Advisor', 'AdvisorDecision', 'Agent', 'AgentMessage', 'AgentList',
56
+ 'Advisor', 'Agent', 'AgentMessage', 'AgentList',
59
57
  'AgentWait', 'AgentInterrupt', 'AgentFollowup', 'OptimizeConversation',
60
58
  ]);
61
59
 
@@ -14,7 +14,6 @@
14
14
  */
15
15
  import { advisorTool } from './advisor/advisor.js';
16
16
  import { optimizeConversationTool } from './optimizeConversation/optimizeConversation.js';
17
- import { advisorDecisionTool } from './advisor/advisorDecision.js';
18
17
  import { applyPatchTool } from './applypatch/applyPatch.js';
19
18
  // ⚠️ agent.ts 与本模块构成环(tools/index → agent → loop → tools/index):
20
19
  // agent.ts 顶层不求值本模块/loop 的任何导出、loop.ts 的工具 token 估算已懒化,
@@ -42,10 +41,6 @@ import { presentResultTool } from './presentresult/presentresult.js';
42
41
  import { readTool } from './read/read.js';
43
42
  import { skillTool } from './skill/skill.js';
44
43
  import { searchSkillsTool } from './skill/searchSkills.js';
45
- import { sshTool } from './ssh/ssh.js';
46
- import { sshUploadTool } from './ssh/sshUpload.js';
47
- import { sshDownloadTool } from './ssh/sshDownload.js';
48
- import { sshHostsTool } from './ssh/sshHostsTool.js';
49
44
  import { snipTool } from './snip/snip.js';
50
45
  import { taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, } from './tasks/taskManagement.js';
51
46
  import { taskOutputTool } from './tasks/taskOutput.js';
@@ -93,7 +88,6 @@ export const ALL_TOOLS = attachBuiltinPromptGuides([
93
88
  taskStopTool,
94
89
  askUserQuestionTool,
95
90
  advisorTool,
96
- advisorDecisionTool,
97
91
  computerUseTool,
98
92
  // 追加在末尾:主循环 tools schema 的原有前缀字节不动(提示词缓存友好)
99
93
  agentTool,
@@ -118,11 +112,6 @@ export const ALL_TOOLS = attachBuiltinPromptGuides([
118
112
  // Browser extensions append after the stable legacy schema prefix.
119
113
  browserBatchTool,
120
114
  browserCdpTool,
121
- // SSH tools append at the end for the same schema-prefix-cache reason as above.
122
- sshHostsTool,
123
- sshTool,
124
- sshUploadTool,
125
- sshDownloadTool,
126
115
  memoryMaintenanceTool,
127
116
  searchSkillsTool,
128
117
  optimizeConversationTool,
@@ -236,7 +225,6 @@ export { multiEditTool } from './edit/multi-edit.js';
236
225
  export { genImageTool } from './genimage/genimage.js';
237
226
  export { advisorTool } from './advisor/advisor.js';
238
227
  export { optimizeConversationTool } from './optimizeConversation/optimizeConversation.js';
239
- export { advisorDecisionTool } from './advisor/advisorDecision.js';
240
228
  export { applyPatchTool } from './applypatch/applyPatch.js';
241
229
  export { agentTool } from './agent/agent.js';
242
230
  export { agentResolveTool } from './agent/agentHandoff.js';
@@ -254,7 +242,3 @@ export { skillTool } from './skill/skill.js';
254
242
  export { snipTool } from './snip/snip.js';
255
243
  export { enterWorktreeTool, exitWorktreeTool, } from './worktree/sessionWorktree.js';
256
244
  export { terminalCaptureTool, installTerminalCapture, } from './terminal/terminalCapture.js';
257
- export { createSshTool, sshTool } from './ssh/ssh.js';
258
- export { createSshUploadTool, sshUploadTool } from './ssh/sshUpload.js';
259
- export { createSshDownloadTool, sshDownloadTool } from './ssh/sshDownload.js';
260
- export { createSshHostsTool, sshHostsTool } from './ssh/sshHostsTool.js';
@@ -16,7 +16,6 @@
16
16
  import type { Tool, ToolCallContext, ToolResult } from '../types.js';
17
17
  import { advisorTool } from './advisor/advisor.js';
18
18
  import { optimizeConversationTool } from './optimizeConversation/optimizeConversation.js';
19
- import { advisorDecisionTool } from './advisor/advisorDecision.js';
20
19
  import { applyPatchTool } from './applypatch/applyPatch.js';
21
20
  // ⚠️ agent.ts 与本模块构成环(tools/index → agent → loop → tools/index):
22
21
  // agent.ts 顶层不求值本模块/loop 的任何导出、loop.ts 的工具 token 估算已懒化,
@@ -61,10 +60,6 @@ import { presentResultTool } from './presentresult/presentresult.js';
61
60
  import { readTool } from './read/read.js';
62
61
  import { skillTool } from './skill/skill.js';
63
62
  import { searchSkillsTool } from './skill/searchSkills.js';
64
- import { sshTool } from './ssh/ssh.js';
65
- import { sshUploadTool } from './ssh/sshUpload.js';
66
- import { sshDownloadTool } from './ssh/sshDownload.js';
67
- import { sshHostsTool } from './ssh/sshHostsTool.js';
68
63
  import { snipTool } from './snip/snip.js';
69
64
  import {
70
65
  taskCreateTool,
@@ -121,7 +116,6 @@ export const ALL_TOOLS: Tool[] = attachBuiltinPromptGuides([
121
116
  taskStopTool,
122
117
  askUserQuestionTool,
123
118
  advisorTool,
124
- advisorDecisionTool,
125
119
  computerUseTool,
126
120
  // 追加在末尾:主循环 tools schema 的原有前缀字节不动(提示词缓存友好)
127
121
  agentTool,
@@ -146,11 +140,6 @@ export const ALL_TOOLS: Tool[] = attachBuiltinPromptGuides([
146
140
  // Browser extensions append after the stable legacy schema prefix.
147
141
  browserBatchTool,
148
142
  browserCdpTool,
149
- // SSH tools append at the end for the same schema-prefix-cache reason as above.
150
- sshHostsTool,
151
- sshTool,
152
- sshUploadTool,
153
- sshDownloadTool,
154
143
  memoryMaintenanceTool,
155
144
  searchSkillsTool,
156
145
  optimizeConversationTool,
@@ -307,7 +296,6 @@ export { multiEditTool } from './edit/multi-edit.js';
307
296
  export { genImageTool } from './genimage/genimage.js';
308
297
  export { advisorTool } from './advisor/advisor.js';
309
298
  export { optimizeConversationTool } from './optimizeConversation/optimizeConversation.js';
310
- export { advisorDecisionTool } from './advisor/advisorDecision.js';
311
299
  export { applyPatchTool } from './applypatch/applyPatch.js';
312
300
  export { agentTool } from './agent/agent.js';
313
301
  export { agentResolveTool } from './agent/agentHandoff.js';
@@ -345,7 +333,3 @@ export {
345
333
  terminalCaptureTool,
346
334
  installTerminalCapture,
347
335
  } from './terminal/terminalCapture.js';
348
- export { createSshTool, sshTool } from './ssh/ssh.js';
349
- export { createSshUploadTool, sshUploadTool } from './ssh/sshUpload.js';
350
- export { createSshDownloadTool, sshDownloadTool } from './ssh/sshDownload.js';
351
- export { createSshHostsTool, sshHostsTool } from './ssh/sshHostsTool.js';
@@ -1,16 +1,16 @@
1
1
  import { z } from 'zod';
2
- import { backgroundLearningHealth } from '../../memory/jobPolicy.js';
2
+ import { backgroundLearningHealth, isPausedJob } from '../../memory/jobPolicy.js';
3
3
  import { getWorkingDir } from '../../bootstrap/workingDir.js';
4
4
  import { sha256 } from '../../memory/codec.js';
5
5
  import { captureDependencies } from '../../memory/dependencies.js';
6
6
  import { adoptExperience, experienceReviewDue, readExperienceStore, recordExperienceFeedback, } from '../../memory/experienceStore.js';
7
- import { factCandidates } from '../../memory/factCandidates.js';
7
+ import { factCandidates, isLiveFactCandidate, } from '../../memory/factCandidates.js';
8
8
  import { cancelFactLearning, factLearningStatus, } from '../../memory/factLearning.js';
9
9
  import { cancelLearning, persistedLearningStatus, } from '../../memory/learning.js';
10
10
  import { createLearningModel } from '../../memory/learningModel.js';
11
11
  import { manageLearning } from '../../memory/managementService.js';
12
12
  import { memoryService } from '../../memory/memoryService.js';
13
- import { projectKnowledgeStatus, promoteExperienceKnowledge, promoteProjectKnowledge, } from '../../memory/projectKnowledge.js';
13
+ import { isLiveKnowledgeCandidate, projectKnowledgeStatus, promoteExperienceKnowledge, promoteProjectKnowledge, } from '../../memory/projectKnowledge.js';
14
14
  import { toToolParameters } from '../../utils/zodToJson.js';
15
15
  import { denyUnlessLocalOwner } from './policy.js';
16
16
  const schema = z.object({
@@ -285,7 +285,7 @@ export const memoryMaintenanceTool = {
285
285
  const knowledge = await projectKnowledgeStatus(ctx.workspaceId);
286
286
  // Same orphan rule as buildContextBundle: a candidate whose old record
287
287
  // was forgotten must not print that record's text back out.
288
- const liveRecordIds = new Set((await memoryService.snapshot(ctx.workspaceId)).records.map((record) => record.id));
288
+ const statements = new Map((await memoryService.snapshot(ctx.workspaceId)).records.map((record) => [record.id, record.statement]));
289
289
  return {
290
290
  ok: true,
291
291
  content: JSON.stringify({
@@ -301,12 +301,11 @@ export const memoryMaintenanceTool = {
301
301
  pendingTurns: facts.pending.length,
302
302
  queue: facts.pending.map(({ id, attempts, nextAttemptAt, failure }) => ({
303
303
  id,
304
- failure,
304
+ failure: failure && { ...failure, paused: isPausedJob({ failure }) },
305
305
  attempts,
306
306
  nextAttemptAt,
307
307
  })),
308
- candidates: (await factCandidates(ctx.workspaceId)).filter((item) => item.status === 'open' &&
309
- (!item.old || liveRecordIds.has(item.old.id))),
308
+ candidates: (await factCandidates(ctx.workspaceId)).filter((item) => isLiveFactCandidate(item, statements)),
310
309
  receipts: facts.receipts.slice(-10),
311
310
  enabled: (await memoryService.settings()).factLearning,
312
311
  },
@@ -314,7 +313,7 @@ export const memoryMaintenanceTool = {
314
313
  records: knowledge.records
315
314
  .filter((item) => item.status !== 'superseded')
316
315
  .slice(-20),
317
- candidates: knowledge.candidates.filter((item) => item.status === 'open'),
316
+ candidates: knowledge.candidates.filter((item) => isLiveKnowledgeCandidate(item, knowledge.records)),
318
317
  },
319
318
  // Dismissed items are filtered out of both lists above, so without
320
319
  // this the IDs `restore` needs are unreachable — delete would be a
@@ -341,7 +340,7 @@ export const memoryMaintenanceTool = {
341
340
  pendingTurns: store.pending.length,
342
341
  queue: store.pending.map(({ id, attempts, nextAttemptAt, failure }) => ({
343
342
  id,
344
- failure,
343
+ failure: failure && { ...failure, paused: isPausedJob({ failure }) },
345
344
  attempts,
346
345
  nextAttemptAt,
347
346
  })),
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { backgroundLearningHealth } from '../../memory/jobPolicy.js';
2
+ import { backgroundLearningHealth, isPausedJob } from '../../memory/jobPolicy.js';
3
3
  import { getWorkingDir } from '../../bootstrap/workingDir.js';
4
4
  import { sha256 } from '../../memory/codec.js';
5
5
  import { captureDependencies } from '../../memory/dependencies.js';
@@ -9,7 +9,10 @@ import {
9
9
  readExperienceStore,
10
10
  recordExperienceFeedback,
11
11
  } from '../../memory/experienceStore.js';
12
- import { factCandidates } from '../../memory/factCandidates.js';
12
+ import {
13
+ factCandidates,
14
+ isLiveFactCandidate,
15
+ } from '../../memory/factCandidates.js';
13
16
  import {
14
17
  cancelFactLearning,
15
18
  factLearningStatus,
@@ -22,6 +25,7 @@ import { createLearningModel } from '../../memory/learningModel.js';
22
25
  import { manageLearning, type LearningManagementRequest } from '../../memory/managementService.js';
23
26
  import { memoryService } from '../../memory/memoryService.js';
24
27
  import {
28
+ isLiveKnowledgeCandidate,
25
29
  projectKnowledgeStatus,
26
30
  promoteExperienceKnowledge,
27
31
  promoteProjectKnowledge,
@@ -379,9 +383,9 @@ export const memoryMaintenanceTool: Tool<z.infer<typeof schema>> = {
379
383
  const knowledge = await projectKnowledgeStatus(ctx.workspaceId);
380
384
  // Same orphan rule as buildContextBundle: a candidate whose old record
381
385
  // was forgotten must not print that record's text back out.
382
- const liveRecordIds = new Set(
386
+ const statements = new Map(
383
387
  (await memoryService.snapshot(ctx.workspaceId)).records.map(
384
- (record) => record.id,
388
+ (record) => [record.id, record.statement],
385
389
  ),
386
390
  );
387
391
  return {
@@ -400,14 +404,12 @@ export const memoryMaintenanceTool: Tool<z.infer<typeof schema>> = {
400
404
  pendingTurns: facts.pending.length,
401
405
  queue: facts.pending.map(({ id, attempts, nextAttemptAt, failure }) => ({
402
406
  id,
403
- failure,
407
+ failure: failure && { ...failure, paused: isPausedJob({ failure }) },
404
408
  attempts,
405
409
  nextAttemptAt,
406
410
  })),
407
411
  candidates: (await factCandidates(ctx.workspaceId)).filter(
408
- (item) =>
409
- item.status === 'open' &&
410
- (!item.old || liveRecordIds.has(item.old.id)),
412
+ (item) => isLiveFactCandidate(item, statements),
411
413
  ),
412
414
  receipts: facts.receipts.slice(-10),
413
415
  enabled: (await memoryService.settings()).factLearning,
@@ -416,8 +418,8 @@ export const memoryMaintenanceTool: Tool<z.infer<typeof schema>> = {
416
418
  records: knowledge.records
417
419
  .filter((item) => item.status !== 'superseded')
418
420
  .slice(-20),
419
- candidates: knowledge.candidates.filter(
420
- (item) => item.status === 'open',
421
+ candidates: knowledge.candidates.filter((item) =>
422
+ isLiveKnowledgeCandidate(item, knowledge.records),
421
423
  ),
422
424
  },
423
425
  // Dismissed items are filtered out of both lists above, so without
@@ -445,7 +447,7 @@ export const memoryMaintenanceTool: Tool<z.infer<typeof schema>> = {
445
447
  pendingTurns: store.pending.length,
446
448
  queue: store.pending.map(({ id, attempts, nextAttemptAt, failure }) => ({
447
449
  id,
448
- failure,
450
+ failure: failure && { ...failure, paused: isPausedJob({ failure }) },
449
451
  attempts,
450
452
  nextAttemptAt,
451
453
  })),
@@ -3,7 +3,7 @@ import { recallExperiences, experienceContext } from '../../memory/experienceSto
3
3
  import { recallProjectKnowledge, projectKnowledgeContext } from '../../memory/projectKnowledge.js';
4
4
  import { readConversationEpisode, searchConversationPage } from '../../memory/episodicMemory.js';
5
5
  import { memoryRecordPath } from '../../memory/fileStore.js';
6
- import { memoryService, } from '../../memory/memoryService.js';
6
+ import { memoryService, settleCandidatesAfterUpdate, } from '../../memory/memoryService.js';
7
7
  import { toToolParameters } from '../../utils/zodToJson.js';
8
8
  import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
9
9
  import { EXPLICIT_CROSS_WORKSPACE_INTENT, EXPLICIT_FORGET_INTENT, EXPLICIT_MEMORY_INTENT, EXPLICIT_PERSONA_INTENT, confirmSensitiveMemory, confirmMemoryCorrection, denyUnlessLocalOwner, requireCurrentEvidence, } from './policy.js';
@@ -307,6 +307,10 @@ export const updateMemoryTool = {
307
307
  }
308
308
  throw error;
309
309
  }
310
+ // Workspace records settle inside updateWithVersion; a personal record's
311
+ // candidates were retained in the workspace where the change was heard.
312
+ if (updated && input.scope === 'personal' && ctx.workspaceId)
313
+ await settleCandidatesAfterUpdate(ctx.workspaceId, updated);
310
314
  return updated
311
315
  ? {
312
316
  ok: true,
@@ -8,6 +8,7 @@ import {
8
8
  type MemoryCategory,
9
9
  type MemoryScope,
10
10
  memoryService,
11
+ settleCandidatesAfterUpdate,
11
12
  } from '../../memory/memoryService.js';
12
13
  import type { Tool } from '../../types.js';
13
14
  import { toToolParameters } from '../../utils/zodToJson.js';
@@ -355,6 +356,10 @@ export const updateMemoryTool: Tool<z.infer<typeof updateSchema>> = {
355
356
  }
356
357
  throw error;
357
358
  }
359
+ // Workspace records settle inside updateWithVersion; a personal record's
360
+ // candidates were retained in the workspace where the change was heard.
361
+ if (updated && input.scope === 'personal' && ctx.workspaceId)
362
+ await settleCandidatesAfterUpdate(ctx.workspaceId, updated);
358
363
  return updated
359
364
  ? {
360
365
  ok: true,
@@ -25,12 +25,10 @@
25
25
  保留原有消息 ID、工具调用 ID、来源标签、工具元数据、顾问咨询和决定;不引入数据库、
26
26
  服务器依赖或新的状态目录。普通 provider 和 gateway 请求会剥离这个本地字段。
27
27
 
28
- - Advisor 展开冷记录与实时尾部,再执行原有脱敏、图片控制和输入预算筛选;不会拿主模型
29
- 的摘要冒充原始证据。上下文包提供证据总数、选取数及省略数;条目是摘录,不代表完整审阅。
30
- - AdvisorDecision 可以关联被压缩移出的 `tool_call_id`。优化结果不参与证据计数、
31
- 证据候选或证据引用校验,不能用“优化成功”证明任务已完成。
32
- - 恢复 Session 时用相同审阅来源重放检查点、版本、历史意见与待处理咨询;新请求仍执行
33
- 原有 pending 隔离规则。压缩不会创建一次新任务或绕过评审。
28
+ - Advisor 展开冷记录与实时尾部(压缩产生的续接摘要紧随其后,标明不是一手证据),再抹密钥、
29
+ 按窗口截尾;不会拿主模型的摘要冒充原始证据。
30
+ - 优化结果不是一手证据,不能用“优化成功”证明任务已完成;顾问提醒只按本次运行内的真实
31
+ 改动、验证和调查证据计算,压缩不会创建一次新任务或绕过提醒。
34
32
  - 串行批次每完成一个工具就写入历史及观察状态,后面的 Advisor 能看到刚完成的结果;
35
33
  并行只读批次仍按调用顺序统一写入。优化工具继续保护整个在途批次。
36
34
  - 手动、自动、应急摘要和规则式 snip 共用保留逻辑;反复压缩把冷记录展平,不递归复制
@@ -32,10 +32,6 @@ export const BUILTIN_TOOL_PROMPT_GUIDES = {
32
32
  TaskOutput: g('shell', '读取后台任务增量输出或等待完成', '持有 task_id 后阻塞等待新输出', '高频轮询'),
33
33
  TaskStop: g('shell', '停止不再需要或失控的后台任务', '传入准确 task_id 并确认终止结果', '任务仍有价值时不要提前停止'),
34
34
  TerminalCapture: g('shell', '查看当前 TUI 终端屏幕状态', '仅在需要屏幕呈现而非命令输出时截取', '项目命令输出用 Bash/TaskOutput'),
35
- SSHHosts: g('shell', '调用 SSH/SSHUpload/SSHDownload 前不确定当前工作区配置了哪些远程主机', '直接调用查看别名列表'),
36
- SSH: g('shell', '在用户已配置的远程主机上执行命令', '按别名指定主机,命令明确后再执行', '本机操作用 Bash;主机未配置时先引导用户去 /config 添加'),
37
- SSHUpload: g('shell', '把本地文件传到已配置的远程主机', '给出本地路径和远程目标路径', '本机内文件操作用 Write/Edit'),
38
- SSHDownload: g('shell', '把已配置远程主机上的文件取回本地', '给出远程源路径和本地落盘路径', '读取远程命令输出用 SSH 而非下载文件'),
39
35
  WebSearch: g('web', '发现来源、查询当前信息或做多来源核实', '用短查询和明确时间范围,再打开高价值来源', '已知 URL 正文直接用 WebFetch', 'preferred'),
40
36
  WebFetch: g('web', '读取已知 URL 的静态正文', '抓取正文后核对来源与发布时间', '需要登录态、点击或动态交互时用 WebBrowser'),
41
37
  WebBrowser: g('web', '操作登录态网页、动态页面、表单或做网页视觉验收', '先观察,单步操作,再验证页面状态', '普通搜索、静态阅读和原生应用不要使用'),
@@ -69,8 +65,7 @@ export const BUILTIN_TOOL_PROMPT_GUIDES = {
69
65
  SearchConversations: g('memory', '用户提到之前、上次或既有方案', '用少量内容关键词检索', '不要提交整段问题或元词'),
70
66
  Skill: g('memory', '加载已安装的专门工作流程', '按精确名称读取并遵循 SKILL.md', '没有匹配 Skill 时不要调用'),
71
67
  SearchSkills: g('memory', 'Skill 目录被省略或需要按任务发现已安装技能', '搜索元数据,核对依赖,再用 Skill 加载命中名称', '已知精确技能名可直接加载'),
72
- Advisor: g('memory', '计划执行前、成果提交前、同题两次失败、用户不满意或非常不确定', '提供目标、证据和分歧点,再核验建议', '不要把顾问当事实来源或权限授予者'),
73
- AdvisorDecision: g('memory', '已收到 Advisor 建议,希望记录主 Agent 的采纳判断', '按证据记录 accept、partial 或 reject', '未咨询 Advisor 时不要调用'),
68
+ Advisor: g('memory', '实质工作前、认为完成后、同一问题失败两次、想换方案或非常不确定', '顾问已看到整段对话;note 只写想挑战的疑点,再核验建议', '不要把顾问当事实来源或权限授予者'),
74
69
  GenerateImage: g('media', '用户要求生成或编辑图片', '给出成品目标和输出位置并检查结果', '分析已有图片不使用'),
75
70
  GenerateSpeech: g('media', '用户要求生成语音或音频', '提供文本、声音要求和输出位置', '普通文字回答不使用'),
76
71
  PresentResult: g('media', '向用户正式交付生成或修改后的文件', '提交真实最终文件并附简短说明', '只提交面向用户的最终产物', 'preferred'),
@@ -109,9 +104,7 @@ export const CONTRACT_DESCRIPTION_OVERRIDES = {
109
104
  const notice = bashShellNotice();
110
105
  return notice ? `${base}\n\n${notice}` : base;
111
106
  },
112
- Advisor: '向无工具权限的顾问模型请求一次结构化第二意见。默认 reviewMode=brief 只给重点短评;完整代码审查用 full,并提供范围、基线和证据。full 不扩大上下文或输出预算,材料不足时必须说明未完成。',
113
- // 保留决策必填条件,与 schema 的 superRefine 一致;不能只概括成“记录决定”。
114
- AdvisorDecision: '记录主 Agent 对顾问第二意见的 accept、partial 或 reject 判断;是否采纳由主 Agent 决定,登记不是执行许可。partial 同时填 acceptedPoints/rejectedPoints;reject 填 rejectedPoints,列出被拒绝点及依据;evidenceRefs 只引用真实 tool_call_id,没有引用则记录待验证。登记失败不阻止任务继续。',
107
+ Advisor: '向无工具权限的顾问模型请求一次第二意见;它能看到整段对话,无需复述。默认 reviewMode=brief 只给重点短评;用户要求完整代码审查时用 full,并在 note 说明范围、基线和证据。full 不扩大上下文或输出预算,材料不足时必须说明未完成。',
115
108
  MultiEdit: '同文件有序批量精确替换,先 Read 相关范围;全部匹配成功才写盘。old_string 非空且唯一,或显式 replace_all。后续匹配前序生成文本会被拒绝,请合并 edits。操作条数不等于替换次数,diff 预览可能不完整。',
116
109
  LSP: '查询定义、引用、类型、符号和诊断。line/character 为 1-based UTF-16;尚未收到诊断不等于没有错误,编辑前读取源码。',
117
110
  WebFetch: '读取已知 HTTP(S) URL 的静态文本并完整保存会话快照,HTML 转 Markdown;结果仅为窗口,使用 snapshot_id + next_offset 续读,query 在全文中精确搜索,max_chars 可扩大读取预算。不要重复读取同一窗口或声称已读未展示部分。不执行 JavaScript、不继承登录态。PDF/图片用 Download 后 Read;动态页面用 WebBrowser。',
@@ -43,10 +43,6 @@ export const BUILTIN_TOOL_PROMPT_GUIDES: Readonly<Record<string, ToolPromptGuide
43
43
  TaskOutput: g('shell', '读取后台任务增量输出或等待完成', '持有 task_id 后阻塞等待新输出', '高频轮询'),
44
44
  TaskStop: g('shell', '停止不再需要或失控的后台任务', '传入准确 task_id 并确认终止结果', '任务仍有价值时不要提前停止'),
45
45
  TerminalCapture: g('shell', '查看当前 TUI 终端屏幕状态', '仅在需要屏幕呈现而非命令输出时截取', '项目命令输出用 Bash/TaskOutput'),
46
- SSHHosts: g('shell', '调用 SSH/SSHUpload/SSHDownload 前不确定当前工作区配置了哪些远程主机', '直接调用查看别名列表'),
47
- SSH: g('shell', '在用户已配置的远程主机上执行命令', '按别名指定主机,命令明确后再执行', '本机操作用 Bash;主机未配置时先引导用户去 /config 添加'),
48
- SSHUpload: g('shell', '把本地文件传到已配置的远程主机', '给出本地路径和远程目标路径', '本机内文件操作用 Write/Edit'),
49
- SSHDownload: g('shell', '把已配置远程主机上的文件取回本地', '给出远程源路径和本地落盘路径', '读取远程命令输出用 SSH 而非下载文件'),
50
46
 
51
47
  WebSearch: g('web', '发现来源、查询当前信息或做多来源核实', '用短查询和明确时间范围,再打开高价值来源', '已知 URL 正文直接用 WebFetch', 'preferred'),
52
48
  WebFetch: g('web', '读取已知 URL 的静态正文', '抓取正文后核对来源与发布时间', '需要登录态、点击或动态交互时用 WebBrowser'),
@@ -84,8 +80,7 @@ export const BUILTIN_TOOL_PROMPT_GUIDES: Readonly<Record<string, ToolPromptGuide
84
80
  SearchConversations: g('memory', '用户提到之前、上次或既有方案', '用少量内容关键词检索', '不要提交整段问题或元词'),
85
81
  Skill: g('memory', '加载已安装的专门工作流程', '按精确名称读取并遵循 SKILL.md', '没有匹配 Skill 时不要调用'),
86
82
  SearchSkills: g('memory', 'Skill 目录被省略或需要按任务发现已安装技能', '搜索元数据,核对依赖,再用 Skill 加载命中名称', '已知精确技能名可直接加载'),
87
- Advisor: g('memory', '计划执行前、成果提交前、同题两次失败、用户不满意或非常不确定', '提供目标、证据和分歧点,再核验建议', '不要把顾问当事实来源或权限授予者'),
88
- AdvisorDecision: g('memory', '已收到 Advisor 建议,希望记录主 Agent 的采纳判断', '按证据记录 accept、partial 或 reject', '未咨询 Advisor 时不要调用'),
83
+ Advisor: g('memory', '实质工作前、认为完成后、同一问题失败两次、想换方案或非常不确定', '顾问已看到整段对话;note 只写想挑战的疑点,再核验建议', '不要把顾问当事实来源或权限授予者'),
89
84
 
90
85
  GenerateImage: g('media', '用户要求生成或编辑图片', '给出成品目标和输出位置并检查结果', '分析已有图片不使用'),
91
86
  GenerateSpeech: g('media', '用户要求生成语音或音频', '提供文本、声音要求和输出位置', '普通文字回答不使用'),
@@ -127,9 +122,7 @@ export const CONTRACT_DESCRIPTION_OVERRIDES: Readonly<Record<string, string | ((
127
122
  const notice = bashShellNotice();
128
123
  return notice ? `${base}\n\n${notice}` : base;
129
124
  },
130
- Advisor: '向无工具权限的顾问模型请求一次结构化第二意见。默认 reviewMode=brief 只给重点短评;完整代码审查用 full,并提供范围、基线和证据。full 不扩大上下文或输出预算,材料不足时必须说明未完成。',
131
- // 保留决策必填条件,与 schema 的 superRefine 一致;不能只概括成“记录决定”。
132
- AdvisorDecision: '记录主 Agent 对顾问第二意见的 accept、partial 或 reject 判断;是否采纳由主 Agent 决定,登记不是执行许可。partial 同时填 acceptedPoints/rejectedPoints;reject 填 rejectedPoints,列出被拒绝点及依据;evidenceRefs 只引用真实 tool_call_id,没有引用则记录待验证。登记失败不阻止任务继续。',
125
+ Advisor: '向无工具权限的顾问模型请求一次第二意见;它能看到整段对话,无需复述。默认 reviewMode=brief 只给重点短评;用户要求完整代码审查时用 full,并在 note 说明范围、基线和证据。full 不扩大上下文或输出预算,材料不足时必须说明未完成。',
133
126
  MultiEdit: '同文件有序批量精确替换,先 Read 相关范围;全部匹配成功才写盘。old_string 非空且唯一,或显式 replace_all。后续匹配前序生成文本会被拒绝,请合并 edits。操作条数不等于替换次数,diff 预览可能不完整。',
134
127
  LSP: '查询定义、引用、类型、符号和诊断。line/character 为 1-based UTF-16;尚未收到诊断不等于没有错误,编辑前读取源码。',
135
128
  WebFetch: '读取已知 HTTP(S) URL 的静态文本并完整保存会话快照,HTML 转 Markdown;结果仅为窗口,使用 snapshot_id + next_offset 续读,query 在全文中精确搜索,max_chars 可扩大读取预算。不要重复读取同一窗口或声称已读未展示部分。不执行 JavaScript、不继承登录态。PDF/图片用 Download 后 Read;动态页面用 WebBrowser。',