ai-memory-layer 2.0.1 → 3.0.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 (186) hide show
  1. package/CHANGELOG.md +19 -12
  2. package/README.md +435 -320
  3. package/bin/memory-server.mjs +0 -0
  4. package/dist/adapters/memory/embeddings.d.ts.map +1 -1
  5. package/dist/adapters/memory/embeddings.js +12 -1
  6. package/dist/adapters/memory/embeddings.js.map +1 -1
  7. package/dist/adapters/memory/index.d.ts.map +1 -1
  8. package/dist/adapters/memory/index.js +1281 -48
  9. package/dist/adapters/memory/index.js.map +1 -1
  10. package/dist/adapters/postgres/index.d.ts +1 -0
  11. package/dist/adapters/postgres/index.d.ts.map +1 -1
  12. package/dist/adapters/postgres/index.js +1770 -42
  13. package/dist/adapters/postgres/index.js.map +1 -1
  14. package/dist/adapters/sqlite/embeddings.d.ts.map +1 -1
  15. package/dist/adapters/sqlite/embeddings.js +49 -12
  16. package/dist/adapters/sqlite/embeddings.js.map +1 -1
  17. package/dist/adapters/sqlite/index.d.ts.map +1 -1
  18. package/dist/adapters/sqlite/index.js +1720 -38
  19. package/dist/adapters/sqlite/index.js.map +1 -1
  20. package/dist/adapters/sqlite/mappers.d.ts +39 -4
  21. package/dist/adapters/sqlite/mappers.d.ts.map +1 -1
  22. package/dist/adapters/sqlite/mappers.js +87 -0
  23. package/dist/adapters/sqlite/mappers.js.map +1 -1
  24. package/dist/adapters/sqlite/schema.d.ts +1 -1
  25. package/dist/adapters/sqlite/schema.d.ts.map +1 -1
  26. package/dist/adapters/sqlite/schema.js +297 -1
  27. package/dist/adapters/sqlite/schema.js.map +1 -1
  28. package/dist/adapters/sync-to-async.d.ts.map +1 -1
  29. package/dist/adapters/sync-to-async.js +54 -0
  30. package/dist/adapters/sync-to-async.js.map +1 -1
  31. package/dist/contracts/async-storage.d.ts +61 -1
  32. package/dist/contracts/async-storage.d.ts.map +1 -1
  33. package/dist/contracts/cognitive.d.ts +37 -0
  34. package/dist/contracts/cognitive.d.ts.map +1 -0
  35. package/dist/contracts/cognitive.js +24 -0
  36. package/dist/contracts/cognitive.js.map +1 -0
  37. package/dist/contracts/coordination.d.ts +101 -0
  38. package/dist/contracts/coordination.d.ts.map +1 -0
  39. package/dist/contracts/coordination.js +26 -0
  40. package/dist/contracts/coordination.js.map +1 -0
  41. package/dist/contracts/embedding.d.ts +1 -1
  42. package/dist/contracts/embedding.d.ts.map +1 -1
  43. package/dist/contracts/errors.d.ts +28 -0
  44. package/dist/contracts/errors.d.ts.map +1 -0
  45. package/dist/contracts/errors.js +41 -0
  46. package/dist/contracts/errors.js.map +1 -0
  47. package/dist/contracts/identity.d.ts +2 -0
  48. package/dist/contracts/identity.d.ts.map +1 -1
  49. package/dist/contracts/identity.js +26 -1
  50. package/dist/contracts/identity.js.map +1 -1
  51. package/dist/contracts/observability.d.ts +2 -1
  52. package/dist/contracts/observability.d.ts.map +1 -1
  53. package/dist/contracts/observability.js +11 -0
  54. package/dist/contracts/observability.js.map +1 -1
  55. package/dist/contracts/profile.d.ts +29 -0
  56. package/dist/contracts/profile.d.ts.map +1 -0
  57. package/dist/contracts/profile.js +2 -0
  58. package/dist/contracts/profile.js.map +1 -0
  59. package/dist/contracts/session-state.d.ts +10 -0
  60. package/dist/contracts/session-state.d.ts.map +1 -0
  61. package/dist/contracts/session-state.js +2 -0
  62. package/dist/contracts/session-state.js.map +1 -0
  63. package/dist/contracts/storage.d.ts +73 -1
  64. package/dist/contracts/storage.d.ts.map +1 -1
  65. package/dist/contracts/storage.js +16 -1
  66. package/dist/contracts/storage.js.map +1 -1
  67. package/dist/contracts/temporal.d.ts +112 -0
  68. package/dist/contracts/temporal.d.ts.map +1 -0
  69. package/dist/contracts/temporal.js +31 -0
  70. package/dist/contracts/temporal.js.map +1 -0
  71. package/dist/contracts/types.d.ts +135 -0
  72. package/dist/contracts/types.d.ts.map +1 -1
  73. package/dist/contracts/types.js +27 -0
  74. package/dist/contracts/types.js.map +1 -1
  75. package/dist/core/associations.d.ts +18 -0
  76. package/dist/core/associations.d.ts.map +1 -0
  77. package/dist/core/associations.js +185 -0
  78. package/dist/core/associations.js.map +1 -0
  79. package/dist/core/circuit-breaker.d.ts +9 -0
  80. package/dist/core/circuit-breaker.d.ts.map +1 -1
  81. package/dist/core/circuit-breaker.js +13 -1
  82. package/dist/core/circuit-breaker.js.map +1 -1
  83. package/dist/core/cognitive.d.ts +5 -0
  84. package/dist/core/cognitive.d.ts.map +1 -0
  85. package/dist/core/cognitive.js +120 -0
  86. package/dist/core/cognitive.js.map +1 -0
  87. package/dist/core/context.d.ts +72 -1
  88. package/dist/core/context.d.ts.map +1 -1
  89. package/dist/core/context.js +471 -45
  90. package/dist/core/context.js.map +1 -1
  91. package/dist/core/episodic.d.ts +28 -0
  92. package/dist/core/episodic.d.ts.map +1 -0
  93. package/dist/core/episodic.js +371 -0
  94. package/dist/core/episodic.js.map +1 -0
  95. package/dist/core/formatter.d.ts +4 -0
  96. package/dist/core/formatter.d.ts.map +1 -1
  97. package/dist/core/formatter.js +103 -0
  98. package/dist/core/formatter.js.map +1 -1
  99. package/dist/core/maintenance.d.ts +1 -0
  100. package/dist/core/maintenance.d.ts.map +1 -1
  101. package/dist/core/maintenance.js +75 -0
  102. package/dist/core/maintenance.js.map +1 -1
  103. package/dist/core/manager.d.ts +159 -7
  104. package/dist/core/manager.d.ts.map +1 -1
  105. package/dist/core/manager.js +740 -31
  106. package/dist/core/manager.js.map +1 -1
  107. package/dist/core/orchestrator.d.ts.map +1 -1
  108. package/dist/core/orchestrator.js +210 -178
  109. package/dist/core/orchestrator.js.map +1 -1
  110. package/dist/core/playbook.d.ts +35 -0
  111. package/dist/core/playbook.d.ts.map +1 -0
  112. package/dist/core/playbook.js +184 -0
  113. package/dist/core/playbook.js.map +1 -0
  114. package/dist/core/profile.d.ts +8 -0
  115. package/dist/core/profile.d.ts.map +1 -0
  116. package/dist/core/profile.js +103 -0
  117. package/dist/core/profile.js.map +1 -0
  118. package/dist/core/quick.d.ts +5 -0
  119. package/dist/core/quick.d.ts.map +1 -1
  120. package/dist/core/quick.js +10 -1
  121. package/dist/core/quick.js.map +1 -1
  122. package/dist/core/runtime.d.ts +17 -1
  123. package/dist/core/runtime.d.ts.map +1 -1
  124. package/dist/core/runtime.js +88 -5
  125. package/dist/core/runtime.js.map +1 -1
  126. package/dist/core/streaming.d.ts +1 -1
  127. package/dist/core/streaming.d.ts.map +1 -1
  128. package/dist/core/temporal.d.ts +29 -0
  129. package/dist/core/temporal.d.ts.map +1 -0
  130. package/dist/core/temporal.js +447 -0
  131. package/dist/core/temporal.js.map +1 -0
  132. package/dist/core/validation.d.ts +3 -0
  133. package/dist/core/validation.d.ts.map +1 -1
  134. package/dist/core/validation.js +25 -10
  135. package/dist/core/validation.js.map +1 -1
  136. package/dist/core/workspace-detect.d.ts +17 -0
  137. package/dist/core/workspace-detect.d.ts.map +1 -0
  138. package/dist/core/workspace-detect.js +55 -0
  139. package/dist/core/workspace-detect.js.map +1 -0
  140. package/dist/embeddings/resilience.d.ts.map +1 -1
  141. package/dist/embeddings/resilience.js +19 -8
  142. package/dist/embeddings/resilience.js.map +1 -1
  143. package/dist/index.d.ts +21 -4
  144. package/dist/index.d.ts.map +1 -1
  145. package/dist/index.js +9 -0
  146. package/dist/index.js.map +1 -1
  147. package/dist/integrations/claude-agent.d.ts +6 -0
  148. package/dist/integrations/claude-agent.d.ts.map +1 -1
  149. package/dist/integrations/claude-agent.js +5 -1
  150. package/dist/integrations/claude-agent.js.map +1 -1
  151. package/dist/integrations/claude-tools.d.ts +5 -4
  152. package/dist/integrations/claude-tools.d.ts.map +1 -1
  153. package/dist/integrations/claude-tools.js +155 -2
  154. package/dist/integrations/claude-tools.js.map +1 -1
  155. package/dist/integrations/middleware.d.ts +6 -0
  156. package/dist/integrations/middleware.d.ts.map +1 -1
  157. package/dist/integrations/middleware.js +11 -1
  158. package/dist/integrations/middleware.js.map +1 -1
  159. package/dist/integrations/openai-tools.d.ts +5 -4
  160. package/dist/integrations/openai-tools.d.ts.map +1 -1
  161. package/dist/integrations/openai-tools.js +170 -2
  162. package/dist/integrations/openai-tools.js.map +1 -1
  163. package/dist/integrations/vercel-ai.d.ts +6 -0
  164. package/dist/integrations/vercel-ai.d.ts.map +1 -1
  165. package/dist/integrations/vercel-ai.js +4 -0
  166. package/dist/integrations/vercel-ai.js.map +1 -1
  167. package/dist/server/http-server.d.ts +8 -0
  168. package/dist/server/http-server.d.ts.map +1 -1
  169. package/dist/server/http-server.js +976 -58
  170. package/dist/server/http-server.js.map +1 -1
  171. package/dist/server/mcp-server.d.ts +8 -0
  172. package/dist/server/mcp-server.d.ts.map +1 -1
  173. package/dist/server/mcp-server.js +1157 -37
  174. package/dist/server/mcp-server.js.map +1 -1
  175. package/dist/server/parsing.d.ts +12 -0
  176. package/dist/server/parsing.d.ts.map +1 -0
  177. package/dist/server/parsing.js +42 -0
  178. package/dist/server/parsing.js.map +1 -0
  179. package/dist/summarizers/prompts.d.ts +4 -0
  180. package/dist/summarizers/prompts.d.ts.map +1 -1
  181. package/dist/summarizers/prompts.js +42 -0
  182. package/dist/summarizers/prompts.js.map +1 -1
  183. package/docs/ULTIMATE_MEMORY_LAYER_ROADMAP.md +291 -0
  184. package/docs/prd.json +1498 -0
  185. package/openapi.yaml +1945 -112
  186. package/package.json +4 -2
