minimal-agent 0.11.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.
Files changed (128) hide show
  1. package/package.json +4 -1
  2. package/plugins/workflow-runner/plugin.js +27 -15
  3. package/plugins/workflow-runner/plugin.ts +34 -20
  4. package/plugins/workflow-runner/src/agentCommon.js +13 -12
  5. package/plugins/workflow-runner/src/agentCommon.ts +22 -13
  6. package/plugins/workflow-runner/src/index.js +5 -3
  7. package/plugins/workflow-runner/src/index.ts +31 -13
  8. package/plugins/workflow-runner/src/multimodal.js +2 -1
  9. package/plugins/workflow-runner/src/multimodal.ts +2 -1
  10. package/plugins/workflow-runner/src/stepExecutors/skill.js +5 -6
  11. package/plugins/workflow-runner/src/stepExecutors/skill.ts +12 -7
  12. package/plugins/workflow-runner/src/stepExecutors/tool.js +68 -57
  13. package/plugins/workflow-runner/src/stepExecutors/tool.ts +88 -66
  14. package/plugins/workflow-runner/src/toolRuntime.js +48 -0
  15. package/plugins/workflow-runner/src/toolRuntime.ts +64 -0
  16. package/plugins/workflow-runner/src/types.ts +26 -7
  17. package/plugins/workflow-runner/test/context-files.test.ts +47 -16
  18. package/plugins/workflow-runner/test/hostCapability.test.ts +9 -3
  19. package/plugins/workflow-runner/test/multimodal.test.ts +61 -10
  20. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +168 -0
  21. package/src/cli/print.js +19 -4
  22. package/src/cli/print.ts +17 -4
  23. package/src/cli/streamJson.js +19 -4
  24. package/src/cli/streamJson.ts +17 -4
  25. package/src/config/configDefaults.js +25 -0
  26. package/src/config/configDefaults.ts +33 -0
  27. package/src/config/configFile.js +2 -21
  28. package/src/config/configFile.ts +11 -24
  29. package/src/config/configManagement.js +1 -1
  30. package/src/config/configManagement.ts +2 -2
  31. package/src/context/compact.js +4 -0
  32. package/src/context/compact.ts +4 -0
  33. package/src/context/contextBundle.js +38 -13
  34. package/src/context/contextBundle.ts +47 -13
  35. package/src/harness/stallGuard.js +19 -4
  36. package/src/harness/stallGuard.ts +30 -7
  37. package/src/loop.js +95 -11
  38. package/src/loop.ts +125 -16
  39. package/src/main.js +8 -1
  40. package/src/main.tsx +7 -1
  41. package/src/memory/constants.js +10 -0
  42. package/src/memory/constants.ts +13 -0
  43. package/src/memory/episodicMemory.js +274 -2
  44. package/src/memory/episodicMemory.ts +306 -1
  45. package/src/memory/fileStore.js +24 -4
  46. package/src/memory/fileStore.ts +22 -2
  47. package/src/memory/memoryService.js +79 -12
  48. package/src/memory/memoryService.ts +108 -9
  49. package/src/memory/repository.js +415 -85
  50. package/src/memory/repository.ts +437 -86
  51. package/src/memory/turnJournal.js +95 -0
  52. package/src/memory/turnJournal.ts +120 -0
  53. package/src/memory/types.ts +16 -0
  54. package/src/plugins/pluginApi.ts +30 -6
  55. package/src/plugins/pluginRunner.js +6 -2
  56. package/src/plugins/pluginRunner.ts +12 -7
  57. package/src/prompts/policyRegistry.js +27 -0
  58. package/src/prompts/policyRegistry.ts +27 -0
  59. package/src/prompts/promptAssembly.js +39 -7
  60. package/src/prompts/promptAssembly.ts +145 -59
  61. package/src/session/runAgentTurn.js +43 -21
  62. package/src/session/runAgentTurn.ts +68 -26
  63. package/src/session/runTurn.js +11 -46
  64. package/src/session/runTurn.ts +12 -46
  65. package/src/session/runtimeStore.js +149 -0
  66. package/src/session/runtimeStore.ts +197 -0
  67. package/src/session/sessionState.js +5 -0
  68. package/src/session/sessionState.ts +14 -0
  69. package/src/tools/agent/agent.js +143 -14
  70. package/src/tools/agent/agent.ts +149 -14
  71. package/src/tools/agent/agentTaskService.js +60 -0
  72. package/src/tools/agent/agentTaskService.ts +113 -0
  73. package/src/tools/agent/agentTypes.js +5 -0
  74. package/src/tools/agent/agentTypes.ts +5 -0
  75. package/src/tools/bash/bash.js +31 -11
  76. package/src/tools/bash/bash.ts +29 -10
  77. package/src/tools/capabilities.js +5 -0
  78. package/src/tools/capabilities.ts +11 -1
  79. package/src/tools/edit/edit.js +7 -4
  80. package/src/tools/edit/edit.ts +7 -4
  81. package/src/tools/edit/multi-edit.js +4 -2
  82. package/src/tools/edit/multi-edit.ts +4 -2
  83. package/src/tools/glob/glob.js +156 -40
  84. package/src/tools/glob/glob.ts +185 -46
  85. package/src/tools/index.js +35 -17
  86. package/src/tools/index.ts +81 -20
  87. package/src/tools/lsp/lsp.js +165 -22
  88. package/src/tools/lsp/lsp.ts +206 -36
  89. package/src/tools/powershell/powershell.js +116 -26
  90. package/src/tools/powershell/powershell.ts +155 -30
  91. package/src/tools/presentresult/presentresult.js +10 -0
  92. package/src/tools/presentresult/presentresult.ts +10 -0
  93. package/src/tools/read/read.js +244 -29
  94. package/src/tools/read/read.ts +391 -59
  95. package/src/tools/shared/diffSummary.js +44 -0
  96. package/src/tools/shared/diffSummary.ts +63 -0
  97. package/src/tools/shared/fileActivity.js +2 -1
  98. package/src/tools/shared/fileActivity.ts +3 -0
  99. package/src/tools/shared/permanentDeleteGuard.js +26 -0
  100. package/src/tools/shared/permanentDeleteGuard.ts +34 -0
  101. package/src/tools/shared/toolOutputStore.js +97 -0
  102. package/src/tools/shared/toolOutputStore.ts +110 -0
  103. package/src/tools/skill/skill.js +86 -0
  104. package/src/tools/skill/skill.ts +94 -0
  105. package/src/tools/snip/snip.js +67 -0
  106. package/src/tools/snip/snip.ts +80 -0
  107. package/src/tools/tasks/backgroundTaskService.js +79 -28
  108. package/src/tools/tasks/backgroundTaskService.ts +165 -49
  109. package/src/tools/tasks/taskManagement.js +163 -0
  110. package/src/tools/tasks/taskManagement.ts +180 -0
  111. package/src/tools/tasks/taskOutput.js +64 -14
  112. package/src/tools/tasks/taskOutput.ts +102 -23
  113. package/src/tools/tasks/taskStop.js +48 -8
  114. package/src/tools/tasks/taskStop.ts +69 -9
  115. package/src/tools/tasks/taskStore.js +46 -0
  116. package/src/tools/tasks/taskStore.ts +77 -0
  117. package/src/tools/terminal/terminalCapture.js +167 -0
  118. package/src/tools/terminal/terminalCapture.ts +179 -0
  119. package/src/tools/trash/trash.js +233 -0
  120. package/src/tools/trash/trash.ts +283 -0
  121. package/src/tools/worktree/sessionWorktree.js +128 -0
  122. package/src/tools/worktree/sessionWorktree.ts +158 -0
  123. package/src/tools/write/write.js +6 -2
  124. package/src/tools/write/write.ts +6 -2
  125. package/src/types.ts +12 -0
  126. package/src/ui/hooks/useChat.js +31 -11
  127. package/src/ui/hooks/useChat.ts +31 -13
  128. package/src/web/protocol.ts +78 -3
