@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,97 @@
1
+ /**
2
+ * Observer module for the observational memory system.
3
+ *
4
+ * Handles extracting observations from raw conversation messages via a
5
+ * background LLM call. The observer watches the conversation and produces
6
+ * structured, timestamped observations that become the agent's sole
7
+ * memory of past interactions.
8
+ *
9
+ * References:
10
+ * - observational-memory-architecture.md (Observer System section)
11
+ * - compaction-strategy.md
12
+ */
13
+ import type { CompleteFn } from '../compaction.js';
14
+ import type { AgentMessage } from '../../context-manager.js';
15
+ import type { ObserverOutput } from './types.js';
16
+ /**
17
+ * Converts an array of AgentMessages into a formatted string for the
18
+ * observer LLM.
19
+ *
20
+ * Each message is formatted with role and positional timestamp. Messages
21
+ * with content arrays (tool calls/results) receive structured formatting
22
+ * so the observer can extract meaningful takeaways.
23
+ *
24
+ * Messages with timestamps are formatted with their actual date and time.
25
+ * Messages without timestamps fall back to sequential labels.
26
+ * Messages are grouped by date when timestamps are available.
27
+ */
28
+ export declare function formatMessagesForObserver(messages: AgentMessage[]): string;
29
+ /**
30
+ * Parse the raw LLM output from the observer.
31
+ *
32
+ * Extracts content from `<observations>`, `<current-task>`, and
33
+ * `<suggested-response>` XML blocks. Uses simple string matching
34
+ * (not a DOM parser) and is lenient with malformed output.
35
+ *
36
+ * If no `<observations>` tag is found, the entire output is used as
37
+ * observations (graceful fallback).
38
+ */
39
+ export declare function parseObserverOutput(raw: string): ObserverOutput;
40
+ /**
41
+ * Build the full observer system prompt.
42
+ *
43
+ * Starts with `OBSERVER_SYSTEM_PROMPT` from constants and optionally
44
+ * appends consumer-provided custom instructions.
45
+ *
46
+ * @param previousObservations - Previous observations for context (unused in system prompt, kept for signature consistency)
47
+ * @param previousObserverTokens - Token budget for previous observations (unused in system prompt)
48
+ * @param customInstruction - Optional consumer-provided instruction to append
49
+ * @returns The complete system prompt string
50
+ */
51
+ export declare function buildObserverPrompt(previousObservations: string | null, previousObserverTokens: number, customInstruction?: string): string;
52
+ /**
53
+ * Build the message array to send to the observer LLM.
54
+ *
55
+ * Constructs a sequence of user messages:
56
+ * 1. (Optional) Previous observations for deduplication context
57
+ * 2. The formatted message history
58
+ * 3. A task instruction to extract observations
59
+ *
60
+ * @param messages - The conversation messages to observe
61
+ * @param previousObservations - Previous observations to prevent duplication
62
+ * @param previousObserverTokens - Token budget for the previous observations context
63
+ * @returns Array of message objects for the LLM call
64
+ */
65
+ export declare function buildObserverMessages(messages: AgentMessage[], previousObservations: string | null, previousObserverTokens: number): unknown[];
66
+ /**
67
+ * Check if the output contains degenerate repetition.
68
+ *
69
+ * Detects a line appearing 5+ times consecutively, which is a known
70
+ * failure mode of LLMs under certain conditions (e.g., high temperature,
71
+ * long context, repetitive input patterns).
72
+ *
73
+ * @param text - The text to check for repetition
74
+ * @returns true if degenerate repetition is detected
75
+ */
76
+ export declare function detectDegenerateRepetition(text: string): boolean;
77
+ /**
78
+ * Run the observer LLM call to extract observations from messages.
79
+ *
80
+ * Orchestrates the full observer pipeline:
81
+ * 1. Builds the system prompt (with optional custom instructions)
82
+ * 2. Builds the message array (with previous observations context)
83
+ * 3. Calls the LLM via `complete`
84
+ * 4. Parses the structured output
85
+ * 5. Detects and retries on degenerate repetition (once)
86
+ *
87
+ * @param complete - The LLM completion function
88
+ * @param messages - The conversation messages to observe
89
+ * @param previousObservations - Previous observations for deduplication
90
+ * @param config - Observer configuration
91
+ * @returns Parsed observer output with observations, current task, and suggested response
92
+ */
93
+ export declare function runObserver(complete: CompleteFn, messages: AgentMessage[], previousObservations: string | null, config: {
94
+ previousObserverTokens: number;
95
+ observerInstruction?: string;
96
+ }): Promise<ObserverOutput>;
97
+ //# sourceMappingURL=observer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observer.d.ts","sourceRoot":"","sources":["../../../src/compaction/observational/observer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQjD;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM,CAkD1E;AA4JD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAoB/D;AAwDD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,oBAAoB,EAAE,MAAM,GAAG,IAAI,EACnC,sBAAsB,EAAE,MAAM,EAC9B,iBAAiB,CAAC,EAAE,MAAM,GACzB,MAAM,CAQR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,YAAY,EAAE,EACxB,oBAAoB,EAAE,MAAM,GAAG,IAAI,EACnC,sBAAsB,EAAE,MAAM,GAC7B,OAAO,EAAE,CAsBX;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAwBhE;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,UAAU,EACpB,QAAQ,EAAE,YAAY,EAAE,EACxB,oBAAoB,EAAE,MAAM,GAAG,IAAI,EACnC,MAAM,EAAE;IACN,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,GACA,OAAO,CAAC,cAAc,CAAC,CAuBzB"}
@@ -0,0 +1,424 @@
1
+ /**
2
+ * Observer module for the observational memory system.
3
+ *
4
+ * Handles extracting observations from raw conversation messages via a
5
+ * background LLM call. The observer watches the conversation and produces
6
+ * structured, timestamped observations that become the agent's sole
7
+ * memory of past interactions.
8
+ *
9
+ * References:
10
+ * - observational-memory-architecture.md (Observer System section)
11
+ * - compaction-strategy.md
12
+ */
13
+ import { OBSERVER_SYSTEM_PROMPT } from './constants.js';
14
+ import { estimateTokens } from '../../token-estimator.js';
15
+ // ---------------------------------------------------------------------------
16
+ // Message Formatting
17
+ // ---------------------------------------------------------------------------
18
+ /**
19
+ * Converts an array of AgentMessages into a formatted string for the
20
+ * observer LLM.
21
+ *
22
+ * Each message is formatted with role and positional timestamp. Messages
23
+ * with content arrays (tool calls/results) receive structured formatting
24
+ * so the observer can extract meaningful takeaways.
25
+ *
26
+ * Messages with timestamps are formatted with their actual date and time.
27
+ * Messages without timestamps fall back to sequential labels.
28
+ * Messages are grouped by date when timestamps are available.
29
+ */
30
+ export function formatMessagesForObserver(messages) {
31
+ if (messages.length === 0)
32
+ return '';
33
+ const lines = [];
34
+ let currentDateHeader = null;
35
+ for (let i = 0; i < messages.length; i++) {
36
+ const msg = messages[i];
37
+ const roleLabel = msg.role;
38
+ // Build the timestamp label from message metadata
39
+ let label;
40
+ if (msg.timestamp !== 0) {
41
+ const date = new Date(msg.timestamp);
42
+ const dateHeader = formatDateHeader(date);
43
+ // Insert a date header when the date changes
44
+ if (dateHeader !== currentDateHeader) {
45
+ if (currentDateHeader !== null) {
46
+ lines.push(''); // blank line between date groups
47
+ }
48
+ lines.push(`Date: ${dateHeader}`);
49
+ currentDateHeader = dateHeader;
50
+ }
51
+ label = formatTime(date);
52
+ }
53
+ else {
54
+ // No timestamp available; use a sequential fallback
55
+ if (currentDateHeader === null) {
56
+ lines.push('Date: (not specified)');
57
+ currentDateHeader = '(not specified)';
58
+ }
59
+ label = `Message ${i + 1}`;
60
+ }
61
+ if (typeof msg.content === 'string') {
62
+ lines.push(`**${roleLabel} (${label})**: ${msg.content}`);
63
+ }
64
+ else if (Array.isArray(msg.content)) {
65
+ const parts = formatContentParts(msg.content);
66
+ if (parts) {
67
+ lines.push(`**${roleLabel} (${label})**:\n${parts}`);
68
+ }
69
+ else {
70
+ lines.push(`**${roleLabel} (${label})**: [empty]`);
71
+ }
72
+ }
73
+ else {
74
+ lines.push(`**${roleLabel} (${label})**: [empty]`);
75
+ }
76
+ }
77
+ return lines.join('\n\n');
78
+ }
79
+ /**
80
+ * Format a date for the observer date header.
81
+ * Example: "April 11, 2026"
82
+ */
83
+ function formatDateHeader(date) {
84
+ return date.toLocaleDateString('en-US', {
85
+ month: 'long',
86
+ day: 'numeric',
87
+ year: 'numeric',
88
+ });
89
+ }
90
+ /**
91
+ * Format a time for a message label.
92
+ * Example: "2:30 PM"
93
+ */
94
+ function formatTime(date) {
95
+ return date.toLocaleTimeString('en-US', {
96
+ hour: 'numeric',
97
+ minute: '2-digit',
98
+ hour12: true,
99
+ });
100
+ }
101
+ /**
102
+ * Format an array of content parts from a structured message.
103
+ *
104
+ * Handles text, tool_use, and tool_result part types. Other part types
105
+ * are rendered with their type label.
106
+ */
107
+ function formatContentParts(parts) {
108
+ const formatted = [];
109
+ for (const part of parts) {
110
+ switch (part.type) {
111
+ case 'text': {
112
+ if (typeof part.text === 'string' && part.text.length > 0) {
113
+ formatted.push(part.text);
114
+ }
115
+ break;
116
+ }
117
+ case 'tool_use': {
118
+ const toolName = typeof part['name'] === 'string' ? part['name'] : 'unknown';
119
+ const argsSummary = summarizeToolArgs(part['input']);
120
+ formatted.push(`[Tool Call: ${toolName}] ${argsSummary}`);
121
+ break;
122
+ }
123
+ case 'tool_result': {
124
+ const toolUseId = typeof part['tool_use_id'] === 'string'
125
+ ? part['tool_use_id']
126
+ : undefined;
127
+ // Resolve tool name: check for a name field on the part, fall back to tool_use_id reference
128
+ const resultToolName = typeof part['name'] === 'string'
129
+ ? part['name']
130
+ : undefined;
131
+ const header = resultToolName
132
+ ? `[Tool Result: ${resultToolName}]`
133
+ : toolUseId
134
+ ? `[Tool Result (ref: ${toolUseId})]`
135
+ : '[Tool Result]';
136
+ const content = extractToolResultContent(part);
137
+ if (content) {
138
+ formatted.push(`${header}\n${content}`);
139
+ }
140
+ else {
141
+ formatted.push(header);
142
+ }
143
+ break;
144
+ }
145
+ default: {
146
+ // Unknown part type: include type label and any text
147
+ if (typeof part.text === 'string' && part.text.length > 0) {
148
+ formatted.push(`[${part.type}]: ${part.text}`);
149
+ }
150
+ break;
151
+ }
152
+ }
153
+ }
154
+ return formatted.join('\n');
155
+ }
156
+ /**
157
+ * Summarize tool call arguments into a brief string.
158
+ *
159
+ * Produces a compact summary of the key arguments without reproducing
160
+ * large values verbatim.
161
+ */
162
+ function summarizeToolArgs(input) {
163
+ if (input === null || input === undefined)
164
+ return '';
165
+ if (typeof input === 'string')
166
+ return `{${truncateValue(input, 100)}}`;
167
+ if (typeof input === 'object' && !Array.isArray(input)) {
168
+ const obj = input;
169
+ const entries = Object.entries(obj);
170
+ if (entries.length === 0)
171
+ return '{}';
172
+ const parts = entries.slice(0, 5).map(([key, value]) => {
173
+ return `${key}: ${truncateValue(String(value), 80)}`;
174
+ });
175
+ const suffix = entries.length > 5 ? `, ... (+${entries.length - 5} more)` : '';
176
+ return `{${parts.join(', ')}${suffix}}`;
177
+ }
178
+ return String(input);
179
+ }
180
+ /**
181
+ * Extract text content from a tool_result part.
182
+ */
183
+ function extractToolResultContent(part) {
184
+ // Direct text field
185
+ if (typeof part.text === 'string' && part.text.length > 0) {
186
+ return part.text;
187
+ }
188
+ // Content may be nested in a 'content' field (some tool result formats)
189
+ const nested = part['content'];
190
+ if (typeof nested === 'string' && nested.length > 0) {
191
+ return nested;
192
+ }
193
+ if (Array.isArray(nested)) {
194
+ const textParts = nested
195
+ .filter((p) => typeof p === 'object' && p !== null && typeof p.text === 'string')
196
+ .map(p => p.text);
197
+ if (textParts.length > 0)
198
+ return textParts.join('\n');
199
+ }
200
+ return '';
201
+ }
202
+ /**
203
+ * Truncate a string value for argument summaries.
204
+ */
205
+ function truncateValue(value, maxLen) {
206
+ if (value.length <= maxLen)
207
+ return value;
208
+ return value.slice(0, maxLen) + '...';
209
+ }
210
+ // ---------------------------------------------------------------------------
211
+ // Output Parsing
212
+ // ---------------------------------------------------------------------------
213
+ /**
214
+ * Parse the raw LLM output from the observer.
215
+ *
216
+ * Extracts content from `<observations>`, `<current-task>`, and
217
+ * `<suggested-response>` XML blocks. Uses simple string matching
218
+ * (not a DOM parser) and is lenient with malformed output.
219
+ *
220
+ * If no `<observations>` tag is found, the entire output is used as
221
+ * observations (graceful fallback).
222
+ */
223
+ export function parseObserverOutput(raw) {
224
+ const observations = extractTagContent(raw, 'observations') ?? raw.trim();
225
+ const rawTask = extractTagContent(raw, 'current-task');
226
+ const rawSuggested = extractTagContent(raw, 'suggested-response');
227
+ const result = {
228
+ observations: observations.trim(),
229
+ };
230
+ const trimmedTask = rawTask?.trim();
231
+ if (trimmedTask && hasMeaningfulContent(trimmedTask)) {
232
+ result.currentTask = trimmedTask;
233
+ }
234
+ const trimmedSuggested = rawSuggested?.trim();
235
+ if (trimmedSuggested && hasMeaningfulContent(trimmedSuggested)) {
236
+ result.suggestedResponse = trimmedSuggested;
237
+ }
238
+ return result;
239
+ }
240
+ /**
241
+ * Check whether extracted tag content is meaningful (not just placeholder
242
+ * labels echoed from the prompt template).
243
+ *
244
+ * The observer prompt shows a structure like "- Primary:" and "- Secondary:"
245
+ * as a template. Some model outputs echo the template without filling in
246
+ * real content. This check rejects such outputs so the caller can fall back
247
+ * to prior hints or mark the field as missing.
248
+ */
249
+ function hasMeaningfulContent(value) {
250
+ const contentOnly = value
251
+ .split('\n')
252
+ .map(line => line
253
+ .replace(/^\s*[-*]\s*/, '')
254
+ .replace(/^Primary\s*:\s*/i, '')
255
+ .replace(/^Secondary\s*:\s*/i, '')
256
+ .trim())
257
+ .filter(line => line.length > 0)
258
+ .join(' ')
259
+ .trim();
260
+ return contentOnly.length >= 8;
261
+ }
262
+ /**
263
+ * Extract content between XML-style tags.
264
+ *
265
+ * Lenient: handles whitespace around tags, multiline content, and
266
+ * nested content. Returns null if the tag pair is not found.
267
+ */
268
+ function extractTagContent(text, tagName) {
269
+ const openPattern = new RegExp(`<${tagName}>`, 'i');
270
+ const closePattern = new RegExp(`</${tagName}>`, 'i');
271
+ const openMatch = openPattern.exec(text);
272
+ if (!openMatch)
273
+ return null;
274
+ const startIndex = openMatch.index + openMatch[0].length;
275
+ const closeMatch = closePattern.exec(text.slice(startIndex));
276
+ if (!closeMatch) {
277
+ // Opening tag found but no closing tag: return everything after the opening tag
278
+ return text.slice(startIndex);
279
+ }
280
+ return text.slice(startIndex, startIndex + closeMatch.index);
281
+ }
282
+ // ---------------------------------------------------------------------------
283
+ // Prompt Building
284
+ // ---------------------------------------------------------------------------
285
+ /**
286
+ * Build the full observer system prompt.
287
+ *
288
+ * Starts with `OBSERVER_SYSTEM_PROMPT` from constants and optionally
289
+ * appends consumer-provided custom instructions.
290
+ *
291
+ * @param previousObservations - Previous observations for context (unused in system prompt, kept for signature consistency)
292
+ * @param previousObserverTokens - Token budget for previous observations (unused in system prompt)
293
+ * @param customInstruction - Optional consumer-provided instruction to append
294
+ * @returns The complete system prompt string
295
+ */
296
+ export function buildObserverPrompt(previousObservations, previousObserverTokens, customInstruction) {
297
+ let prompt = OBSERVER_SYSTEM_PROMPT;
298
+ if (customInstruction) {
299
+ prompt += `\n\n## Additional Instructions\n\n${customInstruction}`;
300
+ }
301
+ return prompt;
302
+ }
303
+ /**
304
+ * Build the message array to send to the observer LLM.
305
+ *
306
+ * Constructs a sequence of user messages:
307
+ * 1. (Optional) Previous observations for deduplication context
308
+ * 2. The formatted message history
309
+ * 3. A task instruction to extract observations
310
+ *
311
+ * @param messages - The conversation messages to observe
312
+ * @param previousObservations - Previous observations to prevent duplication
313
+ * @param previousObserverTokens - Token budget for the previous observations context
314
+ * @returns Array of message objects for the LLM call
315
+ */
316
+ export function buildObserverMessages(messages, previousObservations, previousObserverTokens) {
317
+ const result = [];
318
+ // 1. Previous observations context (if available)
319
+ if (previousObservations && previousObservations.trim().length > 0) {
320
+ const preamble = 'These are the observations that have already been captured. Do not repeat them. Only add NEW observations from the messages below.\n\n';
321
+ const truncated = tailTruncateToTokenBudget(previousObservations, previousObserverTokens);
322
+ result.push({ role: 'user', content: preamble + truncated });
323
+ }
324
+ // 2. Formatted message history (timestamps from message metadata)
325
+ const formatted = formatMessagesForObserver(messages);
326
+ result.push({ role: 'user', content: formatted });
327
+ // 3. Task instruction
328
+ result.push({
329
+ role: 'user',
330
+ content: 'Extract observations from the message history above. Follow the output format exactly.',
331
+ });
332
+ return result;
333
+ }
334
+ /**
335
+ * Tail-truncate a string to fit within a token budget.
336
+ *
337
+ * Keeps the end of the string (most recent observations) and trims
338
+ * from the beginning if the string exceeds the budget.
339
+ */
340
+ function tailTruncateToTokenBudget(text, tokenBudget) {
341
+ const currentTokens = estimateTokens(text);
342
+ if (currentTokens <= tokenBudget)
343
+ return text;
344
+ // Estimate chars to keep (tokens * 4 chars/token approximation)
345
+ const charsToKeep = tokenBudget * 4;
346
+ if (charsToKeep >= text.length)
347
+ return text;
348
+ const truncated = text.slice(text.length - charsToKeep);
349
+ // Try to start at a line boundary for cleaner output
350
+ const firstNewline = truncated.indexOf('\n');
351
+ if (firstNewline > 0 && firstNewline < truncated.length * 0.2) {
352
+ return '[...truncated...]\n' + truncated.slice(firstNewline + 1);
353
+ }
354
+ return '[...truncated...]\n' + truncated;
355
+ }
356
+ // ---------------------------------------------------------------------------
357
+ // Degenerate Repetition Detection
358
+ // ---------------------------------------------------------------------------
359
+ /**
360
+ * Check if the output contains degenerate repetition.
361
+ *
362
+ * Detects a line appearing 5+ times consecutively, which is a known
363
+ * failure mode of LLMs under certain conditions (e.g., high temperature,
364
+ * long context, repetitive input patterns).
365
+ *
366
+ * @param text - The text to check for repetition
367
+ * @returns true if degenerate repetition is detected
368
+ */
369
+ export function detectDegenerateRepetition(text) {
370
+ const lines = text.split('\n');
371
+ if (lines.length < 5)
372
+ return false;
373
+ let consecutiveCount = 1;
374
+ let previousLine = lines[0];
375
+ for (let i = 1; i < lines.length; i++) {
376
+ const currentLine = lines[i];
377
+ // Skip empty lines for comparison
378
+ if (currentLine.trim() === '' && previousLine.trim() === '') {
379
+ continue;
380
+ }
381
+ if (currentLine === previousLine && currentLine.trim().length > 0) {
382
+ consecutiveCount++;
383
+ if (consecutiveCount >= 5)
384
+ return true;
385
+ }
386
+ else {
387
+ consecutiveCount = 1;
388
+ previousLine = currentLine;
389
+ }
390
+ }
391
+ return false;
392
+ }
393
+ // ---------------------------------------------------------------------------
394
+ // Runner
395
+ // ---------------------------------------------------------------------------
396
+ /**
397
+ * Run the observer LLM call to extract observations from messages.
398
+ *
399
+ * Orchestrates the full observer pipeline:
400
+ * 1. Builds the system prompt (with optional custom instructions)
401
+ * 2. Builds the message array (with previous observations context)
402
+ * 3. Calls the LLM via `complete`
403
+ * 4. Parses the structured output
404
+ * 5. Detects and retries on degenerate repetition (once)
405
+ *
406
+ * @param complete - The LLM completion function
407
+ * @param messages - The conversation messages to observe
408
+ * @param previousObservations - Previous observations for deduplication
409
+ * @param config - Observer configuration
410
+ * @returns Parsed observer output with observations, current task, and suggested response
411
+ */
412
+ export async function runObserver(complete, messages, previousObservations, config) {
413
+ const systemPrompt = buildObserverPrompt(previousObservations, config.previousObserverTokens, config.observerInstruction);
414
+ const observerMessages = buildObserverMessages(messages, previousObservations, config.previousObserverTokens);
415
+ const raw = await complete({ systemPrompt, messages: observerMessages });
416
+ const output = parseObserverOutput(raw);
417
+ // Detect degenerate repetition and retry once
418
+ if (detectDegenerateRepetition(output.observations)) {
419
+ const retryRaw = await complete({ systemPrompt, messages: observerMessages });
420
+ return parseObserverOutput(retryRaw);
421
+ }
422
+ return output;
423
+ }
424
+ //# sourceMappingURL=observer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observer.js","sourceRoot":"","sources":["../../../src/compaction/observational/observer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Recall tool: search through past conversation history.
3
+ *
4
+ * The consumer provides a search function via RecallConfig. This module
5
+ * wraps it into a CortexTool that the agent can invoke to retrieve
6
+ * specific details from persisted messages. Observations include
7
+ * timestamps, enabling temporal anchoring for precise recall queries.
8
+ *
9
+ * Reference: docs/cortex/observational-memory-architecture.md (Recall Tool)
10
+ */
11
+ import type { CortexTool } from '../../tool-contract.js';
12
+ import type { RecallConfig } from './types.js';
13
+ /**
14
+ * Create a CortexTool that wraps the consumer's recall search function.
15
+ *
16
+ * The returned tool lets the agent search through persisted conversation
17
+ * history using a free-text query and optional time range derived from
18
+ * observation timestamps.
19
+ */
20
+ export declare function createRecallTool(recallConfig: RecallConfig): CortexTool<{
21
+ query: string;
22
+ timeRange?: {
23
+ start?: string;
24
+ end?: string;
25
+ };
26
+ }, string>;
27
+ //# sourceMappingURL=recall-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall-tool.d.ts","sourceRoot":"","sources":["../../../src/compaction/observational/recall-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,YAAY,CAAC;AA0E7D;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,YAAY,GAAG,UAAU,CAAC;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C,EAAE,MAAM,CAAC,CAgCT"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Recall tool: search through past conversation history.
3
+ *
4
+ * The consumer provides a search function via RecallConfig. This module
5
+ * wraps it into a CortexTool that the agent can invoke to retrieve
6
+ * specific details from persisted messages. Observations include
7
+ * timestamps, enabling temporal anchoring for precise recall queries.
8
+ *
9
+ * Reference: docs/cortex/observational-memory-architecture.md (Recall Tool)
10
+ */
11
+ import { Type } from 'typebox';
12
+ // ---------------------------------------------------------------------------
13
+ // Schema
14
+ // ---------------------------------------------------------------------------
15
+ const RecallParams = Type.Object({
16
+ query: Type.String({
17
+ description: 'What to search for in past conversation history',
18
+ }),
19
+ timeRange: Type.Optional(Type.Object({
20
+ start: Type.Optional(Type.String({ description: 'ISO date string for range start' })),
21
+ end: Type.Optional(Type.String({ description: 'ISO date string for range end' })),
22
+ }, {
23
+ description: 'Optional time range to narrow results. Use timestamps from your observations.',
24
+ })),
25
+ });
26
+ // ---------------------------------------------------------------------------
27
+ // Constants
28
+ // ---------------------------------------------------------------------------
29
+ /** Maximum number of results to include in the formatted output. */
30
+ const MAX_RESULTS = 10;
31
+ /** Maximum character length per individual result content. */
32
+ const MAX_RESULT_CHARS = 2_000;
33
+ // ---------------------------------------------------------------------------
34
+ // Formatting
35
+ // ---------------------------------------------------------------------------
36
+ function formatResult(result) {
37
+ const role = result.role ?? result.type;
38
+ const timestamp = result.timestamp.toISOString();
39
+ const content = result.content.length > MAX_RESULT_CHARS
40
+ ? result.content.slice(0, MAX_RESULT_CHARS) + '... (truncated)'
41
+ : result.content;
42
+ return `[${role}] (${timestamp}): ${content}`;
43
+ }
44
+ function formatResults(results) {
45
+ if (results.length === 0) {
46
+ return 'No results found for your query.';
47
+ }
48
+ const limited = results.slice(0, MAX_RESULTS);
49
+ const lines = limited.map(formatResult);
50
+ if (results.length > MAX_RESULTS) {
51
+ lines.push(`\n(${results.length - MAX_RESULTS} additional results omitted)`);
52
+ }
53
+ return lines.join('\n\n');
54
+ }
55
+ // ---------------------------------------------------------------------------
56
+ // Tool factory
57
+ // ---------------------------------------------------------------------------
58
+ /**
59
+ * Create a CortexTool that wraps the consumer's recall search function.
60
+ *
61
+ * The returned tool lets the agent search through persisted conversation
62
+ * history using a free-text query and optional time range derived from
63
+ * observation timestamps.
64
+ */
65
+ export function createRecallTool(recallConfig) {
66
+ return {
67
+ name: 'recall',
68
+ description: 'Search through past conversation history for specific details. ' +
69
+ 'Use when your observations mention something but lack the detail needed, ' +
70
+ 'or when you need exact content (code, errors, quotes, URLs). ' +
71
+ 'Include a timeRange from your observation timestamps for precision.',
72
+ parameters: RecallParams,
73
+ async execute(params) {
74
+ const { query, timeRange } = params;
75
+ // Build the time range object without assigning undefined to optional
76
+ // properties (exactOptionalPropertyTypes is enabled).
77
+ let options;
78
+ if (timeRange) {
79
+ const range = {};
80
+ if (timeRange.start) {
81
+ range.start = new Date(timeRange.start);
82
+ }
83
+ if (timeRange.end) {
84
+ range.end = new Date(timeRange.end);
85
+ }
86
+ options = { timeRange: range };
87
+ }
88
+ const results = await recallConfig.search(query, options);
89
+ return formatResults(results);
90
+ },
91
+ };
92
+ }
93
+ //# sourceMappingURL=recall-tool.js.map