@@ -3,6 +3,70 @@ import { DEFAULT_CONTEXT_POLICY } from '../contracts/policy.js';
3
3
  import { estimateTokens } from './tokens.js';
4
4
  import { emitMemoryEvent } from './telemetry.js';
5
5
  import { getLineageScore, rankKnowledge } from './retrieval.js';
6
+ const DEFAULT_MAX_ASSOCIATION_SEED_ITEMS = 8;
7
+ const DEFAULT_MAX_ASSOCIATED_KNOWLEDGE_ITEMS = 12;
8
+ const DEFAULT_RECENT_OUTPUT_LIMIT = 3;
9
+ const BLOCKER_PATTERN = /\b(blocked|blocker|waiting on|pending|stuck|cannot proceed|can't proceed)\b/i;
10
+ const ASSUMPTION_PATTERN = /\b(assume|assuming|assumption|likely|probably)\b/i;
11
+ const DECISION_PATTERN = /\b(decide|decision|choose|choice|whether|should we|need to determine)\b/i;
12
+ const TOOL_PATTERN = /\b(?:tool|command|script|query|search|fetch|deploy|build|test|lint|run)\b/i;
13
+ function matchesVisibility(visibilityClass, item, scope) {
14
+ const left = normalizeScope(item);
15
+ const right = normalizeScope(scope);
16
+ if (left.tenant_id !== right.tenant_id)
17
+ return false;
18
+ switch (visibilityClass) {
19
+ case 'tenant':
20
+ return true;
21
+ case 'workspace':
22
+ return left.workspace_id === right.workspace_id;
23
+ case 'shared_collaboration':
24
+ return (left.workspace_id === right.workspace_id &&
25
+ left.collaboration_id.length > 0 &&
26
+ left.collaboration_id === right.collaboration_id);
27
+ case 'private':
28
+ default:
29
+ return (left.system_id === right.system_id &&
30
+ left.workspace_id === right.workspace_id &&
31
+ left.collaboration_id === right.collaboration_id &&
32
+ left.scope_id === right.scope_id);
33
+ }
34
+ }
35
+ function isVisibilityAllowed(visibilityClass, item, scope, view) {
36
+ if (!matchesVisibility(visibilityClass, item, scope)) {
37
+ return false;
38
+ }
39
+ if (view === 'local_only') {
40
+ return visibilityClass === 'private';
41
+ }
42
+ if (view === 'local_plus_shared_collaboration') {
43
+ return visibilityClass === 'private' || visibilityClass === 'shared_collaboration';
44
+ }
45
+ if (view === 'workspace_shared') {
46
+ return (visibilityClass === 'private' ||
47
+ visibilityClass === 'shared_collaboration' ||
48
+ visibilityClass === 'workspace');
49
+ }
50
+ return (visibilityClass === 'private' ||
51
+ visibilityClass === 'shared_collaboration' ||
52
+ visibilityClass === 'workspace' ||
53
+ visibilityClass === 'tenant');
54
+ }
55
+ export function resolveVisibleKnowledge(items, scope, view) {
56
+ return items.filter((item) => isVisibilityAllowed(item.visibility_class, item, scope, view));
57
+ }
58
+ export function resolveVisibleWorkItems(items, scope, view) {
59
+ return items.filter((item) => isVisibilityAllowed(item.visibility_class, item, scope, view));
60
+ }
61
+ export function resolveVisiblePlaybooks(items, scope, view) {
62
+ return items.filter((item) => isVisibilityAllowed(item.visibility_class, item, scope, view));
63
+ }
64
+ export function resolveVisibleWorkClaims(items, scope, view) {
65
+ return items.filter((item) => isVisibilityAllowed(item.visibility_class, item, scope, view));
66
+ }
67
+ export function resolveVisibleHandoffs(items, scope, view) {
68
+ return items.filter((item) => isVisibilityAllowed(item.visibility_class, item, scope, view));
69
+ }
6
70
  function resolveContextPolicy(options) {
7
71
  const base = {
8
72
  ...DEFAULT_CONTEXT_POLICY,
@@ -82,7 +146,111 @@ function deriveUnresolvedWork(workingMemory, activeTurns, relevantKnowledge, wor
82
146
  }
83
147
  return [...unresolved];
84
148
  }
85
- function computeContextTokenEstimate(activeTurns, workingMemory, relevantKnowledge, recentSummaries, tokenEstimator = estimateTokens) {
149
+ function compactSnippet(text, maxLength = 160) {
150
+ const normalized = text.replace(/\s+/g, ' ').trim();
151
+ if (normalized.length <= maxLength)
152
+ return normalized;
153
+ return `${normalized.slice(0, maxLength - 3).trimEnd()}...`;
154
+ }
155
+ function collectSignalSnippets(values, pattern, limit = 4) {
156
+ const matches = new Set();
157
+ for (const value of values) {
158
+ if (matches.size >= limit)
159
+ break;
160
+ if (pattern.test(value)) {
161
+ matches.add(compactSnippet(value));
162
+ }
163
+ }
164
+ return [...matches];
165
+ }
166
+ function deriveSessionState(workingMemory, activeTurns, activeObjectives, contextWorkItems, recentSummaries, currentObjective) {
167
+ const recentTexts = [
168
+ ...activeTurns.slice(-6).map((turn) => turn.content),
169
+ workingMemory?.summary ?? '',
170
+ ...recentSummaries.slice(0, 2).map((summary) => summary.summary),
171
+ ].filter((value) => value.trim().length > 0);
172
+ const blockers = [
173
+ ...contextWorkItems
174
+ .filter((item) => item.status === 'blocked')
175
+ .map((item) => compactSnippet(item.title)),
176
+ ...collectSignalSnippets(recentTexts, BLOCKER_PATTERN),
177
+ ];
178
+ const assumptions = collectSignalSnippets(recentTexts, ASSUMPTION_PATTERN);
179
+ const pendingDecisions = [
180
+ ...collectSignalSnippets(recentTexts, DECISION_PATTERN),
181
+ ...activeObjectives
182
+ .filter((item) => DECISION_PATTERN.test(item.title))
183
+ .map((item) => compactSnippet(item.title)),
184
+ ];
185
+ const activeTools = [
186
+ ...new Set([
187
+ ...activeTurns
188
+ .map((turn) => turn.actor)
189
+ .filter((actor) => actor.length > 0 && !['user', 'assistant', 'system'].includes(actor)),
190
+ ...activeTurns
191
+ .filter((turn) => TOOL_PATTERN.test(turn.content))
192
+ .map((turn) => compactSnippet(turn.content, 80)),
193
+ ]),
194
+ ].slice(0, 6);
195
+ const recentOutputs = activeTurns
196
+ .filter((turn) => turn.role !== 'user')
197
+ .slice(-DEFAULT_RECENT_OUTPUT_LIMIT)
198
+ .map((turn) => compactSnippet(turn.content));
199
+ const updatedAt = Math.max(0, ...activeTurns.map((turn) => turn.created_at), ...contextWorkItems.map((item) => item.updated_at), ...(workingMemory ? [workingMemory.created_at] : []), ...recentSummaries.map((summary) => summary.created_at));
200
+ return {
201
+ currentObjective,
202
+ blockers: [...new Set(blockers)].slice(0, 6),
203
+ assumptions: [...new Set(assumptions)].slice(0, 6),
204
+ pendingDecisions: [...new Set(pendingDecisions)].slice(0, 6),
205
+ activeTools,
206
+ recentOutputs,
207
+ updatedAt,
208
+ };
209
+ }
210
+ export function buildDerivedShortTermState(input) {
211
+ const workingMemory = [...input.workingMemoryCandidates]
212
+ .sort((a, b) => b.id - a.id)[0] ?? null;
213
+ const recentSummaries = input.workingMemoryCandidates
214
+ .filter((summary) => summary.id !== workingMemory?.id)
215
+ .slice(0, input.maxRecentSummaries ?? DEFAULT_CONTEXT_POLICY.maxRecentSummaries);
216
+ const activeObjectives = input.contextWorkItems.filter((item) => item.kind === 'objective');
217
+ const currentObjective = deriveCurrentObjective(workingMemory, input.activeTurns);
218
+ return {
219
+ workingMemory,
220
+ recentSummaries,
221
+ activeObjectives,
222
+ currentObjective,
223
+ activeState: deriveActiveState(workingMemory, input.activeTurns),
224
+ // The session-state projection intentionally computes a fast-resume subset
225
+ // even when relevantKnowledge is omitted by projection refresh.
226
+ unresolvedWork: deriveUnresolvedWork(workingMemory, input.activeTurns, input.relevantKnowledge ?? [], input.contextWorkItems),
227
+ sessionState: deriveSessionState(workingMemory, input.activeTurns, activeObjectives, input.contextWorkItems, recentSummaries, currentObjective),
228
+ };
229
+ }
230
+ function isWorkItemActiveAt(item, asOf) {
231
+ return item.created_at <= asOf && !(item.status === 'done' && item.updated_at <= asOf);
232
+ }
233
+ export async function getContextWorkItems(adapter, scope, asOf, level) {
234
+ if (asOf == null) {
235
+ return level && level !== 'scope'
236
+ ? adapter.getActiveWorkItemsCrossScope(scope, level)
237
+ : adapter.getActiveWorkItems(scope);
238
+ }
239
+ const workItems = level && level !== 'scope'
240
+ ? await adapter.getWorkItemsByTimeRangeCrossScope(scope, level, { end_at: asOf })
241
+ : await adapter.getWorkItemsByTimeRange(scope, { end_at: asOf });
242
+ return workItems
243
+ .filter((item) => isWorkItemActiveAt(item, asOf))
244
+ .sort((a, b) => b.updated_at - a.updated_at || b.created_at - a.created_at || b.id - a.id);
245
+ }
246
+ export function resolveContextScopeLevel(crossScopeLevel, view) {
247
+ if (view === 'operator_supervisor')
248
+ return crossScopeLevel ?? 'tenant';
249
+ if (view && view !== 'local_only')
250
+ return crossScopeLevel ?? 'workspace';
251
+ return crossScopeLevel;
252
+ }
253
+ function computeContextTokenEstimate(activeTurns, workingMemory, relevantKnowledge, recentSummaries, tokenEstimator = estimateTokens, playbooks = [], associatedKnowledge = []) {
86
254
  const turnTokens = activeTurns.reduce((acc, turn) => acc + turn.token_estimate, 0);
87
255
  const workingTokens = workingMemory
88
256
  ? tokenEstimator(workingMemory.summary) +
@@ -91,7 +259,9 @@ function computeContextTokenEstimate(activeTurns, workingMemory, relevantKnowled
91
259
  : 0;
92
260
  const knowledgeTokens = relevantKnowledge.reduce((acc, knowledge) => acc + tokenEstimator(knowledge.fact), 0);
93
261
  const summaryTokens = recentSummaries.reduce((acc, summary) => acc + tokenEstimator(summary.summary), 0);
94
- return turnTokens + workingTokens + knowledgeTokens + summaryTokens;
262
+ const playbookTokens = playbooks.reduce((acc, pb) => acc + tokenEstimator(pb.title) + tokenEstimator(pb.description) + tokenEstimator(pb.instructions), 0);
263
+ const associatedTokens = associatedKnowledge.reduce((acc, knowledge) => acc + tokenEstimator(knowledge.fact), 0);
264
+ return turnTokens + workingTokens + knowledgeTokens + summaryTokens + playbookTokens + associatedTokens;
95
265
  }
96
266
  function dropLowestPriorityTurn(activeTurns) {
97
267
  if (activeTurns.length === 0)
@@ -208,26 +378,33 @@ export async function buildMemoryContext(adapter, scope, options) {
208
378
  const policy = resolveContextPolicy(options);
209
379
  const tokenEstimator = options?.tokenEstimator ?? estimateTokens;
210
380
  const asOf = options?.asOf;
381
+ const view = options?.view;
382
+ const effectiveScopeLevel = resolveContextScopeLevel(options?.crossScopeLevel, view);
211
383
  let activeTurns = await adapter.getActiveTurns(normalizedScope, options?.sessionId);
212
384
  if (asOf != null) {
213
385
  activeTurns = activeTurns.filter((turn) => turn.created_at <= asOf);
214
386
  }
215
- const activeObjectives = (await adapter.getActiveWorkItems(normalizedScope)).filter((item) => item.kind === 'objective');
387
+ const contextWorkItems = view
388
+ ? resolveVisibleWorkItems(await getContextWorkItems(adapter, normalizedScope, asOf, effectiveScopeLevel), normalizedScope, view)
389
+ : await getContextWorkItems(adapter, normalizedScope, asOf, effectiveScopeLevel);
216
390
  const workingMemoryCandidates = await adapter.getActiveWorkingMemory(normalizedScope, options?.sessionId);
217
- const workingMemory = [...workingMemoryCandidates]
218
- .filter((item) => asOf == null || item.created_at <= asOf)
219
- .sort((a, b) => b.id - a.id)[0] ?? null;
220
391
  const allWorkingMemory = workingMemoryCandidates.filter((item) => asOf == null || item.created_at <= asOf);
221
- const recentSummaries = allWorkingMemory
222
- .filter((summary) => summary.id !== workingMemory?.id)
223
- .slice(0, policy.maxRecentSummaries);
224
- const activeKnowledge = options?.crossScopeLevel
225
- ? await adapter.getActiveKnowledgeCrossScope(normalizedScope, options.crossScopeLevel)
392
+ const initialShortTermState = buildDerivedShortTermState({
393
+ activeTurns,
394
+ workingMemoryCandidates: allWorkingMemory,
395
+ contextWorkItems,
396
+ maxRecentSummaries: policy.maxRecentSummaries,
397
+ });
398
+ const { activeObjectives, currentObjective, recentSummaries, workingMemory, } = initialShortTermState;
399
+ const activeKnowledge = effectiveScopeLevel && effectiveScopeLevel !== 'scope'
400
+ ? await adapter.getActiveKnowledgeCrossScope(normalizedScope, effectiveScopeLevel)
226
401
  : await adapter.getActiveKnowledgeMemory(normalizedScope);
227
- const temporalKnowledge = activeKnowledge.filter((item) => asOf == null || item.created_at <= asOf);
402
+ const temporalKnowledge = view
403
+ ? resolveVisibleKnowledge(activeKnowledge.filter((item) => asOf == null || item.created_at <= asOf), normalizedScope, view)
404
+ : activeKnowledge.filter((item) => asOf == null || item.created_at <= asOf);
228
405
  const lexicalRanks = options?.relevanceQuery
229
- ? normalizeLexicalRanks(options.crossScopeLevel
230
- ? await adapter.searchKnowledgeCrossScope(normalizedScope, options.crossScopeLevel, options.relevanceQuery, {
406
+ ? normalizeLexicalRanks(effectiveScopeLevel && effectiveScopeLevel !== 'scope'
407
+ ? await adapter.searchKnowledgeCrossScope(normalizedScope, effectiveScopeLevel, options.relevanceQuery, {
231
408
  limit: policy.maxKnowledgeItems * 2,
232
409
  activeOnly: true,
233
410
  })
@@ -239,8 +416,8 @@ export async function buildMemoryContext(adapter, scope, options) {
239
416
  let semanticRanks = new Map();
240
417
  if (options?.embeddingAdapter && options.queryVector) {
241
418
  try {
242
- const semanticResults = options.crossScopeLevel
243
- ? await options.embeddingAdapter.findSimilarCrossScope(normalizedScope, options.crossScopeLevel, options.queryVector, {
419
+ const semanticResults = effectiveScopeLevel && effectiveScopeLevel !== 'scope'
420
+ ? await options.embeddingAdapter.findSimilarCrossScope(normalizedScope, effectiveScopeLevel, options.queryVector, {
244
421
  limit: policy.maxKnowledgeItems * 2,
245
422
  minSimilarity: policy.semanticMinSimilarity,
246
423
  })
@@ -256,60 +433,300 @@ export async function buildMemoryContext(adapter, scope, options) {
256
433
  });
257
434
  }
258
435
  }
259
- const scopedKnowledge = options?.crossScopeLevel && options.crossScopeLevel !== 'scope'
260
- ? temporalKnowledge.filter((item) => item.scope_id === normalizedScope.scope_id ||
261
- (normalizedScope.collaboration_id.length > 0 &&
262
- item.collaboration_id === normalizedScope.collaboration_id) ||
263
- getLineageScore(normalizedScope.scope_id, item.scope_id) >= policy.minimumLineageScore)
264
- : temporalKnowledge;
436
+ const scopedKnowledge = view && view !== 'local_only'
437
+ ? temporalKnowledge
438
+ : effectiveScopeLevel && effectiveScopeLevel !== 'scope'
439
+ ? temporalKnowledge.filter((item) => item.scope_id === normalizedScope.scope_id ||
440
+ (normalizedScope.collaboration_id.length > 0 &&
441
+ item.collaboration_id === normalizedScope.collaboration_id) ||
442
+ getLineageScore(normalizedScope.scope_id, item.scope_id) >= policy.minimumLineageScore)
443
+ : temporalKnowledge;
265
444
  const relevanceTexts = [
266
445
  options?.relevanceQuery ?? '',
267
446
  workingMemory?.summary ?? '',
268
447
  ...activeObjectives.map((item) => item.title),
269
448
  ].filter((value) => value.trim().length > 0);
270
- const candidates = buildCandidates(scopedKnowledge, lexicalRanks, semanticRanks, policy, normalizedScope, relevanceTexts, options?.crossScopeLevel != null && options.crossScopeLevel !== 'scope');
449
+ const candidates = buildCandidates(scopedKnowledge, lexicalRanks, semanticRanks, policy, normalizedScope, relevanceTexts, effectiveScopeLevel != null && effectiveScopeLevel !== 'scope');
271
450
  const trustedCoreClasses = new Set(['identity', 'constraint', 'preference']);
272
- let trustedCoreMemory = selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'trusted' &&
273
- trustedCoreClasses.has(candidate.item.knowledge_class)), policy, 'trusted_core', Math.min(policy.trustedCoreLimit, Math.max(3, Math.floor(policy.maxKnowledgeItems / 2)))).relevantKnowledge;
451
+ const trustedCoreSelection = selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'trusted' &&
452
+ trustedCoreClasses.has(candidate.item.knowledge_class)), policy, 'trusted_core', Math.min(policy.trustedCoreLimit, Math.max(3, Math.floor(policy.maxKnowledgeItems / 2))));
453
+ let trustedCoreMemory = trustedCoreSelection.relevantKnowledge;
274
454
  const trustedCoreIds = new Set(trustedCoreMemory.map((item) => item.id));
275
- let taskRelevantKnowledge = selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'trusted' && !trustedCoreIds.has(candidate.item.id)), policy, 'task_relevant', Math.min(policy.taskRelevantLimit, Math.max(0, policy.maxKnowledgeItems - trustedCoreMemory.length))).relevantKnowledge;
276
- const provisionalKnowledge = selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'provisional'), policy, 'provisional', 4).relevantKnowledge;
277
- const disputedKnowledge = selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'disputed'), policy, 'disputed', 4).relevantKnowledge;
455
+ const taskRelevantSelection = selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'trusted' && !trustedCoreIds.has(candidate.item.id)), policy, 'task_relevant', Math.min(policy.taskRelevantLimit, Math.max(0, policy.maxKnowledgeItems - trustedCoreMemory.length)));
456
+ let taskRelevantKnowledge = taskRelevantSelection.relevantKnowledge;
457
+ const provisionalSelection = selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'provisional'), policy, 'provisional', 4);
458
+ const provisionalKnowledge = provisionalSelection.relevantKnowledge;
459
+ const disputedSelection = selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'disputed'), policy, 'disputed', 4);
460
+ const disputedKnowledge = disputedSelection.relevantKnowledge;
278
461
  let relevantKnowledge = [...trustedCoreMemory, ...taskRelevantKnowledge];