@@ -12,8 +12,19 @@ import {
12
12
  sha256,
13
13
  validateMemoryInput,
14
14
  } from './codec.js';
15
- import { DEFAULT_SETTINGS, PERSONA_MAX_CHARS } from './constants.js';
16
- import { episodicMemoryService } from './episodicMemory.js';
15
+ import {
16
+ DEFAULT_RETENTION,
17
+ DEFAULT_SETTINGS,
18
+ MEMORY_RETENTION_DAYS_MAX,
19
+ MEMORY_RETENTION_DAYS_MIN,
20
+ MEMORY_RETENTION_MB_MAX,
21
+ MEMORY_RETENTION_MB_MIN,
22
+ PERSONA_MAX_CHARS,
23
+ } from './constants.js';
24
+ import {
25
+ clearConversationEpisodes,
26
+ episodicMemoryService,
27
+ } from './episodicMemory.js';
17
28
  import {
18
29
  acquireFileLock,
19
30
  appendPrivateLine,
@@ -26,7 +37,9 @@ import {
26
37
  } from './fileStore.js';
27
38
  import { ensureMemoryMigrated } from './migration.js';
28
39
  import {
40
+ clearScopeTransactionQuarantine,
29
41
  readVersionedMemory,
42
+ refreshTopicView,
30
43
  removeVersionedMemory,
31
44
  replaceMemoryBatchVersioned,
32
45
  replaceVersionedMemory,
@@ -86,6 +99,7 @@ export { containsForbiddenSecret } from './codec.js';
86
99
 
87
100
  function mergeSettings(raw: Partial<MemorySettings>): MemorySettings {
88
101
  const review = raw.reviewAfterDays;
102
+ const retention = raw.retention;
89
103
  return {
90
104
  autoRemember:
91
105
  typeof raw.autoRemember === 'boolean'
@@ -100,16 +114,44 @@ function mergeSettings(raw: Partial<MemorySettings>): MemorySettings {
100
114
  project: review?.project ?? DEFAULT_SETTINGS.reviewAfterDays!.project,
101
115
  decision: review?.decision ?? DEFAULT_SETTINGS.reviewAfterDays!.decision,
102
116
  },
117
+ retention: {
118
+ episodeDays: retention?.episodeDays ?? DEFAULT_RETENTION.episodeDays,
119
+ episodeMaxMegabytes:
120
+ retention?.episodeMaxMegabytes ?? DEFAULT_RETENTION.episodeMaxMegabytes,
121
+ },
103
122
  };
104
123
  }
105
124
 
106
125
  function validateSettingsPatch(patch: Partial<MemorySettings>): void {
107
- if (patch.reviewAfterDays === undefined) return;
108
- for (const [category, days] of Object.entries(patch.reviewAfterDays)) {
109
- if (!Number.isInteger(days) || days < 7 || days > 3_650) {
110
- throw new Error(`复核周期 ${category} 必须是 7-3650 之间的整数天`);
126
+ if (patch.reviewAfterDays !== undefined) {
127
+ for (const [category, days] of Object.entries(patch.reviewAfterDays)) {
128
+ if (!Number.isInteger(days) || days < 7 || days > 3_650) {
129
+ throw new Error(`复核周期 ${category} 必须是 7-3650 之间的整数天`);
130
+ }
111
131
  }
112
132
  }
133
+ if (patch.retention === undefined) return;
134
+ const { episodeDays, episodeMaxMegabytes } = patch.retention;
135
+ if (
136
+ episodeDays !== undefined
137
+ && (!Number.isInteger(episodeDays)
138
+ || episodeDays < MEMORY_RETENTION_DAYS_MIN
139
+ || episodeDays > MEMORY_RETENTION_DAYS_MAX)
140
+ ) {
141
+ throw new Error(
142
+ `会话原文保留天数必须是 ${MEMORY_RETENTION_DAYS_MIN}-${MEMORY_RETENTION_DAYS_MAX} 之间的整数`,
143
+ );
144
+ }
145
+ if (
146
+ episodeMaxMegabytes !== undefined
147
+ && (!Number.isInteger(episodeMaxMegabytes)
148
+ || episodeMaxMegabytes < MEMORY_RETENTION_MB_MIN
149
+ || episodeMaxMegabytes > MEMORY_RETENTION_MB_MAX)
150
+ ) {
151
+ throw new Error(
152
+ `会话原文体积上限必须是 ${MEMORY_RETENTION_MB_MIN}-${MEMORY_RETENTION_MB_MAX} 之间的整数 MB`,
153
+ );
154
+ }
113
155
  }
114
156
 
115
157
  async function settingsDocument(): Promise<VersionedMemorySettings> {
@@ -129,6 +171,9 @@ async function settingsDocument(): Promise<VersionedMemorySettings> {
129
171
  }
130
172
  }
131
173
 
174
+ /** 审计日志单代上限;超限挪成 `.1`,保留最近两代。 */
175
+ const AUDIT_MAX_BYTES = 4 * 1024 * 1024;
176
+
132
177
  async function appendAudit(input: {
133
178
  action: string;
134
179
  record?: MemoryRecord;
@@ -147,28 +192,69 @@ async function appendAudit(input: {
147
192
  version: input.version,
148
193
  result: input.result,
149
194
  }),
195
+ // 审计日志同样是 append-only,必须轮转——它此前是仓库里第二个只增不减的存储。
196
+ { maxBytes: AUDIT_MAX_BYTES },
150
197
  ).catch(() => undefined);
151
198
  }
152
199
 
200
+ const EMPTY_SCOPE_SNAPSHOT: MemorySnapshot = Object.freeze({
201
+ records: [],
202
+ versions: {},
203
+ diagnostics: [],
204
+ createdAt: 0,
205
+ }) as MemorySnapshot;
206
+
207
+ /**
208
+ * 合并快照的记忆化。
209
+ *
210
+ * ⚠️ 这不是"顺手加个缓存",是修一个死缓存:`retrieval.ts` 用
211
+ * `WeakMap<MemorySnapshot, Bm25Index>` 按快照对象缓存 BM25 索引,而本函数以前**每次都
212
+ * 返回全新对象字面量** —— 于是 recall / buildContextBundle 这两条热路径上 WeakMap 永远
213
+ * miss,每轮对话都要重建整个索引,`recordSearchIndexCacheHit()` 一次都不会触发(诊断计数
214
+ * 器因此说谎)。单测直接对同一个 snapshot 对象调两次 recallFromSnapshot,机制是对的,
215
+ * 但生产集成从不复用对象,属于"测试通过、生产死代码"。
216
+ *
217
+ * 用底层两个 scope 快照的**对象标识**做键:scanMemoryScope 在缓存命中时返回同一个对象,
218
+ * 有变更时才换新对象——比时间戳更精确,也不怕时钟碰撞。
219
+ */
220
+ let combinedSnapshotCache: {
221
+ personal: MemorySnapshot;
222
+ workspace: MemorySnapshot;
223
+ workspaceId?: string;
224
+ combined: MemorySnapshot;
225
+ } | null = null;
226
+
153
227
  async function combinedSnapshot(workspaceId?: string): Promise<MemorySnapshot> {
154
228
  await ensureMemoryMigrated();
155
229
  const personal = await scanMemoryScope('personal');
156
230
  const workspace = workspaceId
157
231
  ? await scanMemoryScope('workspace', workspaceId)
158
- : { records: [], versions: {}, diagnostics: [], createdAt: Date.now() };
159
- return {
232
+ : EMPTY_SCOPE_SNAPSHOT;
233
+ const cached = combinedSnapshotCache;
234
+ if (
235
+ cached
236
+ && cached.personal === personal
237
+ && cached.workspace === workspace
238
+ && cached.workspaceId === workspaceId
239
+ ) {
240
+ return cached.combined;
241
+ }
242
+ const combined: MemorySnapshot = {
160
243
  records: [...personal.records, ...workspace.records],
161
244
  versions: { ...personal.versions, ...workspace.versions },
162
245
  diagnostics: [...personal.diagnostics, ...workspace.diagnostics],
163
246
  createdAt: Date.now(),
164
247
  };
248
+ combinedSnapshotCache = { personal, workspace, workspaceId, combined };
249
+ return combined;
165
250
  }
166
251
 
167
252
  function refreshTopicViewAfterMutation(
168
253
  scope: MemoryScope,
169
254
  workspaceId?: string,
170
255
  ): void {
171
- void scanMemoryScope(scope, workspaceId).catch(() => undefined);
256
+ combinedSnapshotCache = null;
257
+ void refreshTopicView(scope, workspaceId).catch(() => undefined);
172
258
  }
173
259
 
174
260
  function sameTopic(
@@ -565,6 +651,19 @@ export const memoryService = {
565
651
  await removeVersionedMemory({ record, version }, version);
566
652
  await appendAudit({ action: 'clear', record, version, result: 'ok' });
567
653
  }
654
+ // ★ 会话原文日志也要清掉。
655
+ // Desktop「永久清空」以前只删 records,而同一个记忆中心页面还提供
656
+ // ConversationHistorySearch —— 用户"清空记忆"后全部对话原文依然可搜,
657
+ // 与按钮承诺严重不符。工作区范围才有对应的 episodes 文件。
658
+ if (scope === 'workspace' && workspaceId) {
659
+ const removed = await clearConversationEpisodes(workspaceId).catch(() => 0);
660
+ if (removed) {
661
+ await appendAudit({ action: 'clear-episodes', result: 'ok' });
662
+ }
663
+ }
664
+ // 只有用户明确清空整个 scope 才表示隔离事务的复核现场也不再需要。
665
+ // 普通新增/更新记忆不得清除这类诊断。
666
+ await clearScopeTransactionQuarantine(scope, workspaceId);
568
667
  refreshTopicViewAfterMutation(scope, workspaceId);
569
668
  });
570
669
  },