@botbotgo/agent-harness 0.0.298 → 0.0.300

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 (166) hide show
  1. package/README.md +78 -38
  2. package/README.zh.md +80 -31
  3. package/dist/acp.d.ts +3 -0
  4. package/dist/acp.js +10 -2
  5. package/dist/api.d.ts +14 -2
  6. package/dist/api.js +19 -3
  7. package/dist/cli.d.ts +18 -1
  8. package/dist/cli.js +1408 -319
  9. package/dist/client/acp.d.ts +9 -3
  10. package/dist/client/acp.js +55 -1
  11. package/dist/client/in-process.d.ts +5 -2
  12. package/dist/client/in-process.js +4 -6
  13. package/dist/client/index.d.ts +1 -1
  14. package/dist/client/types.d.ts +6 -5
  15. package/dist/config/agents/direct.yaml +7 -17
  16. package/dist/config/agents/orchestra.yaml +9 -65
  17. package/dist/config/catalogs/embedding-models.yaml +1 -1
  18. package/dist/config/catalogs/stores.yaml +1 -1
  19. package/dist/config/knowledge/knowledge-runtime.yaml +36 -2
  20. package/dist/config/knowledge/procedural-memory-runtime.yaml +78 -0
  21. package/dist/config/{catalogs/models.yaml → models.yaml} +2 -2
  22. package/dist/config/prompts/direct-system.md +16 -0
  23. package/dist/config/prompts/orchestra-system.md +62 -0
  24. package/dist/config/prompts/routing-system.md +14 -0
  25. package/dist/config/runtime/runtime-memory.yaml +39 -5
  26. package/dist/config/runtime/workspace.yaml +7 -16
  27. package/dist/contracts/runtime.d.ts +242 -1
  28. package/dist/contracts/workspace.d.ts +2 -0
  29. package/dist/index.d.ts +5 -3
  30. package/dist/index.js +2 -1
  31. package/dist/init-project.js +178 -33
  32. package/dist/knowledge/contracts.d.ts +5 -0
  33. package/dist/knowledge/module.d.ts +5 -0
  34. package/dist/knowledge/module.js +340 -18
  35. package/dist/package-version.d.ts +1 -1
  36. package/dist/package-version.js +1 -1
  37. package/dist/persistence/file-store.d.ts +5 -1
  38. package/dist/persistence/file-store.js +16 -0
  39. package/dist/persistence/sqlite-store.d.ts +4 -1
  40. package/dist/persistence/sqlite-store.js +88 -14
  41. package/dist/persistence/types.d.ts +4 -1
  42. package/dist/procedural/config.d.ts +63 -0
  43. package/dist/procedural/config.js +125 -0
  44. package/dist/procedural/index.d.ts +2 -0
  45. package/dist/procedural/index.js +1 -0
  46. package/dist/protocol/ag-ui/http.d.ts +3 -0
  47. package/dist/protocol/ag-ui/http.js +10 -0
  48. package/dist/request-events.d.ts +63 -0
  49. package/dist/request-events.js +400 -0
  50. package/dist/resource/isolation.js +11 -0
  51. package/dist/resource/resource-impl.d.ts +1 -0
  52. package/dist/resource/resource-impl.js +103 -12
  53. package/dist/resources/init-templates/agent-context/deep-research.md +5 -0
  54. package/dist/resources/init-templates/prompts/research-analyst-basic.md +1 -0
  55. package/dist/resources/init-templates/prompts/research-analyst-web-search.md +1 -0
  56. package/dist/resources/init-templates/prompts/research-host-deep-research-basic.md +1 -0
  57. package/dist/resources/init-templates/prompts/research-host-deep-research-web-search.md +1 -0
  58. package/dist/resources/init-templates/prompts/research-host-single-agent-basic.md +1 -0
  59. package/dist/resources/init-templates/prompts/research-host-single-agent-web-search.md +1 -0
  60. package/dist/resources/prompts/runtime/browser-capability-disclaimer-recovery.md +1 -0
  61. package/dist/resources/prompts/runtime/default-subagent.md +2 -0
  62. package/dist/resources/prompts/runtime/durable-memory-context.md +7 -0
  63. package/dist/resources/prompts/runtime/execution-with-tool-evidence-retry.md +1 -0
  64. package/dist/resources/prompts/runtime/execution-with-tool-evidence.md +1 -0
  65. package/dist/resources/prompts/runtime/invalid-tool-selection-recovery.md +1 -0
  66. package/dist/resources/prompts/runtime/memory-manager.md +31 -0
  67. package/dist/resources/prompts/runtime/memory-mutation-reconciliation.md +22 -0
  68. package/dist/resources/prompts/runtime/slash-command-skill.md +6 -0
  69. package/dist/resources/prompts/runtime/strict-tool-json.md +1 -0
  70. package/dist/resources/prompts/runtime/workspace-boundary-guidance.md +3 -0
  71. package/dist/resources/prompts/runtime/workspace-relative-path.md +1 -0
  72. package/dist/resources/prompts/runtime/write-todos-descriptive-content.md +1 -0
  73. package/dist/resources/prompts/runtime/write-todos-full-entry.md +1 -0
  74. package/dist/resources/prompts/runtime/write-todos-non-empty-initial-list.md +1 -0
  75. package/dist/resources/tools/_runtime_tool_helpers.mjs +152 -0
  76. package/dist/resources/tools/cancel_request.mjs +21 -0
  77. package/dist/resources/tools/fetch_url.mjs +23 -0
  78. package/dist/resources/tools/http_request.mjs +30 -0
  79. package/dist/resources/tools/inspect_approvals.mjs +27 -0
  80. package/dist/resources/tools/inspect_artifacts.mjs +21 -0
  81. package/dist/resources/tools/inspect_events.mjs +21 -0
  82. package/dist/resources/tools/inspect_requests.mjs +27 -0
  83. package/dist/resources/tools/inspect_sessions.mjs +21 -0
  84. package/dist/resources/tools/list_files.mjs +27 -0
  85. package/dist/resources/tools/read_artifact.mjs +22 -0
  86. package/dist/resources/tools/request_approval.mjs +27 -0
  87. package/dist/resources/tools/run_command.mjs +21 -0
  88. package/dist/resources/tools/schedule_task.mjs +76 -0
  89. package/dist/resources/tools/search_files.mjs +47 -0
  90. package/dist/resources/tools/send_message.mjs +23 -0
  91. package/dist/runtime/adapter/direct-builtin-utility.d.ts +1 -0
  92. package/dist/runtime/adapter/direct-builtin-utility.js +90 -0
  93. package/dist/runtime/adapter/flow/execution-context.d.ts +1 -1
  94. package/dist/runtime/adapter/flow/execution-context.js +1 -1
  95. package/dist/runtime/adapter/flow/invocation-flow.d.ts +1 -0
  96. package/dist/runtime/adapter/flow/invocation-flow.js +9 -1
  97. package/dist/runtime/adapter/flow/invoke-runtime.d.ts +1 -1
  98. package/dist/runtime/adapter/flow/stream-runtime.d.ts +5 -1
  99. package/dist/runtime/adapter/flow/stream-runtime.js +556 -35
  100. package/dist/runtime/adapter/invocation-result.js +3 -2
  101. package/dist/runtime/adapter/local-tool-invocation.d.ts +1 -1
  102. package/dist/runtime/adapter/local-tool-invocation.js +28 -4
  103. package/dist/runtime/adapter/middleware-assembly.js +3 -1
  104. package/dist/runtime/adapter/model/invocation-request.d.ts +4 -1
  105. package/dist/runtime/adapter/model/invocation-request.js +138 -16
  106. package/dist/runtime/adapter/model/message-assembly.js +2 -6
  107. package/dist/runtime/adapter/model/model-providers.js +103 -5
  108. package/dist/runtime/adapter/resilience.js +17 -2
  109. package/dist/runtime/adapter/runtime-adapter-support.d.ts +11 -7
  110. package/dist/runtime/adapter/runtime-adapter-support.js +39 -5
  111. package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +63 -1
  112. package/dist/runtime/adapter/tool/builtin-middleware-tools.js +193 -21
  113. package/dist/runtime/adapter/tool/tool-arguments.d.ts +3 -1
  114. package/dist/runtime/adapter/tool/tool-arguments.js +52 -17
  115. package/dist/runtime/adapter/tool-resolution.d.ts +1 -0
  116. package/dist/runtime/adapter/tool-resolution.js +4 -2
  117. package/dist/runtime/agent-runtime-adapter.d.ts +27 -0
  118. package/dist/runtime/agent-runtime-adapter.js +163 -11
  119. package/dist/runtime/harness/events/event-bus.d.ts +1 -0
  120. package/dist/runtime/harness/events/event-bus.js +3 -0
  121. package/dist/runtime/harness/events/event-sink.d.ts +3 -0
  122. package/dist/runtime/harness/events/event-sink.js +16 -7
  123. package/dist/runtime/harness/events/streaming.d.ts +18 -1
  124. package/dist/runtime/harness/events/streaming.js +23 -10
  125. package/dist/runtime/harness/run/inspection.js +26 -5
  126. package/dist/runtime/harness/run/stream-run.d.ts +13 -4
  127. package/dist/runtime/harness/run/stream-run.js +448 -4
  128. package/dist/runtime/harness/run/surface-semantics.js +7 -34
  129. package/dist/runtime/harness/system/runtime-memory-manager.d.ts +3 -0
  130. package/dist/runtime/harness/system/runtime-memory-manager.js +384 -69
  131. package/dist/runtime/harness/system/runtime-memory-policy.d.ts +20 -1
  132. package/dist/runtime/harness/system/runtime-memory-policy.js +65 -17
  133. package/dist/runtime/harness/system/runtime-memory-records.js +100 -0
  134. package/dist/runtime/harness/system/runtime-memory-sync.js +2 -2
  135. package/dist/runtime/harness/system/store.d.ts +4 -0
  136. package/dist/runtime/harness/system/store.js +153 -0
  137. package/dist/runtime/harness.d.ts +9 -1
  138. package/dist/runtime/harness.js +141 -7
  139. package/dist/runtime/maintenance/sqlite-checkpoint-saver.d.ts +8 -3
  140. package/dist/runtime/maintenance/sqlite-checkpoint-saver.js +152 -53
  141. package/dist/runtime/parsing/output-parsing.d.ts +10 -2
  142. package/dist/runtime/parsing/output-parsing.js +223 -16
  143. package/dist/runtime/parsing/stream-event-parsing.d.ts +7 -0
  144. package/dist/runtime/parsing/stream-event-parsing.js +51 -1
  145. package/dist/runtime/scheduling/system-schedule-manager.d.ts +41 -0
  146. package/dist/runtime/scheduling/system-schedule-manager.js +532 -0
  147. package/dist/runtime/support/embedding-models.d.ts +1 -1
  148. package/dist/runtime/support/embedding-models.js +5 -2
  149. package/dist/runtime/support/runtime-factories.js +1 -1
  150. package/dist/runtime/support/runtime-layout.d.ts +3 -0
  151. package/dist/runtime/support/runtime-layout.js +10 -1
  152. package/dist/runtime/support/runtime-prompts.d.ts +30 -0
  153. package/dist/runtime/support/runtime-prompts.js +55 -0
  154. package/dist/runtime/support/vector-stores.d.ts +1 -1
  155. package/dist/runtime/support/vector-stores.js +5 -2
  156. package/dist/upstream-events.js +8 -7
  157. package/dist/utils/bundled-text.d.ts +3 -0
  158. package/dist/utils/bundled-text.js +25 -0
  159. package/dist/utils/id.js +3 -2
  160. package/dist/workspace/agent-binding-compiler.js +53 -13
  161. package/dist/workspace/object-loader.js +64 -2
  162. package/dist/workspace/support/workspace-ref-utils.d.ts +2 -1
  163. package/dist/workspace/support/workspace-ref-utils.js +24 -5
  164. package/dist/workspace/yaml-object-reader.d.ts +1 -0
  165. package/dist/workspace/yaml-object-reader.js +95 -17
  166. package/package.json +11 -5