279
462
  let knowledgeSelectionReasons = [
280
- ...selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'trusted' &&
281
- trustedCoreClasses.has(candidate.item.knowledge_class)), policy, 'trusted_core', trustedCoreMemory.length).knowledgeSelectionReasons,
282
- ...selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'trusted' && !trustedCoreIds.has(candidate.item.id)), policy, 'task_relevant', taskRelevantKnowledge.length).knowledgeSelectionReasons,
283
- ...selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'provisional'), policy, 'provisional', provisionalKnowledge.length).knowledgeSelectionReasons,
284
- ...selectKnowledge(candidates.filter((candidate) => candidate.item.knowledge_state === 'disputed'), policy, 'disputed', disputedKnowledge.length).knowledgeSelectionReasons,
463
+ ...trustedCoreSelection.knowledgeSelectionReasons,
464
+ ...taskRelevantSelection.knowledgeSelectionReasons,
465
+ ...provisionalSelection.knowledgeSelectionReasons,
466
+ ...disputedSelection.knowledgeSelectionReasons,
285
467
  ];
468
+ const initiallySelectedIds = new Set(relevantKnowledge.map((item) => item.id));
469
+ const excludedKnowledge = candidates
470
+ .filter((candidate) => !initiallySelectedIds.has(candidate.item.id))
471
+ .map((candidate) => ({
472
+ knowledgeMemoryId: candidate.item.id,
473
+ reason: 'not_selected',
474
+ detail: `excluded:${candidate.item.knowledge_state}:${candidate.item.knowledge_class}`,
475
+ }));
476
+ const scopedKnowledgeById = new Map(scopedKnowledge.map((item) => [item.id, item]));
477
+ let relevantPlaybooks = options?.relevanceQuery
478
+ ? (effectiveScopeLevel && effectiveScopeLevel !== 'scope'
479
+ ? await adapter.searchPlaybooksCrossScope(normalizedScope, effectiveScopeLevel, options.relevanceQuery, { limit: 3, activeOnly: true })
480
+ : await adapter.searchPlaybooks(normalizedScope, options.relevanceQuery, {
481
+ limit: 3,
482
+ activeOnly: true,
483
+ })).map((hit) => hit.item)
484
+ : [];
485
+ relevantPlaybooks = view
486
+ ? resolveVisiblePlaybooks(relevantPlaybooks, normalizedScope, view)
487
+ : relevantPlaybooks;
488
+ // Single-hop association expansion via supports + related_to edges
489
+ const associationMinConfidence = options?.associationMinConfidence ?? 0.3;
490
+ const maxAssociationSeedItems = options?.maxAssociationSeedItems ?? DEFAULT_MAX_ASSOCIATION_SEED_ITEMS;
491
+ const maxAssociatedKnowledgeItems = options?.maxAssociatedKnowledgeItems ?? DEFAULT_MAX_ASSOCIATED_KNOWLEDGE_ITEMS;
492
+ const selectedIds = new Set(relevantKnowledge.map((k) => k.id));
493
+ const associatedKnowledge = [];
494
+ const associationTrace = {
495
+ seedKnowledgeIds: relevantKnowledge.slice(0, maxAssociationSeedItems).map((knowledge) => knowledge.id),
496
+ candidateKnowledgeIds: [],
497
+ includedKnowledgeIds: [],
498
+ truncatedKnowledgeIds: [],
499
+ maxSeedKnowledgeItems: maxAssociationSeedItems,
500
+ maxAssociatedKnowledgeItems,
501
+ };
502
+ if (relevantKnowledge.length > 0) {
503
+ const associationSeeds = relevantKnowledge.slice(0, maxAssociationSeedItems);
504
+ const associationResults = await Promise.all(associationSeeds.map(async (knowledge) => {
505
+ const associationScope = normalizeScope(knowledge);
506
+ const [from, to] = await Promise.all([
507
+ adapter.getAssociationsFrom('knowledge', knowledge.id, associationScope),
508
+ adapter.getAssociationsTo('knowledge', knowledge.id, associationScope),
509
+ ]);
510
+ return { from, to };
511
+ }));
512
+ const expandScores = new Map();
513
+ // Outbound: current node is source, neighbor is target
514
+ for (const { from: assocs } of associationResults) {
515
+ for (const a of assocs) {
516
+ if ((a.association_type === 'supports' || a.association_type === 'related_to') &&
517
+ a.target_kind === 'knowledge' &&
518
+ a.confidence >= associationMinConfidence &&
519
+ !selectedIds.has(a.target_id)) {
520
+ expandScores.set(a.target_id, Math.max(expandScores.get(a.target_id) ?? 0, a.confidence));
521
+ }
522
+ }
523
+ }
524
+ // Inbound: current node is target, neighbor is source
525
+ for (const { to: assocs } of associationResults) {
526
+ for (const a of assocs) {
527
+ if ((a.association_type === 'supports' || a.association_type === 'related_to') &&
528
+ a.source_kind === 'knowledge' &&
529
+ a.confidence >= associationMinConfidence &&
530
+ !selectedIds.has(a.source_id)) {
531
+ expandScores.set(a.source_id, Math.max(expandScores.get(a.source_id) ?? 0, a.confidence));
532
+ }
533
+ }
534
+ }
535
+ const candidateAssociationIds = [...expandScores.entries()]
536
+ .sort((a, b) => b[1] - a[1] || a[0] - b[0])
537
+ .map(([id]) => id);
538
+ associationTrace.candidateKnowledgeIds = candidateAssociationIds;
539
+ if (candidateAssociationIds.length > maxAssociatedKnowledgeItems) {
540
+ associationTrace.truncatedKnowledgeIds = candidateAssociationIds.slice(maxAssociatedKnowledgeItems);
541
+ }
542
+ for (const targetId of candidateAssociationIds.slice(0, maxAssociatedKnowledgeItems)) {
543
+ const knowledge = scopedKnowledgeById.get(targetId);
544
+ if (knowledge && knowledge.knowledge_state !== 'retired' && knowledge.knowledge_state !== 'superseded') {
545
+ associatedKnowledge.push(knowledge);
546
+ }
547
+ }
548
+ associationTrace.includedKnowledgeIds = associatedKnowledge.map((knowledge) => knowledge.id);
549
+ }
286
550
  let trimmedSummaries = [...recentSummaries];
