@animus-labs/cortex 0.2.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 (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/budget-guard.d.ts +75 -0
  4. package/dist/budget-guard.d.ts.map +1 -0
  5. package/dist/budget-guard.js +142 -0
  6. package/dist/budget-guard.js.map +1 -0
  7. package/dist/compaction/compaction.d.ts +99 -0
  8. package/dist/compaction/compaction.d.ts.map +1 -0
  9. package/dist/compaction/compaction.js +302 -0
  10. package/dist/compaction/compaction.js.map +1 -0
  11. package/dist/compaction/failsafe.d.ts +57 -0
  12. package/dist/compaction/failsafe.d.ts.map +1 -0
  13. package/dist/compaction/failsafe.js +135 -0
  14. package/dist/compaction/failsafe.js.map +1 -0
  15. package/dist/compaction/index.d.ts +381 -0
  16. package/dist/compaction/index.d.ts.map +1 -0
  17. package/dist/compaction/index.js +979 -0
  18. package/dist/compaction/index.js.map +1 -0
  19. package/dist/compaction/microcompaction.d.ts +219 -0
  20. package/dist/compaction/microcompaction.d.ts.map +1 -0
  21. package/dist/compaction/microcompaction.js +536 -0
  22. package/dist/compaction/microcompaction.js.map +1 -0
  23. package/dist/compaction/observational/buffering.d.ts +225 -0
  24. package/dist/compaction/observational/buffering.d.ts.map +1 -0
  25. package/dist/compaction/observational/buffering.js +354 -0
  26. package/dist/compaction/observational/buffering.js.map +1 -0
  27. package/dist/compaction/observational/constants.d.ts +70 -0
  28. package/dist/compaction/observational/constants.d.ts.map +1 -0
  29. package/dist/compaction/observational/constants.js +507 -0
  30. package/dist/compaction/observational/constants.js.map +1 -0
  31. package/dist/compaction/observational/index.d.ts +219 -0
  32. package/dist/compaction/observational/index.d.ts.map +1 -0
  33. package/dist/compaction/observational/index.js +641 -0
  34. package/dist/compaction/observational/index.js.map +1 -0
  35. package/dist/compaction/observational/observer.d.ts +97 -0
  36. package/dist/compaction/observational/observer.d.ts.map +1 -0
  37. package/dist/compaction/observational/observer.js +424 -0
  38. package/dist/compaction/observational/observer.js.map +1 -0
  39. package/dist/compaction/observational/recall-tool.d.ts +27 -0
  40. package/dist/compaction/observational/recall-tool.d.ts.map +1 -0
  41. package/dist/compaction/observational/recall-tool.js +93 -0
  42. package/dist/compaction/observational/recall-tool.js.map +1 -0
  43. package/dist/compaction/observational/reflector.d.ts +94 -0
  44. package/dist/compaction/observational/reflector.d.ts.map +1 -0
  45. package/dist/compaction/observational/reflector.js +167 -0
  46. package/dist/compaction/observational/reflector.js.map +1 -0
  47. package/dist/compaction/observational/types.d.ts +271 -0
  48. package/dist/compaction/observational/types.d.ts.map +1 -0
  49. package/dist/compaction/observational/types.js +15 -0
  50. package/dist/compaction/observational/types.js.map +1 -0
  51. package/dist/context-manager.d.ts +134 -0
  52. package/dist/context-manager.d.ts.map +1 -0
  53. package/dist/context-manager.js +170 -0
  54. package/dist/context-manager.js.map +1 -0
  55. package/dist/cortex-agent.d.ts +1020 -0
  56. package/dist/cortex-agent.d.ts.map +1 -0
  57. package/dist/cortex-agent.js +3589 -0
  58. package/dist/cortex-agent.js.map +1 -0
  59. package/dist/error-classifier.d.ts +48 -0
  60. package/dist/error-classifier.d.ts.map +1 -0
  61. package/dist/error-classifier.js +152 -0
  62. package/dist/error-classifier.js.map +1 -0
  63. package/dist/event-bridge.d.ts +166 -0
  64. package/dist/event-bridge.d.ts.map +1 -0
  65. package/dist/event-bridge.js +381 -0
  66. package/dist/event-bridge.js.map +1 -0
  67. package/dist/index.d.ts +55 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +57 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/mcp-client.d.ts +119 -0
  72. package/dist/mcp-client.d.ts.map +1 -0
  73. package/dist/mcp-client.js +474 -0
  74. package/dist/mcp-client.js.map +1 -0
  75. package/dist/model-wrapper.d.ts +58 -0
  76. package/dist/model-wrapper.d.ts.map +1 -0
  77. package/dist/model-wrapper.js +86 -0
  78. package/dist/model-wrapper.js.map +1 -0
  79. package/dist/noop-logger.d.ts +4 -0
  80. package/dist/noop-logger.d.ts.map +1 -0
  81. package/dist/noop-logger.js +8 -0
  82. package/dist/noop-logger.js.map +1 -0
  83. package/dist/prompt-diagnostics.d.ts +47 -0
  84. package/dist/prompt-diagnostics.d.ts.map +1 -0
  85. package/dist/prompt-diagnostics.js +230 -0
  86. package/dist/prompt-diagnostics.js.map +1 -0
  87. package/dist/provider-manager.d.ts +224 -0
  88. package/dist/provider-manager.d.ts.map +1 -0
  89. package/dist/provider-manager.js +563 -0
  90. package/dist/provider-manager.js.map +1 -0
  91. package/dist/provider-registry.d.ts +115 -0
  92. package/dist/provider-registry.d.ts.map +1 -0
  93. package/dist/provider-registry.js +305 -0
  94. package/dist/provider-registry.js.map +1 -0
  95. package/dist/schema-converter.d.ts +20 -0
  96. package/dist/schema-converter.d.ts.map +1 -0
  97. package/dist/schema-converter.js +48 -0
  98. package/dist/schema-converter.js.map +1 -0
  99. package/dist/skill-preprocessor.d.ts +46 -0
  100. package/dist/skill-preprocessor.d.ts.map +1 -0
  101. package/dist/skill-preprocessor.js +237 -0
  102. package/dist/skill-preprocessor.js.map +1 -0
  103. package/dist/skill-registry.d.ts +107 -0
  104. package/dist/skill-registry.d.ts.map +1 -0
  105. package/dist/skill-registry.js +330 -0
  106. package/dist/skill-registry.js.map +1 -0
  107. package/dist/skill-tool.d.ts +54 -0
  108. package/dist/skill-tool.d.ts.map +1 -0
  109. package/dist/skill-tool.js +88 -0
  110. package/dist/skill-tool.js.map +1 -0
  111. package/dist/sub-agent-manager.d.ts +90 -0
  112. package/dist/sub-agent-manager.d.ts.map +1 -0
  113. package/dist/sub-agent-manager.js +192 -0
  114. package/dist/sub-agent-manager.js.map +1 -0
  115. package/dist/token-estimator.d.ts +23 -0
  116. package/dist/token-estimator.d.ts.map +1 -0
  117. package/dist/token-estimator.js +27 -0
  118. package/dist/token-estimator.js.map +1 -0
  119. package/dist/tool-contract.d.ts +68 -0
  120. package/dist/tool-contract.d.ts.map +1 -0
  121. package/dist/tool-contract.js +35 -0
  122. package/dist/tool-contract.js.map +1 -0
  123. package/dist/tool-result-persistence.d.ts +89 -0
  124. package/dist/tool-result-persistence.d.ts.map +1 -0
  125. package/dist/tool-result-persistence.js +152 -0
  126. package/dist/tool-result-persistence.js.map +1 -0
  127. package/dist/tools/bash/index.d.ts +71 -0
  128. package/dist/tools/bash/index.d.ts.map +1 -0
  129. package/dist/tools/bash/index.js +485 -0
  130. package/dist/tools/bash/index.js.map +1 -0
  131. package/dist/tools/bash/interactive.d.ts +47 -0
  132. package/dist/tools/bash/interactive.d.ts.map +1 -0
  133. package/dist/tools/bash/interactive.js +262 -0
  134. package/dist/tools/bash/interactive.js.map +1 -0
  135. package/dist/tools/bash/safety.d.ts +149 -0
  136. package/dist/tools/bash/safety.d.ts.map +1 -0
  137. package/dist/tools/bash/safety.js +1116 -0
  138. package/dist/tools/bash/safety.js.map +1 -0
  139. package/dist/tools/edit.d.ts +57 -0
  140. package/dist/tools/edit.d.ts.map +1 -0
  141. package/dist/tools/edit.js +310 -0
  142. package/dist/tools/edit.js.map +1 -0
  143. package/dist/tools/glob.d.ts +34 -0
  144. package/dist/tools/glob.d.ts.map +1 -0
  145. package/dist/tools/glob.js +268 -0
  146. package/dist/tools/glob.js.map +1 -0
  147. package/dist/tools/grep.d.ts +53 -0
  148. package/dist/tools/grep.d.ts.map +1 -0
  149. package/dist/tools/grep.js +673 -0
  150. package/dist/tools/grep.js.map +1 -0
  151. package/dist/tools/index.d.ts +62 -0
  152. package/dist/tools/index.d.ts.map +1 -0
  153. package/dist/tools/index.js +52 -0
  154. package/dist/tools/index.js.map +1 -0
  155. package/dist/tools/read.d.ts +43 -0
  156. package/dist/tools/read.d.ts.map +1 -0
  157. package/dist/tools/read.js +459 -0
  158. package/dist/tools/read.js.map +1 -0
  159. package/dist/tools/runtime.d.ts +62 -0
  160. package/dist/tools/runtime.d.ts.map +1 -0
  161. package/dist/tools/runtime.js +116 -0
  162. package/dist/tools/runtime.js.map +1 -0
  163. package/dist/tools/shared/cwd-tracker.d.ts +32 -0
  164. package/dist/tools/shared/cwd-tracker.d.ts.map +1 -0
  165. package/dist/tools/shared/cwd-tracker.js +44 -0
  166. package/dist/tools/shared/cwd-tracker.js.map +1 -0
  167. package/dist/tools/shared/edit-history.d.ts +55 -0
  168. package/dist/tools/shared/edit-history.d.ts.map +1 -0
  169. package/dist/tools/shared/edit-history.js +72 -0
  170. package/dist/tools/shared/edit-history.js.map +1 -0
  171. package/dist/tools/shared/edit-matcher.d.ts +83 -0
  172. package/dist/tools/shared/edit-matcher.d.ts.map +1 -0
  173. package/dist/tools/shared/edit-matcher.js +359 -0
  174. package/dist/tools/shared/edit-matcher.js.map +1 -0
  175. package/dist/tools/shared/file-mutation-lock.d.ts +22 -0
  176. package/dist/tools/shared/file-mutation-lock.d.ts.map +1 -0
  177. package/dist/tools/shared/file-mutation-lock.js +35 -0
  178. package/dist/tools/shared/file-mutation-lock.js.map +1 -0
  179. package/dist/tools/shared/gitignore.d.ts +17 -0
  180. package/dist/tools/shared/gitignore.d.ts.map +1 -0
  181. package/dist/tools/shared/gitignore.js +59 -0
  182. package/dist/tools/shared/gitignore.js.map +1 -0
  183. package/dist/tools/shared/pdf-extractor.d.ts +96 -0
  184. package/dist/tools/shared/pdf-extractor.d.ts.map +1 -0
  185. package/dist/tools/shared/pdf-extractor.js +196 -0
  186. package/dist/tools/shared/pdf-extractor.js.map +1 -0
  187. package/dist/tools/shared/read-registry.d.ts +66 -0
  188. package/dist/tools/shared/read-registry.d.ts.map +1 -0
  189. package/dist/tools/shared/read-registry.js +65 -0
  190. package/dist/tools/shared/read-registry.js.map +1 -0
  191. package/dist/tools/shared/safe-env.d.ts +18 -0
  192. package/dist/tools/shared/safe-env.d.ts.map +1 -0
  193. package/dist/tools/shared/safe-env.js +70 -0
  194. package/dist/tools/shared/safe-env.js.map +1 -0
  195. package/dist/tools/sub-agent.d.ts +91 -0
  196. package/dist/tools/sub-agent.d.ts.map +1 -0
  197. package/dist/tools/sub-agent.js +89 -0
  198. package/dist/tools/sub-agent.js.map +1 -0
  199. package/dist/tools/task-output.d.ts +38 -0
  200. package/dist/tools/task-output.d.ts.map +1 -0
  201. package/dist/tools/task-output.js +186 -0
  202. package/dist/tools/task-output.js.map +1 -0
  203. package/dist/tools/tool-search/index.d.ts +40 -0
  204. package/dist/tools/tool-search/index.d.ts.map +1 -0
  205. package/dist/tools/tool-search/index.js +110 -0
  206. package/dist/tools/tool-search/index.js.map +1 -0
  207. package/dist/tools/tool-search/registry.d.ts +82 -0
  208. package/dist/tools/tool-search/registry.d.ts.map +1 -0
  209. package/dist/tools/tool-search/registry.js +238 -0
  210. package/dist/tools/tool-search/registry.js.map +1 -0
  211. package/dist/tools/undo-edit.d.ts +51 -0
  212. package/dist/tools/undo-edit.d.ts.map +1 -0
  213. package/dist/tools/undo-edit.js +231 -0
  214. package/dist/tools/undo-edit.js.map +1 -0
  215. package/dist/tools/web-fetch/cache.d.ts +49 -0
  216. package/dist/tools/web-fetch/cache.d.ts.map +1 -0
  217. package/dist/tools/web-fetch/cache.js +89 -0
  218. package/dist/tools/web-fetch/cache.js.map +1 -0
  219. package/dist/tools/web-fetch/index.d.ts +53 -0
  220. package/dist/tools/web-fetch/index.d.ts.map +1 -0
  221. package/dist/tools/web-fetch/index.js +513 -0
  222. package/dist/tools/web-fetch/index.js.map +1 -0
  223. package/dist/tools/write.d.ts +59 -0
  224. package/dist/tools/write.d.ts.map +1 -0
  225. package/dist/tools/write.js +316 -0
  226. package/dist/tools/write.js.map +1 -0
  227. package/dist/types.d.ts +881 -0
  228. package/dist/types.d.ts.map +1 -0
  229. package/dist/types.js +16 -0
  230. package/dist/types.js.map +1 -0
  231. package/dist/working-tags.d.ts +44 -0
  232. package/dist/working-tags.d.ts.map +1 -0
  233. package/dist/working-tags.js +103 -0
  234. package/dist/working-tags.js.map +1 -0
  235. package/package.json +87 -0
  236. package/src/budget-guard.ts +170 -0
  237. package/src/compaction/compaction.ts +386 -0
  238. package/src/compaction/failsafe.ts +185 -0
  239. package/src/compaction/index.ts +1199 -0
  240. package/src/compaction/microcompaction.ts +709 -0
  241. package/src/compaction/observational/buffering.ts +430 -0
  242. package/src/compaction/observational/constants.ts +532 -0
  243. package/src/compaction/observational/index.ts +837 -0
  244. package/src/compaction/observational/observer.ts +510 -0
  245. package/src/compaction/observational/recall-tool.ts +130 -0
  246. package/src/compaction/observational/reflector.ts +221 -0
  247. package/src/compaction/observational/types.ts +343 -0
  248. package/src/context-manager.ts +237 -0
  249. package/src/cortex-agent.ts +4297 -0
  250. package/src/error-classifier.ts +199 -0
  251. package/src/event-bridge.ts +508 -0
  252. package/src/index.ts +292 -0
  253. package/src/mcp-client.ts +582 -0
  254. package/src/model-wrapper.ts +128 -0
  255. package/src/noop-logger.ts +9 -0
  256. package/src/prompt-diagnostics.ts +296 -0
  257. package/src/provider-manager.ts +823 -0
  258. package/src/provider-registry.ts +386 -0
  259. package/src/schema-converter.ts +51 -0
  260. package/src/skill-preprocessor.ts +314 -0
  261. package/src/skill-registry.ts +378 -0
  262. package/src/skill-tool.ts +130 -0
  263. package/src/sub-agent-manager.ts +236 -0
  264. package/src/token-estimator.ts +26 -0
  265. package/src/tool-contract.ts +113 -0
  266. package/src/tool-result-persistence.ts +197 -0
  267. package/src/tools/bash/index.ts +633 -0
  268. package/src/tools/bash/interactive.ts +302 -0
  269. package/src/tools/bash/safety.ts +1297 -0
  270. package/src/tools/edit.ts +422 -0
  271. package/src/tools/glob.ts +330 -0
  272. package/src/tools/grep.ts +819 -0
  273. package/src/tools/index.ts +110 -0
  274. package/src/tools/read.ts +580 -0
  275. package/src/tools/runtime.ts +173 -0
  276. package/src/tools/shared/cwd-tracker.ts +50 -0
  277. package/src/tools/shared/edit-history.ts +96 -0
  278. package/src/tools/shared/edit-matcher.ts +457 -0
  279. package/src/tools/shared/file-mutation-lock.ts +40 -0
  280. package/src/tools/shared/gitignore.ts +61 -0
  281. package/src/tools/shared/pdf-extractor.ts +290 -0
  282. package/src/tools/shared/read-registry.ts +93 -0
  283. package/src/tools/shared/safe-env.ts +82 -0
  284. package/src/tools/sub-agent.ts +171 -0
  285. package/src/tools/task-output.ts +236 -0
  286. package/src/tools/tool-search/index.ts +167 -0
  287. package/src/tools/tool-search/registry.ts +278 -0
  288. package/src/tools/undo-edit.ts +314 -0
  289. package/src/tools/web-fetch/cache.ts +112 -0
  290. package/src/tools/web-fetch/index.ts +604 -0
  291. package/src/tools/write.ts +385 -0
  292. package/src/types.ts +1057 -0
  293. package/src/working-tags.ts +118 -0
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Reflector module for the observational memory system.
3
+ *
4
+ * The Reflector condenses observations when they grow too large. It runs
5
+ * on the utility model and uses progressive compression: starting with
6
+ * no compression guidance (level 0) and escalating through levels 1-4
7
+ * if the output exceeds the target token threshold.
8
+ *
9
+ * References:
10
+ * - observational-memory-architecture.md (Reflector System section)
11
+ * - compaction-strategy.md
12
+ */
13
+
14
+ import type { CompleteFn } from '../compaction.js';
15
+ import type { ReflectorOutput } from './types.js';
16
+ import {
17
+ REFLECTOR_SYSTEM_PROMPT,
18
+ COMPRESSION_LEVEL_GUIDANCE,
19
+ } from './constants.js';
20
+ import { estimateTokens } from '../../token-estimator.js';
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // Prompt Building
24
+ // ---------------------------------------------------------------------------
25
+
26
+ /**
27
+ * Build the full reflector system prompt.
28
+ *
29
+ * Starts with the base reflector prompt, then appends compression level
30
+ * guidance and optional consumer instructions.
31
+ *
32
+ * @param compressionLevel - Compression level (0-4). Level 0 adds no
33
+ * compression guidance.
34
+ * @param customInstruction - Optional consumer-provided instruction to
35
+ * append to the prompt.
36
+ * @returns The assembled system prompt string.
37
+ */
38
+ export function buildReflectorPrompt(
39
+ compressionLevel: number,
40
+ customInstruction?: string,
41
+ ): string {
42
+ let prompt = REFLECTOR_SYSTEM_PROMPT;
43
+
44
+ const guidance = COMPRESSION_LEVEL_GUIDANCE[compressionLevel];
45
+ if (compressionLevel > 0 && guidance) {
46
+ prompt += `\n\n## Compression Target\n\n${guidance}`;
47
+ }
48
+
49
+ if (customInstruction) {
50
+ prompt += `\n\n## Additional Instructions\n\n${customInstruction}`;
51
+ }
52
+
53
+ return prompt;
54
+ }
55
+
56
+ // ---------------------------------------------------------------------------
57
+ // Message Building
58
+ // ---------------------------------------------------------------------------
59
+
60
+ /**
61
+ * Build the message array to send to the reflector LLM.
62
+ *
63
+ * Creates two user messages: one containing the observations to reflect on,
64
+ * and one with the output instruction.
65
+ *
66
+ * @param observations - The full observation text to consolidate.
67
+ * @returns An array of message objects for the LLM call.
68
+ */
69
+ export function buildReflectorMessages(
70
+ observations: string,
71
+ ): unknown[] {
72
+ return [
73
+ {
74
+ role: 'user',
75
+ content:
76
+ 'Here are all current observations to reflect on and consolidate:\n\n' +
77
+ observations,
78
+ },
79
+ {
80
+ role: 'user',
81
+ content:
82
+ 'Produce your consolidated reflections. Follow the observation format exactly. Output ONLY the consolidated observations, nothing else.',
83
+ },
84
+ ];
85
+ }
86
+
87
+ // ---------------------------------------------------------------------------
88
+ // Output Parsing
89
+ // ---------------------------------------------------------------------------
90
+
91
+ /**
92
+ * Parse the raw LLM output from the reflector.
93
+ *
94
+ * Extracts content from `<observations>` tags if present, strips any
95
+ * analysis/thinking tags, and trims whitespace.
96
+ *
97
+ * @param raw - The raw string output from the reflector LLM call.
98
+ * @returns The cleaned observation text.
99
+ */
100
+ export function parseReflectorOutput(raw: string): string {
101
+ let output = raw;
102
+
103
+ // Strip analysis/thinking tags if present
104
+ output = output.replace(/<analysis>[\s\S]*?<\/analysis>/g, '');
105
+ output = output.replace(/<thinking>[\s\S]*?<\/thinking>/g, '');
106
+
107
+ // Extract content from <observations> tags if present
108
+ const match = /<observations>([\s\S]*?)<\/observations>/.exec(output);
109
+ if (match?.[1]) {
110
+ output = match[1];
111
+ }
112
+
113
+ return output.trim();
114
+ }
115
+
116
+ // ---------------------------------------------------------------------------
117
+ // Validation
118
+ // ---------------------------------------------------------------------------
119
+
120
+ /**
121
+ * Check whether the reflector output is within the target token budget.
122
+ *
123
+ * @param output - The parsed reflector output text.
124
+ * @param targetTokens - The maximum allowed token count.
125
+ * @returns `true` if estimated tokens are at or below the target.
126
+ */
127
+ export function validateCompression(
128
+ output: string,
129
+ targetTokens: number,
130
+ ): boolean {
131
+ return estimateTokens(output) <= targetTokens;
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // Threshold Computation
136
+ // ---------------------------------------------------------------------------
137
+
138
+ /**
139
+ * Compute the effective reflection threshold by clamping to both the
140
+ * primary model's context window and the utility model's context window.
141
+ *
142
+ * The threshold is the smaller of:
143
+ * - `reflectionThreshold` as a percentage of the primary context window
144
+ * - 50% of the utility model's context window (to ensure the reflector
145
+ * input fits within the utility model)
146
+ *
147
+ * @param contextWindow - The primary model's context window size in tokens.
148
+ * @param reflectionThreshold - Fraction of the context window (e.g. 0.20).
149
+ * @param utilityModelContextWindow - The utility model's context window
150
+ * size in tokens.
151
+ * @returns The effective reflection threshold in tokens.
152
+ */
153
+ export function computeEffectiveReflectionThreshold(
154
+ contextWindow: number,
155
+ reflectionThreshold: number,
156
+ utilityModelContextWindow: number,
157
+ ): number {
158
+ return Math.min(
159
+ contextWindow * reflectionThreshold,
160
+ utilityModelContextWindow * 0.5,
161
+ );
162
+ }
163
+
164
+ // ---------------------------------------------------------------------------
165
+ // Reflector Execution
166
+ // ---------------------------------------------------------------------------
167
+
168
+ const MAX_RETRIES = 4;
169
+ const MAX_COMPRESSION_LEVEL = 4;
170
+
171
+ /**
172
+ * Run the reflector with progressive compression retry.
173
+ *
174
+ * Starts at compression level 0 and escalates if the output exceeds the
175
+ * reflection threshold. Retries up to 3 times, incrementing the
176
+ * compression level each time (capped at level 4).
177
+ *
178
+ * Even if the final attempt does not validate, the best result is returned.
179
+ * The observation slot will be larger than ideal, but the next reflection
180
+ * cycle will try again.
181
+ *
182
+ * @param complete - The LLM completion function.
183
+ * @param observations - The full observation text to consolidate.
184
+ * @param config - Configuration with reflectionThreshold (in tokens) and
185
+ * optional reflectorInstruction.
186
+ * @returns The reflector output with consolidated observations and the
187
+ * compression level that was applied.
188
+ */
189
+ export async function runReflector(
190
+ complete: CompleteFn,
191
+ observations: string,
192
+ config: {
193
+ reflectionThreshold: number;
194
+ reflectorInstruction?: string;
195
+ },
196
+ ): Promise<ReflectorOutput> {
197
+ let level = 0;
198
+ let retries = 0;
199
+ let parsedOutput = '';
200
+
201
+ while (true) {
202
+ const systemPrompt = buildReflectorPrompt(level, config.reflectorInstruction);
203
+ const messages = buildReflectorMessages(observations);
204
+ const raw = await complete({ systemPrompt, messages });
205
+
206
+ parsedOutput = parseReflectorOutput(raw);
207
+
208
+ if (validateCompression(parsedOutput, config.reflectionThreshold)) {
209
+ return { observations: parsedOutput, compressionLevel: level };
210
+ }
211
+
212
+ if (level >= MAX_COMPRESSION_LEVEL || retries >= MAX_RETRIES) {
213
+ break;
214
+ }
215
+
216
+ level++;
217
+ retries++;
218
+ }
219
+
220
+ return { observations: parsedOutput, compressionLevel: level };
221
+ }
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Type definitions for the observational memory system.
3
+ *
4
+ * Observational memory is an alternative compaction strategy that replaces
5
+ * Layers 1 and 2 (microcompaction + conversation summarization) with a
6
+ * continuous, background-driven compression system. Two background LLM agents
7
+ * (Observer and Reflector) maintain a compressed event log of the conversation.
8
+ *
9
+ * References:
10
+ * - observational-memory-architecture.md
11
+ * - compaction-strategy.md
12
+ * - context-manager.md
13
+ */
14
+
15
+ import type { AgentMessage } from '../../context-manager.js';
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Configuration
19
+ // ---------------------------------------------------------------------------
20
+
21
+ /**
22
+ * Consumer-facing configuration for the observational memory system.
23
+ *
24
+ * All fields are optional with sensible defaults. The system adapts to any
25
+ * context window size from 32k to 1M+ through percentage-based thresholds.
26
+ */
27
+ export interface ObservationalMemoryConfig {
28
+ /**
29
+ * Percentage of total context window utilization that triggers observation
30
+ * activation. When total context (system prompt + slots + observations +
31
+ * messages) exceeds this fraction of the context window, buffered
32
+ * observations activate and raw messages are trimmed.
33
+ * @default 0.9
34
+ */
35
+ activationThreshold: number;
36
+
37
+ /**
38
+ * Maximum token count per async buffer observation. Caps how many tokens
39
+ * of unobserved messages a single observer call will process. Prevents
40
+ * oversized observer calls on large context windows.
41
+ * The actual interval is computed dynamically (see Observer System section
42
+ * in architecture doc).
43
+ * Internally clamped to utilityModelContextWindow * 0.6 to ensure the
44
+ * observer input fits within the utility model's context window.
45
+ * @default 30_000
46
+ */
47
+ bufferTokenCap: number;
48
+
49
+ /**
50
+ * Minimum tokens of unobserved messages before a buffer observation runs.
51
+ * Prevents thrashing when the context window is nearly full or on very
52
+ * small windows.
53
+ * @default 5_000
54
+ */
55
+ bufferMinTokens: number;
56
+
57
+ /**
58
+ * Target number of buffer cycles between current utilization and the
59
+ * activation threshold. Higher values mean more frequent, smaller observer
60
+ * calls. Lower values mean fewer, larger observer calls.
61
+ * @default 4
62
+ */
63
+ bufferTargetCycles: number;
64
+
65
+ /**
66
+ * Fraction of the context window at which reflection triggers.
67
+ * When the observation slot exceeds this percentage of the context window,
68
+ * the Reflector condenses it. Scales naturally across all window sizes.
69
+ * Internally clamped to utilityModelContextWindow * 0.5 to ensure the
70
+ * reflector input fits within the utility model's context window.
71
+ * @default 0.20
72
+ */
73
+ reflectionThreshold: number;
74
+
75
+ /**
76
+ * Fraction of reflectionThreshold at which async reflection buffering
77
+ * begins. For example, 0.5 means start background reflection at 50% of
78
+ * the threshold.
79
+ * @default 0.5
80
+ */
81
+ reflectionBufferActivation: number;
82
+
83
+ /**
84
+ * Token budget for previous observations sent to the Observer as context.
85
+ * Provides continuity between observation cycles so the observer does not
86
+ * duplicate already-captured information.
87
+ * @default 2_000
88
+ */
89
+ previousObserverTokens: number;
90
+
91
+ /**
92
+ * Custom instructions appended to the Observer's system prompt.
93
+ * Use for domain-specific observation behavior. Cannot replace the core
94
+ * prompt, only extend it.
95
+ */
96
+ observerInstruction?: string;
97
+
98
+ /**
99
+ * Custom instructions appended to the Reflector's system prompt.
100
+ * Use for domain-specific reflection behavior. Cannot replace the core
101
+ * prompt, only extend it.
102
+ */
103
+ reflectorInstruction?: string;
104
+
105
+ /**
106
+ * Optional recall tool configuration. When provided, Cortex registers a
107
+ * recall tool that enables the agent to search through persisted
108
+ * conversation history. The consumer owns message persistence and search
109
+ * implementation.
110
+ */
111
+ recall?: RecallConfig;
112
+ }
113
+
114
+ /**
115
+ * Configuration for the optional recall tool.
116
+ *
117
+ * The consumer provides a search function that Cortex wraps into a tool
118
+ * registered on the agent. Observations include timestamps, enabling
119
+ * temporal anchoring for precise recall queries.
120
+ */
121
+ export interface RecallConfig {
122
+ /**
123
+ * Search function provided by the consumer. Accepts a query string and
124
+ * optional time range for narrowing results.
125
+ *
126
+ * The consumer owns the search implementation (vector DB, full-text
127
+ * search, SQL, etc.). Cortex only wraps it into a tool.
128
+ */
129
+ search: (
130
+ query: string,
131
+ options?: { timeRange?: { start?: Date; end?: Date } },
132
+ ) => Promise<RecallResult[]>;
133
+ }
134
+
135
+ // ---------------------------------------------------------------------------
136
+ // Session State
137
+ // ---------------------------------------------------------------------------
138
+
139
+ /**
140
+ * Serializable session state for the observational memory system.
141
+ *
142
+ * Saved via `agent.getObservationalMemoryState()` and restored via
143
+ * `agent.restoreObservationalMemoryState()`. The consumer decides where
144
+ * and when to persist this (same pattern as `getConversationHistory()`).
145
+ */
146
+ export interface ObservationalMemoryState {
147
+ /** Current observation text (the content stored in the _observations slot). */
148
+ observations: string;
149
+
150
+ /** Continuation hints from the last observer run. */
151
+ continuationHint: ContinuationHint | null;
152
+
153
+ /** Current observation token estimate. */
154
+ observationTokenCount: number;
155
+
156
+ /** How many reflection cycles have occurred in this session. */
157
+ generationCount: number;
158
+
159
+ /** Buffered observation chunks not yet activated. */
160
+ bufferedChunks: ObservationChunk[];
161
+ }
162
+
163
+ // ---------------------------------------------------------------------------
164
+ // Observation Chunks
165
+ // ---------------------------------------------------------------------------
166
+
167
+ /**
168
+ * A buffered observation chunk produced by an async observer call.
169
+ *
170
+ * Chunks accumulate between activation cycles. On activation, completed
171
+ * chunks are merged into the observation slot and their corresponding
172
+ * raw messages are removed from context.
173
+ */
174
+ export interface ObservationChunk {
175
+ /** The observation text produced by the observer. */
176
+ observations: string;
177
+
178
+ /** Token count of messages that were observed in this chunk. */
179
+ messageTokensObserved: number;
180
+
181
+ /** When this chunk was created. */
182
+ createdAt: Date;
183
+
184
+ /** Current task extracted from this observation. Latest chunk wins on activation. */
185
+ currentTask?: string;
186
+
187
+ /** Suggested response extracted from this observation. Latest chunk wins on activation. */
188
+ suggestedResponse?: string;
189
+ }
190
+
191
+ // ---------------------------------------------------------------------------
192
+ // Events
193
+ // ---------------------------------------------------------------------------
194
+
195
+ /**
196
+ * Event payload fired when observation activates (messages are compressed
197
+ * and removed from context).
198
+ *
199
+ * Registered via `agent.onObservation()`. Multiple handlers are supported.
200
+ * Consumers can use this to persist compacted messages or coordinate their
201
+ * own compression systems.
202
+ */
203
+ export interface ObservationEvent {
204
+ /** The raw messages that were compressed and removed from context. */
205
+ compactedMessages: AgentMessage[];
206
+
207
+ /** The observation text those messages were compressed into. */
208
+ observations: string;
209
+
210
+ /** Total context utilization (0-1) at the time of activation. */
211
+ contextUtilization: number;
212
+
213
+ /** Whether this was a sync (blocking) or async (buffered) observation. */
214
+ sync: boolean;
215
+
216
+ /** Timestamp of the observation. */
217
+ timestamp: Date;
218
+ }
219
+
220
+ /**
221
+ * Event payload fired after a reflection cycle completes (observations
222
+ * are condensed by the reflector).
223
+ *
224
+ * Registered via `agent.onReflection()`. Multiple handlers are supported.
225
+ * Consumers can use this to coordinate their own compaction timing with
226
+ * Cortex's reflection cycles.
227
+ */
228
+ export interface ReflectionEvent {
229
+ /** Observations before reflection. */
230
+ previousObservations: string;
231
+
232
+ /** Observations after reflection (condensed). */
233
+ newObservations: string;
234
+
235
+ /** How many reflection generations have occurred in this session. */
236
+ generationCount: number;
237
+
238
+ /** Compression level used (0-4). */
239
+ compressionLevel: number;
240
+
241
+ /** Timestamp of the reflection. */
242
+ timestamp: Date;
243
+ }
244
+
245
+ // ---------------------------------------------------------------------------
246
+ // Recall
247
+ // ---------------------------------------------------------------------------
248
+
249
+ /**
250
+ * A single result returned from the consumer's recall search function.
251
+ *
252
+ * Contains the content of a past message or tool result along with
253
+ * temporal and classification metadata.
254
+ */
255
+ export interface RecallResult {
256
+ /** The message or tool result content. */
257
+ content: string;
258
+
259
+ /** When the message occurred. */
260
+ timestamp: Date;
261
+
262
+ /** Type of content returned. */
263
+ type: 'message' | 'tool-result' | 'tool-call';
264
+
265
+ /** Message role, if applicable. */
266
+ role?: 'user' | 'assistant';
267
+ }
268
+
269
+ // ---------------------------------------------------------------------------
270
+ // LLM Output Types
271
+ // ---------------------------------------------------------------------------
272
+
273
+ /**
274
+ * Parsed output from the observer LLM call.
275
+ *
276
+ * The observer produces XML with three sections: observations, current-task,
277
+ * and suggested-response. This type represents the parsed result.
278
+ */
279
+ export interface ObserverOutput {
280
+ /** Extracted observations in the structured bulleted format. */
281
+ observations: string;
282
+
283
+ /** The agent's current task, if identified by the observer. */
284
+ currentTask?: string;
285
+
286
+ /** A suggested response hint for the agent after observation activates. */
287
+ suggestedResponse?: string;
288
+ }
289
+
290
+ /**
291
+ * Parsed output from the reflector LLM call.
292
+ *
293
+ * The reflector produces consolidated observations and reports the
294
+ * compression level it applied.
295
+ */
296
+ export interface ReflectorOutput {
297
+ /** Consolidated and reorganized observations. */
298
+ observations: string;
299
+
300
+ /** The compression level that was applied (0-4). */
301
+ compressionLevel: number;
302
+ }
303
+
304
+ // ---------------------------------------------------------------------------
305
+ // Internal Types
306
+ // ---------------------------------------------------------------------------
307
+
308
+ /**
309
+ * Continuation hint carried between observer runs and across sessions.
310
+ *
311
+ * Provides the agent with awareness of what it was working on and what
312
+ * it should say next, particularly valuable on session resumption.
313
+ */
314
+ export interface ContinuationHint {
315
+ /** What the agent is currently working on. */
316
+ currentTask: string;
317
+
318
+ /** Hint for the agent's next message after observation activates. */
319
+ suggestedResponse: string;
320
+ }
321
+
322
+ /**
323
+ * Internal state for the buffering coordinator.
324
+ *
325
+ * Tracks the observation watermark, accumulated chunks, and in-flight
326
+ * async operations for both the observer and reflector.
327
+ */
328
+ export interface BufferState {
329
+ /**
330
+ * Index into agent.state.messages marking where the last completed
331
+ * observation ended. Messages from this index onward are "unobserved."
332
+ */
333
+ watermark: number;
334
+
335
+ /** Completed observation chunks awaiting activation. */
336
+ chunks: ObservationChunk[];
337
+
338
+ /** Promise for the currently in-flight async observer call, or null. */
339
+ inFlightObserver: Promise<ObserverOutput | null> | null;
340
+
341
+ /** Promise for the currently in-flight async reflector call, or null. */
342
+ inFlightReflector: Promise<ReflectorOutput | null> | null;
343
+ }