@@ -2,7 +2,7 @@ import { createPersistentId } from "../utils/id.js";
2
2
  import { findMemoryRecordById, getMemoryRecord, listMemoryRecordsForScopes, persistStructuredMemoryRecords, removeMemoryRecord, updateMemoryRecord, } from "../runtime/harness/system/runtime-memory-records.js";
3
3
  import { consolidateStructuredMemoryScope } from "../runtime/harness/system/runtime-memory-consolidation.js";
4
4
  import { renderMemoryCandidatesMarkdown } from "../runtime/harness/system/runtime-memory-candidates.js";
5
- import { normalizeLangMemMemoryKind, scoreMemoryText, } from "../runtime/harness/system/runtime-memory-policy.js";
5
+ import { shouldRecallDurableMemory, normalizeLangMemMemoryKind, shouldStoreMemoryCandidate, } from "../runtime/harness/system/runtime-memory-policy.js";
6
6
  const ALL_SCOPES = ["session", "agent", "workspace", "user", "project"];
7
7
  const TITLE_BY_SCOPE = {
8
8
  session: "Session Structured Memory",
@@ -25,6 +25,24 @@ function normalizeRuntimeContext(context) {
25
25
  function summarizeMemoryContent(content) {
26
26
  return (content.trim().split("\n")[0] || content.trim()).slice(0, 240);
27
27
  }
28
+ function normalizeMemoryScope(scope) {
29
+ if (scope === "agent" || scope === "workspace" || scope === "user" || scope === "project") {
30
+ return scope;
31
+ }
32
+ return "session";
33
+ }
34
+ function extractCandidateScopeOptions(candidate) {
35
+ if (candidate.scope) {
36
+ return [normalizeMemoryScope(candidate.scope)];
37
+ }
38
+ const provenance = typeof candidate.provenance === "object" && candidate.provenance !== null && !Array.isArray(candidate.provenance)
39
+ ? candidate.provenance
40
+ : undefined;
41
+ const scopeOptions = Array.isArray(provenance?.scopeOptions)
42
+ ? provenance.scopeOptions.filter((item) => item === "session" || item === "agent" || item === "workspace" || item === "user" || item === "project")
43
+ : [];
44
+ return scopeOptions.length > 0 ? Array.from(new Set(scopeOptions)) : ["session"];
45
+ }
28
46
  function resolveRecallScopes(input, context) {
29
47
  if (Array.isArray(input.scopes) && input.scopes.length > 0) {
30
48
  return Array.from(new Set(input.scopes));
@@ -88,14 +106,268 @@ function getMemoryScopeBoost(scope) {
88
106
  function memoryFreshnessBoost(value) {
89
107
  return Math.max(0, 1 - ((Date.now() - Date.parse(value)) / (1000 * 60 * 60 * 24 * 365)));
90
108
  }
91
- function scoreStructuredRecord(query, record) {
92
- return (scoreMemoryText(query, `${record.summary}\n${record.content}`, getMemoryScopeBoost(record.scope)) +
109
+ function scoreStructuredRecord(record) {
110
+ return (getMemoryScopeBoost(record.scope) +
93
111
  memoryFreshnessBoost(record.lastConfirmedAt) +
94
112
  record.confidence);
95
113
  }
114
+ function characterGramSet(value) {
115
+ const normalized = normalizeCompareText(value).replace(/\s+/g, "");
116
+ const grams = new Set();
117
+ if (normalized.length < 2) {
118
+ if (normalized.length > 0) {
119
+ grams.add(normalized);
120
+ }
121
+ return grams;
122
+ }
123
+ for (let index = 0; index < normalized.length - 1; index += 1) {
124
+ grams.add(normalized.slice(index, index + 2));
125
+ }
126
+ return grams;
127
+ }
128
+ function characterGramSimilarity(left, right) {
129
+ const leftGrams = characterGramSet(left);
130
+ const rightGrams = characterGramSet(right);
131
+ if (leftGrams.size === 0 || rightGrams.size === 0) {
132
+ return 0;
133
+ }
134
+ let intersection = 0;
135
+ for (const gram of leftGrams) {
136
+ if (rightGrams.has(gram)) {
137
+ intersection += 1;
138
+ }
139
+ }
140
+ const union = new Set([...leftGrams, ...rightGrams]).size;
141
+ return union === 0 ? 0 : intersection / union;
142
+ }
143
+ function textSimilarity(left, right) {
144
+ return Math.max(jaccardTextSimilarity(left, right), characterGramSimilarity(left, right));
145
+ }
146
+ function scoreStructuredRecordForQuery(record, query) {
147
+ let score = scoreStructuredRecord(record);
148
+ score += textSimilarity(record.summary, query) * 5;
149
+ score += textSimilarity(record.content, query) * 4;
150
+ if (record.knowledgeIdentity) {
151
+ score += textSimilarity(record.knowledgeIdentity, query) * 2;
152
+ }
153
+ if (record.operationalRule) {
154
+ score += textSimilarity(record.operationalRule.trigger, query) * 3;
155
+ score += textSimilarity(record.operationalRule.target, query) * 2;
156
+ if (record.operationalRule.effect === "invalidate" || record.knowledgeOperation === "delete") {
157
+ score += 0.5;
158
+ }
159
+ }
160
+ return score;
161
+ }
96
162
  function normalizeMemoryDedupKey(record) {
97
163
  return `${record.scope}::${record.summary.toLowerCase().replace(/\s+/g, " ").trim()}::${record.content.toLowerCase().replace(/\s+/g, " ").trim()}`;
98
164
  }
165
+ function normalizeCompareText(value) {
166
+ return value.toLowerCase().replace(/\s+/g, " ").trim();
167
+ }
168
+ function tokenizeText(value) {
169
+ return new Set(value
170
+ .toLowerCase()
171
+ .split(/[^a-z0-9_]+/i)
172
+ .map((token) => token.trim())
173
+ .filter((token) => token.length > 2));
174
+ }
175
+ function jaccardTextSimilarity(left, right) {
176
+ const leftTokens = tokenizeText(left);
177
+ const rightTokens = tokenizeText(right);
178
+ if (leftTokens.size === 0 || rightTokens.size === 0) {
179
+ return 0;
180
+ }
181
+ let intersection = 0;
182
+ for (const token of leftTokens) {
183
+ if (rightTokens.has(token)) {
184
+ intersection += 1;
185
+ }
186
+ }
187
+ const union = new Set([...leftTokens, ...rightTokens]).size;
188
+ return union === 0 ? 0 : intersection / union;
189
+ }
190
+ function containsDeletionSignal(value) {
191
+ const normalized = normalizeCompareText(value);
192
+ if (!normalized) {
193
+ return false;
194
+ }
195
+ return [
196
+ "delete",
197
+ "deleted",
198
+ "remove",
199
+ "removed",
200
+ "revoked",
201
+ "forbidden",
202
+ "not allowed",
203
+ "no longer",
204
+ "unavailable",
205
+ "disabled",
206
+ "deprecated",
207
+ "取消",
208
+ "撤销",
209
+ "删除",
210
+ "已删除",
211
+ "删掉",
212
+ "移除",
213
+ "不再",
214
+ "不可用",
215
+ "不能",
216
+ "无法",
217
+ "禁用",
218
+ "废弃",
219
+ ].some((signal) => normalized.includes(signal));
220
+ }
221
+ function extractSalientLiterals(value) {
222
+ const results = new Set();
223
+ const normalized = value.trim();
224
+ if (!normalized) {
225
+ return results;
226
+ }
227
+ for (const match of normalized.matchAll(/[`'"]([^`'"]{1,64})[`'"]/g)) {
228
+ const literal = match[1]?.trim().toLowerCase();
229
+ if (literal && literal.length >= 2) {
230
+ results.add(literal);
231
+ }
232
+ }
233
+ for (const match of normalized.matchAll(/\b[a-z][a-z0-9._/-]{1,63}\b/gi)) {
234
+ const token = match[0]?.trim().toLowerCase();
235
+ if (token && !["system", "startup", "command", "memory", "instruction", "user", "deleted"].includes(token)) {
236
+ results.add(token);
237
+ }
238
+ }
239
+ return results;
240
+ }
241
+ function sharesSalientLiteral(left, right) {
242
+ const leftLiterals = extractSalientLiterals(left);
243
+ const rightLiterals = extractSalientLiterals(right);
244
+ if (leftLiterals.size === 0 || rightLiterals.size === 0) {
245
+ return false;
246
+ }
247
+ for (const literal of leftLiterals) {
248
+ if (rightLiterals.has(literal)) {
249
+ return true;
250
+ }
251
+ }
252
+ return false;
253
+ }
254
+ function mergeScoredRecords(...groups) {
255
+ const merged = new Map();
256
+ for (const group of groups) {
257
+ for (const item of group) {
258
+ const existing = merged.get(item.record.id);
259
+ if (!existing || item.score > existing.score) {
260
+ merged.set(item.record.id, item);
261
+ }
262
+ }
263
+ }
264
+ return Array.from(merged.values())
265
+ .sort((left, right) => right.score - left.score || right.record.lastConfirmedAt.localeCompare(left.record.lastConfirmedAt))
266
+ .map((item) => item.record);
267
+ }
268
+ function selectRelevantExistingRecords(candidates, existingRecords) {
269
+ const scored = new Map();
270
+ for (const candidate of candidates) {
271
+ const candidateScopes = new Set(extractCandidateScopeOptions(candidate));
272
+ const content = normalizeCompareText(candidate.content);
273
+ const summary = normalizeCompareText(candidate.summary ?? summarizeMemoryContent(candidate.content));
274
+ const sourceRef = typeof candidate.sourceRef === "string" ? candidate.sourceRef.trim() : "";
275
+ const candidateText = `${candidate.summary ?? ""}\n${candidate.content}`;
276
+ const deletionSignal = containsDeletionSignal(candidateText);
277
+ for (const record of existingRecords) {
278
+ if (!candidateScopes.has(record.scope)) {
279
+ continue;
280
+ }
281
+ let score = 0;
282
+ let deterministicMatch = false;
283
+ if (sourceRef && record.sourceRefs.includes(sourceRef)) {
284
+ score += 10;
285
+ deterministicMatch = true;
286
+ }
287
+ if (normalizeCompareText(record.content) === content) {
288
+ score += 9;
289
+ deterministicMatch = true;
290
+ }
291
+ if (normalizeCompareText(record.summary) === summary) {
292
+ score += 8;
293
+ deterministicMatch = true;
294
+ }
295
+ const similarityScore = textSimilarity(record.summary, candidate.summary ?? candidate.content) * 4
296
+ + textSimilarity(record.content, candidate.content) * 3;
297
+ score += similarityScore;
298
+ if (deletionSignal) {
299
+ const ruleTarget = record.operationalRule?.target?.trim().toLowerCase();
300
+ if (ruleTarget && candidateText.toLowerCase().includes(ruleTarget)) {
301
+ score += 12;
302
+ deterministicMatch = true;
303
+ }
304
+ if (sharesSalientLiteral(candidateText, `${record.summary}\n${record.content}`)) {
305
+ score += 8;
306
+ deterministicMatch = true;
307
+ }
308
+ }
309
+ if (!deterministicMatch && similarityScore < 1) {
310
+ continue;
311
+ }
312
+ if (score <= 0) {
313
+ continue;
314
+ }
315
+ const existing = scored.get(record.id);
316
+ if (!existing || score > existing.score) {
317
+ scored.set(record.id, { record, score });
318
+ }
319
+ }
320
+ }
321
+ return Array.from(scored.values())
322
+ .sort((left, right) => right.score - left.score || right.record.lastConfirmedAt.localeCompare(left.record.lastConfirmedAt))
323
+ .map((item) => item.record);
324
+ }
325
+ async function selectVectorRelevantExistingRecords(input) {
326
+ const vectorStore = await input.resolveVectorStore();
327
+ if (!vectorStore) {
328
+ return [];
329
+ }
330
+ const existingById = new Map(input.existingRecords.map((record) => [record.id, record]));
331
+ const scored = new Map();
332
+ try {
333
+ for (const candidate of input.candidates) {
334
+ const candidateScopes = new Set(extractCandidateScopeOptions(candidate));
335
+ const query = [candidate.summary?.trim(), candidate.content.trim()].filter((value) => !!value && value.length > 0).join("\n");
336
+ if (!query) {
337
+ continue;
338
+ }
339
+ const hits = await vectorStore.similaritySearch(query, 8);
340
+ for (const hit of hits) {
341
+ const metadata = typeof hit.metadata === "object" && hit.metadata !== null && !Array.isArray(hit.metadata)
342
+ ? hit.metadata
343
+ : {};
344
+ const recordId = typeof metadata.recordId === "string" ? metadata.recordId : undefined;
345
+ if (!recordId) {
346
+ continue;
347
+ }
348
+ const record = existingById.get(recordId);
349
+ if (!record || record.status !== "active" || !candidateScopes.has(record.scope)) {
350
+ continue;
351
+ }
352
+ const score = (typeof hit.score === "number" ? hit.score : 0) + scoreStructuredRecordForQuery(record, query);
353
+ const existing = scored.get(record.id);
354
+ if (!existing || score > existing.score) {
355
+ scored.set(record.id, { record, score });
356
+ }
357
+ }
358
+ }
359
+ }
360
+ catch {
361
+ return [];
362
+ }
363
+ return Array.from(scored.values())
364
+ .sort((left, right) => right.score - left.score || right.record.lastConfirmedAt.localeCompare(left.record.lastConfirmedAt));
365
+ }
366
+ function sortPromptRecallRecords(items) {
367
+ return [...items].sort((left, right) => left.record.observedAt.localeCompare(right.record.observedAt)
368
+ || left.record.createdAt.localeCompare(right.record.createdAt)
369
+ || left.record.id.localeCompare(right.record.id));
370
+ }
99
371
  function inferMem0MemoryKind(hit) {
100
372
  const candidates = [
101
373
  ...hit.categories,
@@ -187,7 +459,10 @@ export class DefaultKnowledgeModule {
187
459
  requestId,
188
460
  sessionId,
189
461
  recordedAt,
190
- }, { storeCandidateLog: input.storeCandidateLog !== false });
462
+ }, {
463
+ storeCandidateLog: input.storeCandidateLog !== false,
464
+ forceStore: input.forceStore === true,
465
+ });
191
466
  }
192
467
  async recall(input, context) {
193
468
  if (typeof input.query !== "string" || input.query.trim().length === 0) {
@@ -211,7 +486,10 @@ export class DefaultKnowledgeModule {
211
486
  .map(({ record }) => record);
212
487
  return { items };
213
488
  }
214
- async buildPromptContext(input, context) {
489
+ async buildPromptRecall(input, context) {
490
+ if (!shouldRecallDurableMemory(input.query)) {
491
+ return { items: [] };
492
+ }
215
493
  const normalizedContext = normalizeRuntimeContext(context);
216
494
  const ranked = (await this.rankRecallCandidates({
217
495
  query: input.query,
@@ -230,6 +508,8 @@ export class DefaultKnowledgeModule {
230
508
  ? 2
231
509
  : 1;
232
510
  return {
511
+ record: item.record,
512
+ scope: item.record.scope,
233
513
  content: [
234
514
  `# Durable ${item.record.scope[0].toUpperCase()}${item.record.scope.slice(1)} Memory`,
235
515
  "",
@@ -237,20 +517,38 @@ export class DefaultKnowledgeModule {
237
517
  `- kind: ${item.record.kind}`,
238
518
  `- scope: ${item.record.scope}`,
239
519
  `- confidence: ${item.record.confidence.toFixed(2)}`,
520
+ ...(item.record.knowledgeIdentity
521
+ ? [
522
+ `- knowledge_identity: ${item.record.knowledgeIdentity}`,
523
+ `- knowledge_operation: ${item.record.knowledgeOperation ?? "create"}`,
524
+ ]
525
+ : []),
240
526
  "",
241
527
  item.record.content,
242
528
  ].join("\n"),
243
- score: scoreMemoryText(input.query, `${item.record.summary}\n${item.record.content}`, scopeBoost) +
529
+ score: scopeBoost +
244
530
  memoryFreshnessBoost(item.record.lastConfirmedAt) +
245
531
  item.record.confidence,
246
532
  };
247
533
  })
248
- .sort((left, right) => right.score - left.score)
249
- .slice(0, this.deps.policy?.retrieval.maxPromptMemories ?? 8);
534
+ .sort((left, right) => right.score - left.score);
250
535
  if (ranked.length === 0) {
251
- return undefined;
536
+ return { items: [] };
252
537
  }
253
- return ranked.map((entry) => entry.content).join("\n\n");
538
+ const maxPromptMemories = this.deps.policy?.retrieval.maxPromptMemories ?? 8;
539
+ const selected = ranked.slice(0, maxPromptMemories);
540
+ if (selected.length === 0) {
541
+ return { items: [] };
542
+ }
543
+ const orderedSelected = sortPromptRecallRecords(selected);
544
+ return {
545
+ items: orderedSelected.map((entry) => entry.record),
546
+ context: orderedSelected.map((entry) => entry.content).join("\n\n"),
547
+ };
548
+ }
549
+ async buildPromptContext(input, context) {
550
+ const promptRecall = await this.buildPromptRecall(input, context);
551
+ return promptRecall.context;
254
552
  }
255
553
  async list(input = {}, context) {
256
554
  const normalizedContext = { ...context };
@@ -305,6 +603,12 @@ export class DefaultKnowledgeModule {
305
603
  tags: Array.isArray(input.tags)
306
604
  ? Array.from(new Set(input.tags.map((item) => item.trim()).filter((item) => item.length > 0)))
307
605
  : existing.tags,
606
+ knowledgeIdentity: typeof input.knowledgeIdentity === "string" && input.knowledgeIdentity.trim().length > 0
607
+ ? input.knowledgeIdentity.trim()
608
+ : existing.knowledgeIdentity,
609
+ knowledgeOperation: input.knowledgeOperation === "create" || input.knowledgeOperation === "update" || input.knowledgeOperation === "delete"
610
+ ? input.knowledgeOperation
611
+ : existing.knowledgeOperation,
308
612
  observedAt: typeof input.observedAt === "string" && input.observedAt.trim().length > 0 ? input.observedAt : existing.observedAt,
309
613
  lastConfirmedAt: typeof input.lastConfirmedAt === "string" && input.lastConfirmedAt.trim().length > 0
310
614
  ? input.lastConfirmedAt
@@ -339,21 +643,39 @@ export class DefaultKnowledgeModule {
339
643
  if (validCandidates.length === 0) {
340
644
  return { records: [], decisions: [] };
341
645
  }
342
- const existingRecords = await listMemoryRecordsForScopes(this.deps.store, ALL_SCOPES);
646
+ const relevantScopes = Array.from(new Set(validCandidates.flatMap((candidate) => extractCandidateScopeOptions(candidate))));
647
+ const existingRecords = await listMemoryRecordsForScopes(this.deps.store, relevantScopes);
648
+ const vectorRelatedExistingRecords = await selectVectorRelevantExistingRecords({
649
+ candidates: validCandidates,
650
+ existingRecords,
651
+ resolveVectorStore: this.deps.resolveVectorStore,
652
+ });
653
+ const deterministicRelatedExistingRecords = selectRelevantExistingRecords(validCandidates, existingRecords)
654
+ .map((record) => ({
655
+ record,
656
+ score: scoreStructuredRecord(record),
657
+ }));
658
+ const relatedExistingRecords = mergeScoredRecords(vectorRelatedExistingRecords, deterministicRelatedExistingRecords);
343
659
  const transformedCandidates = this.deps.transformCandidates
344
- ? await this.deps.transformCandidates({ candidates: validCandidates, context: normalizedContext, existingRecords })
660
+ ? await this.deps.transformCandidates({ candidates: validCandidates, context: normalizedContext, existingRecords: relatedExistingRecords })
345
661
  : validCandidates;
662
+ const storedCandidates = options.forceStore === true
663
+ ? transformedCandidates
664
+ : transformedCandidates.filter((candidate) => shouldStoreMemoryCandidate(this.deps.policy, candidate));
665
+ if (storedCandidates.length === 0) {
666
+ return { records: [], decisions: [] };
667
+ }
346
668
  if (options.storeCandidateLog) {
347
669
  await this.deps.store.put(["memories", "candidates", normalizedContext.sessionId ?? `memory-api-${normalizedContext.requestId ?? "unknown"}`], `${normalizedContext.requestId}.json`, {
348
670
  requestId: normalizedContext.requestId,
349
671
  sessionId: normalizedContext.sessionId,
350
672
  storedAt: normalizedContext.recordedAt,
351
- candidates: transformedCandidates,
673
+ candidates: storedCandidates,
352
674
  });
353
675
  }
354
676
  const persisted = await persistStructuredMemoryRecords({
355
677
  store: this.deps.store,
356
- candidates: transformedCandidates,
678
+ candidates: storedCandidates,
357
679
  sessionId: normalizedContext.sessionId ?? `memory-api-${normalizedContext.requestId ?? "unknown"}`,
358
680
  requestId: normalizedContext.requestId ?? createPersistentId(new Date(normalizedContext.recordedAt ?? new Date().toISOString())),
359
681
  agentId: normalizedContext.agentId,
@@ -363,7 +685,7 @@ export class DefaultKnowledgeModule {
363
685
  recordedAt: normalizedContext.recordedAt ?? new Date().toISOString(),
364
686
  });
365
687
  await this.rebuildVectorIndex();
366
- await this.refreshAfterWrite(transformedCandidates, normalizedContext);
688
+ await this.refreshAfterWrite(storedCandidates, normalizedContext);
367
689
  return persisted;
368
690
  }
369
691
  async refreshAfterWrite(candidates, context) {
@@ -489,7 +811,7 @@ export class DefaultKnowledgeModule {
489
811
  .filter((record) => (input.kinds ? input.kinds.has(record.kind) : true))
490
812
  .map((record) => ({
491
813
  record,
492
- score: scoreStructuredRecord(input.query, record),
814
+ score: scoreStructuredRecordForQuery(record, input.query),
493
815
  }));
494
816
  const deduped = new Map();
495
817
  for (const item of ranked) {
@@ -528,7 +850,7 @@ export class DefaultKnowledgeModule {
528
850
  continue;
529
851
  }
530
852
  const key = normalizeMemoryDedupKey(canonical);
531
- const score = scoreStructuredRecord(input.query, canonical) + (typeof hit.score === "number" ? hit.score : 0);
853
+ const score = scoreStructuredRecordForQuery(canonical, input.query) + (typeof hit.score === "number" ? hit.score : 0);
532
854
  const existing = deduped.get(key);
533
855
  if (!existing || score > existing.score) {
534
856
  deduped.set(key, { record: canonical, score });
@@ -571,7 +893,7 @@ export class DefaultKnowledgeModule {
571
893
  }
572
894
  deduped.set(key, {
573
895
  record,
574
- score: scoreStructuredRecord(input.query, record) + Math.max(0, Math.min(1, hit.score)) * 4,
896
+ score: scoreStructuredRecordForQuery(record, input.query) + Math.max(0, Math.min(1, hit.score)) * 4,
575
897
  });
576
898
  }
577
899
  return Array.from(deduped.values()).sort((left, right) => right.score - left.score);
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.297";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.299";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.297";
1
+ export const AGENT_HARNESS_VERSION = "0.0.299";
@@ -1,4 +1,4 @@
1
- import type { ArtifactListing, ArtifactRecord, HarnessEvent, InternalApprovalRecord, RequestSummary, RequestState, SessionRequestRecord, SessionSummary, TranscriptMessage } from "../contracts/types.js";
1
+ import type { ArtifactListing, ArtifactRecord, HarnessEvent, InternalApprovalRecord, RequestPlanState, RequestSummary, RequestState, SessionRequestRecord, SessionSummary, TranscriptMessage } from "../contracts/types.js";
2
2
  import type { ApprovalFilter, PersistedSessionListSummary, PersistedRequestInput, PersistedRequestControlRecord, PersistedRunInspection, PersistedRequestQueueRecord, PersistenceLifecycle as Lifecycle, PersistenceRequestMeta as RequestMeta, RuntimePersistence, RecoveryIntent, PersistenceSessionMeta as SessionMeta, RequestSummaryFilter, SessionSummaryFilter } from "./types.js";
3
3
  type RequestIndexRecord = {
4
4
  requestId: string;
@@ -17,6 +17,7 @@ export declare class FilePersistence implements RuntimePersistence {
17
17
  private requestQueuePath;
18
18
  private requestControlPath;
19
19
  private traceItemsPath;
20
+ private requestPlanStatePath;
20
21
  private writeSessionHead;
21
22
  initialize(): Promise<void>;
22
23
  sessionDir(sessionId: string): string;
@@ -73,6 +74,9 @@ export declare class FilePersistence implements RuntimePersistence {
73
74
  clearRequestInput(sessionId: string, requestId: string): Promise<void>;
74
75
  createApproval(record: InternalApprovalRecord): Promise<void>;
75
76
  resolveApproval(sessionId: string, requestId: string, approvalId: string, status: InternalApprovalRecord["status"]): Promise<InternalApprovalRecord>;
77
+ saveRequestPlanState(sessionId: string, requestId: string, planState: RequestPlanState): Promise<void>;
78
+ getRequestPlanState(sessionId: string, requestId: string): Promise<RequestPlanState | null>;
79
+ clearRequestPlanState(sessionId: string, requestId: string): Promise<void>;
76
80
  createRequestArtifact(sessionId: string, requestId: string, artifact: ArtifactRecord, content: unknown): Promise<ArtifactRecord>;
77
81
  listRequestArtifacts(sessionId: string, requestId: string): Promise<ArtifactListing>;
78
82
  readRequestArtifact(sessionId: string, requestId: string, artifactPath: string): Promise<unknown>;
@@ -31,6 +31,9 @@ export class FilePersistence {
31
31
  traceItemsPath(sessionId, requestId) {
32
32
  return path.join(this.requestDir(sessionId, requestId), "trace-items.ndjson");
33
33
  }
34
+ requestPlanStatePath(sessionId, requestId) {
35
+ return path.join(this.requestDir(sessionId, requestId), "plan-state.json");
36
+ }
34
37
  async writeSessionHead(sessionId, input) {
35
38
  const sessionMetaPath = path.join(this.sessionDir(sessionId), "meta.json");
36
39
  const sessionMeta = await readJson(sessionMetaPath);
@@ -540,6 +543,19 @@ export class FilePersistence {
540
543
  ]);
541
544
  return updated;
542
545
  }
546
+ async saveRequestPlanState(sessionId, requestId, planState) {
547
+ await writeJson(this.requestPlanStatePath(sessionId, requestId), planState);
548
+ }
549
+ async getRequestPlanState(sessionId, requestId) {
550
+ const planStatePath = this.requestPlanStatePath(sessionId, requestId);
551
+ if (!(await fileExists(planStatePath))) {
552
+ return null;
553
+ }
554
+ return readJson(planStatePath);
555
+ }
556
+ async clearRequestPlanState(sessionId, requestId) {
557
+ await rm(this.requestPlanStatePath(sessionId, requestId), { force: true });
558
+ }
543
559
  async createRequestArtifact(sessionId, requestId, artifact, content) {
544
560
  const requestDir = this.requestDir(sessionId, requestId);
545
561
  await writeJson(path.join(requestDir, artifact.path), content);
@@ -1,4 +1,4 @@
1
- import type { ArtifactListing, ArtifactRecord, HarnessEvent, InternalApprovalRecord, RequestSummary, RequestState, SessionRequestRecord, SessionSummary, TranscriptMessage } from "../contracts/types.js";
1
+ import type { ArtifactListing, ArtifactRecord, HarnessEvent, InternalApprovalRecord, RequestPlanState, RequestSummary, RequestState, SessionRequestRecord, SessionSummary, TranscriptMessage } from "../contracts/types.js";
2
2
  import type { PersistedSessionListSummary, PersistenceSessionMeta, PersistedRequestInput, PersistedRequestControlRecord, PersistedRunInspection, PersistedRequestQueueRecord, PersistenceLifecycle, PersistenceRequestMeta, RecoveryIntent, RuntimePersistence, ApprovalFilter, RequestSummaryFilter, SessionSummaryFilter } from "./types.js";
3
3
  export declare function listProtectedCheckpointSessionIds(dbPath: string): Promise<Set<string>>;
4
4
  export declare class SqlitePersistence implements RuntimePersistence {
@@ -92,6 +92,9 @@ export declare class SqlitePersistence implements RuntimePersistence {
92
92
  clearRequestInput(sessionId: string, requestId: string): Promise<void>;
93
93
  createApproval(record: InternalApprovalRecord): Promise<void>;
94
94
  resolveApproval(sessionId: string, requestId: string, approvalId: string, status: InternalApprovalRecord["status"]): Promise<InternalApprovalRecord>;
95
+ saveRequestPlanState(sessionId: string, requestId: string, planState: RequestPlanState): Promise<void>;
96
+ getRequestPlanState(sessionId: string, requestId: string): Promise<RequestPlanState | null>;
97
+ clearRequestPlanState(sessionId: string, requestId: string): Promise<void>;
95
98
  createRequestArtifact(sessionId: string, requestId: string, artifact: ArtifactRecord, content: unknown): Promise<ArtifactRecord>;
96
99
  listRequestArtifacts(sessionId: string, requestId: string): Promise<ArtifactListing>;
97
100
  appendSessionMessage(sessionId: string, message: TranscriptMessage): Promise<void>;