287
- let tokenEstimate = computeContextTokenEstimate(activeTurns, workingMemory, relevantKnowledge, trimmedSummaries, tokenEstimator);
551
+ let trimmedAssociated = [...associatedKnowledge];
552
+ const tokenTrimTrace = {
553
+ initialTokenEstimate: 0,
554
+ finalTokenEstimate: 0,
555
+ droppedTurnIds: [],
556
+ droppedSummaryIds: [],
557
+ droppedPlaybookIds: [],
558
+ droppedAssociatedKnowledgeIds: [],
559
+ droppedKnowledgeIds: [],
560
+ };
561
+ function recomputeTokens() {
562
+ return computeContextTokenEstimate(activeTurns, workingMemory, relevantKnowledge, trimmedSummaries, tokenEstimator, relevantPlaybooks, trimmedAssociated);
563
+ }
564
+ let tokenEstimate = recomputeTokens();
565
+ tokenTrimTrace.initialTokenEstimate = tokenEstimate;
288
566
  while (tokenEstimate > policy.tokenBudget && activeTurns.length > 0) {
567
+ const beforeIds = new Set(activeTurns.map((turn) => turn.id));
289
568
  activeTurns = dropLowestPriorityTurn(activeTurns);
290
- tokenEstimate = computeContextTokenEstimate(activeTurns, workingMemory, relevantKnowledge, trimmedSummaries, tokenEstimator);
569
+ const afterIds = new Set(activeTurns.map((turn) => turn.id));
570
+ for (const id of beforeIds) {
571
+ if (!afterIds.has(id)) {
572
+ tokenTrimTrace.droppedTurnIds.push(id);
573
+ }
574
+ }
575
+ tokenEstimate = recomputeTokens();
291
576
  }
292
577
  while (tokenEstimate > policy.tokenBudget && trimmedSummaries.length > 0) {
578
+ const removed = trimmedSummaries[trimmedSummaries.length - 1];
579
+ if (removed)
580
+ tokenTrimTrace.droppedSummaryIds.push(removed.id);
293
581
  trimmedSummaries = trimmedSummaries.slice(0, -1);
294
- tokenEstimate = computeContextTokenEstimate(activeTurns, workingMemory, relevantKnowledge, trimmedSummaries, tokenEstimator);
582
+ tokenEstimate = recomputeTokens();
583
+ }
584
+ // Trim playbooks (procedural guidance) before associated knowledge or core
585
+ // relevant knowledge. A few large playbooks can otherwise push the context
586
+ // over budget after every other lower-priority category has been trimmed.
587
+ // Drop the largest playbook first so we shed bytes aggressively rather
588
+ // than dropping smaller playbooks that may still be useful alongside a
589
+ // single outsized offender.
590
+ while (tokenEstimate > policy.tokenBudget && relevantPlaybooks.length > 0) {
591
+ const sizes = relevantPlaybooks.map((pb) => tokenEstimator(`${pb.title}\n${pb.description}\n${pb.instructions}`));
592
+ let worstIdx = 0;
593
+ for (let i = 1; i < sizes.length; i++) {
594
+ if (sizes[i] > sizes[worstIdx])
595
+ worstIdx = i;
596
+ }
597
+ const removed = relevantPlaybooks[worstIdx];
598
+ if (removed)
599
+ tokenTrimTrace.droppedPlaybookIds.push(removed.id);
600
+ relevantPlaybooks = relevantPlaybooks.filter((_, i) => i !== worstIdx);
601
+ tokenEstimate = recomputeTokens();
602
+ }
603
+ // Trim associated knowledge before core relevant knowledge
604
+ while (tokenEstimate > policy.tokenBudget && trimmedAssociated.length > 0) {
605
+ const removed = trimmedAssociated[trimmedAssociated.length - 1];
606
+ if (removed)
607
+ tokenTrimTrace.droppedAssociatedKnowledgeIds.push(removed.id);
608
+ trimmedAssociated = trimmedAssociated.slice(0, -1);
609
+ tokenEstimate = recomputeTokens();
295
610
  }
296
611
  while (tokenEstimate > policy.tokenBudget && relevantKnowledge.length > 0) {
612
+ const removed = relevantKnowledge[relevantKnowledge.length - 1];
613
+ if (removed) {
614
+ tokenTrimTrace.droppedKnowledgeIds.push(removed.id);
615
+ excludedKnowledge.push({
616
+ knowledgeMemoryId: removed.id,
617
+ reason: 'token_budget',
618
+ detail: 'trimmed:token_budget',
619
+ });
620
+ }
297
621
  relevantKnowledge = relevantKnowledge.slice(0, -1);
298
622
  trustedCoreMemory = trustedCoreMemory.filter((item) => relevantKnowledge.some((entry) => entry.id === item.id));
299
623
  taskRelevantKnowledge = taskRelevantKnowledge.filter((item) => relevantKnowledge.some((entry) => entry.id === item.id));
300
624
  const retainedIds = new Set(relevantKnowledge.map((item) => item.id));
301
625
  knowledgeSelectionReasons = knowledgeSelectionReasons.filter((entry) => retainedIds.has(entry.knowledgeMemoryId));
302
- tokenEstimate = computeContextTokenEstimate(activeTurns, workingMemory, relevantKnowledge, trimmedSummaries, tokenEstimator);
626
+ tokenEstimate = recomputeTokens();
303
627
  }
628
+ tokenTrimTrace.finalTokenEstimate = tokenEstimate;
304
629
  if (policy.touchSelectedKnowledge) {
305
- for (const knowledge of relevantKnowledge) {
306
- await adapter.touchKnowledgeMemory(knowledge.id);
307
- }
630
+ await adapter.touchKnowledgeMemories(relevantKnowledge.map((knowledge) => knowledge.id));
308
631
  }
309
- const currentObjective = deriveCurrentObjective(workingMemory, activeTurns);
310
- const activeState = deriveActiveState(workingMemory, activeTurns);
311
- const allWorkItems = await adapter.getActiveWorkItems(normalizedScope);
312
- const unresolvedWork = deriveUnresolvedWork(workingMemory, activeTurns, relevantKnowledge, allWorkItems);
632
+ const rawWorkClaims = options?.includeCoordinationState || view
633
+ ? await (effectiveScopeLevel && effectiveScopeLevel !== 'scope'
634
+ ? adapter.listWorkClaimsCrossScope(normalizedScope, effectiveScopeLevel, {
635
+ actor: options?.viewer
636
+ ? {
637
+ actor_kind: options.viewer.actor_kind,
638
+ actor_id: options.viewer.actor_id,
639
+ }
640
+ : undefined,
641
+ })
642
+ : adapter.listWorkClaims(normalizedScope, {
643
+ actor: options?.viewer
644
+ ? {
645
+ actor_kind: options.viewer.actor_kind,
646
+ actor_id: options.viewer.actor_id,
647
+ }
648
+ : undefined,
649
+ }))
650
+ : [];
651
+ const workClaims = view
652
+ ? resolveVisibleWorkClaims(rawWorkClaims, normalizedScope, view)
653
+ : rawWorkClaims;
654
+ const rawHandoffs = options?.includeCoordinationState || view
655
+ ? await (effectiveScopeLevel && effectiveScopeLevel !== 'scope'
656
+ ? adapter.listHandoffsCrossScope(normalizedScope, effectiveScopeLevel, {
657
+ actor: options?.viewer
658
+ ? {
659
+ actor_kind: options.viewer.actor_kind,
660
+ actor_id: options.viewer.actor_id,
661
+ }
662
+ : undefined,
663
+ })
664
+ : adapter.listHandoffs(normalizedScope, {
665
+ actor: options?.viewer
666
+ ? {
667
+ actor_kind: options.viewer.actor_kind,
668
+ actor_id: options.viewer.actor_id,
669
+ }
670
+ : undefined,
671
+ }))
672
+ : [];
673
+ const handoffs = view ? resolveVisibleHandoffs(rawHandoffs, normalizedScope, view) : rawHandoffs;
674
+ const coordinationState = options?.includeCoordinationState || view
675
+ ? {
676
+ ownedClaims: options?.viewer
677
+ ? workClaims.filter((claim) => claim.actor.actor_kind === options.viewer.actor_kind &&
678
+ claim.actor.actor_id === options.viewer.actor_id &&
679
+ claim.status === 'active')
680
+ : [],
681
+ pendingInboundHandoffs: options?.viewer
682
+ ? handoffs.filter((handoff) => handoff.status === 'pending' &&
683
+ handoff.to_actor.actor_kind === options.viewer.actor_kind &&
684
+ handoff.to_actor.actor_id === options.viewer.actor_id)
685
+ : [],
686
+ pendingOutboundHandoffs: options?.viewer
687
+ ? handoffs.filter((handoff) => handoff.status === 'pending' &&
688
+ handoff.from_actor.actor_kind === options.viewer.actor_kind &&
689
+ handoff.from_actor.actor_id === options.viewer.actor_id)
690
+ : [],
691
+ sharedWorkItems: contextWorkItems.filter((item) => item.visibility_class !== 'private'),
692
+ }
693
+ : null;
694
+ const shortTermState = buildDerivedShortTermState({
695
+ activeTurns,
696
+ workingMemoryCandidates: allWorkingMemory,
697
+ contextWorkItems,
698
+ relevantKnowledge,
699
+ maxRecentSummaries: policy.maxRecentSummaries,
700
+ });
701
+ const { activeState, sessionState: derivedSessionState, unresolvedWork, } = shortTermState;
702
+ const projectedSessionState = asOf == null && options?.sessionId
703
+ ? await adapter.getSessionState(normalizedScope, options.sessionId)
704
+ : null;
705
+ const sessionState = projectedSessionState && projectedSessionState.updatedAt >= derivedSessionState.updatedAt
706
+ ? {
707
+ currentObjective: projectedSessionState.currentObjective,
708
+ blockers: projectedSessionState.blockers,
709
+ assumptions: projectedSessionState.assumptions,
710
+ pendingDecisions: projectedSessionState.pendingDecisions,
711
+ activeTools: projectedSessionState.activeTools,
712
+ recentOutputs: projectedSessionState.recentOutputs,
713
+ updatedAt: projectedSessionState.updatedAt,
714
+ }
715
+ : derivedSessionState;
716
+ const debugTrace = {
717
+ scope: {
718
+ normalizedScope,
719
+ scopeSource: effectiveScopeLevel != null && effectiveScopeLevel !== 'scope'
720
+ ? 'cross_scope'
721
+ : 'local',
722
+ scopeLevel: effectiveScopeLevel ?? 'scope',
723
+ asOf: asOf ?? null,
724
+ },
725
+ selectedKnowledge: knowledgeSelectionReasons,
726
+ excludedKnowledge,
727
+ associationExpansion: associationTrace,
728
+ tokenTrimming: tokenTrimTrace,
729
+ };
313
730
  emitMemoryEvent('context_assembly', normalizedScope, options, Date.now() - startedAt, {
314
731
  mode: policy.mode,
315
732
  activeTurnCount: activeTurns.length,
@@ -318,10 +735,14 @@ export async function buildMemoryContext(adapter, scope, options) {
318
735
  recentSummaryCount: trimmedSummaries.length,
319
736
  tokenEstimate,
320
737
  relevanceQuery: options?.relevanceQuery ?? null,
321
- crossScopeLevel: options?.crossScopeLevel ?? 'scope',
738
+ crossScopeLevel: effectiveScopeLevel ?? 'scope',
322
739
  currentObjective,
323
740
  unresolvedWorkCount: unresolvedWork.length,
741
+ sessionState,
324
742
  selectionReasons: knowledgeSelectionReasons,
743
+ excludedKnowledgeCount: excludedKnowledge.length,
744
+ associationExpansion: associationTrace,
745
+ tokenTrimming: tokenTrimTrace,
325
746
  });
326
747
  return {
327
748
  mode: policy.mode,
@@ -335,10 +756,15 @@ export async function buildMemoryContext(adapter, scope, options) {
335
756
  durableKnowledge: trustedCoreMemory,
336
757
  recentSummaries: trimmedSummaries,
337
758
  currentObjective,
759
+ sessionState,
338
760
  activeObjectives,
339
761
  activeState,
762
+ coordinationState,
763
+ relevantPlaybooks,
764
+ associatedKnowledge: trimmedAssociated,
340
765
  unresolvedWork,
341
766
  knowledgeSelectionReasons,
767
+ debugTrace,
342
768
  tokenEstimate,
343
769
  };
344
770
  }