@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
package/src/types.ts ADDED
@@ -0,0 +1,1057 @@
1
+ /**
2
+ * Core types for the @animus-labs/cortex package.
3
+ *
4
+ * These types define the public API surface for CortexAgent configuration,
5
+ * context management, error classification, working tags, budget guards,
6
+ * compaction, events, and model tiers.
7
+ *
8
+ * References:
9
+ * - cortex-architecture.md
10
+ * - context-manager.md
11
+ * - model-tiers.md
12
+ * - error-recovery.md
13
+ * - working-tags.md
14
+ */
15
+
16
+ import type { CortexModel } from './model-wrapper.js';
17
+ import type {
18
+ ObservationalMemoryConfig,
19
+ ObservationEvent,
20
+ ReflectionEvent,
21
+ } from './compaction/observational/types.js';
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Logger
25
+ // ---------------------------------------------------------------------------
26
+
27
+ /**
28
+ * Pluggable logger interface for Cortex diagnostics.
29
+ *
30
+ * Cortex never decides where logs go. The consumer provides an implementation
31
+ * via CortexAgentConfig.logger. If omitted, all logging is silently discarded.
32
+ *
33
+ * All methods share the same signature for uniformity. The optional `data`
34
+ * parameter carries structured context (token counts, server names, error
35
+ * objects, etc.) that the consumer can serialize or inspect as needed.
36
+ *
37
+ * Compatible with `console` for quick development: `logger: console` works
38
+ * because console methods accept variadic args and ignore the extra object.
39
+ */
40
+ export interface CortexLogger {
41
+ debug(message: string, data?: Record<string, unknown>): void;
42
+ info(message: string, data?: Record<string, unknown>): void;
43
+ warn(message: string, data?: Record<string, unknown>): void;
44
+ error(message: string, data?: Record<string, unknown>): void;
45
+ }
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // Usage
49
+ // ---------------------------------------------------------------------------
50
+
51
+ /**
52
+ * Token usage and cost data from a single LLM call.
53
+ * Mirrors the pi-ai AssistantMessage.usage structure but is decoupled
54
+ * from pi-ai's types to avoid hard runtime dependencies.
55
+ */
56
+ export interface CortexUsage {
57
+ /** Input (prompt) tokens. */
58
+ input: number;
59
+ /** Output (completion) tokens. */
60
+ output: number;
61
+ /** Cache-read tokens (tokens served from cache). */
62
+ cacheRead: number;
63
+ /** Cache-write tokens (tokens written to cache). */
64
+ cacheWrite: number;
65
+ /** Total tokens (input + output). */
66
+ totalTokens: number;
67
+ /** Cost breakdown in USD. */
68
+ cost: {
69
+ input: number;
70
+ output: number;
71
+ cacheRead: number;
72
+ cacheWrite: number;
73
+ total: number;
74
+ };
75
+ /** Model identifier string (if available from the response). */
76
+ model?: string;
77
+ }
78
+
79
+ // ---------------------------------------------------------------------------
80
+ // Session Usage
81
+ // ---------------------------------------------------------------------------
82
+
83
+ /**
84
+ * Accumulated usage data across the lifetime of a session.
85
+ *
86
+ * Unlike BudgetGuard (which resets per agentic loop for enforcement),
87
+ * SessionUsage accumulates across all loops for reporting and persistence.
88
+ * Cortex tracks this in memory; consumers persist and restore as needed.
89
+ */
90
+ export interface SessionUsage {
91
+ /** Total cost in USD across all turns. */
92
+ totalCost: number;
93
+ /** Total number of LLM turns across all loops. */
94
+ totalTurns: number;
95
+ /** Accumulated token counts across all turns. */
96
+ tokens: {
97
+ input: number;
98
+ output: number;
99
+ cacheRead: number;
100
+ cacheWrite: number;
101
+ };
102
+ }
103
+
104
+ // ---------------------------------------------------------------------------
105
+ // Lifecycle
106
+ // ---------------------------------------------------------------------------
107
+
108
+ /**
109
+ * The lifecycle state of a CortexAgent instance.
110
+ *
111
+ * CREATED -> ACTIVE -> DESTROYED
112
+ *
113
+ * abort() returns the agent to ACTIVE (still usable).
114
+ * destroy() transitions to DESTROYED (all resources released).
115
+ */
116
+ export type CortexLifecycleState = 'created' | 'active' | 'destroyed';
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Thinking / Effort Level
120
+ // ---------------------------------------------------------------------------
121
+
122
+ /**
123
+ * Consumer-facing thinking/effort level.
124
+ *
125
+ * "max" maps to pi-ai/pi-agent-core's "xhigh" internally.
126
+ * "off" disables extended thinking entirely.
127
+ */
128
+ export type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'max';
129
+
130
+ /**
131
+ * Describes a model's thinking/reasoning capabilities.
132
+ * Returned by CortexAgent.getModelThinkingCapabilities().
133
+ */
134
+ export interface ModelThinkingCapabilities {
135
+ /** Whether the model supports extended thinking at all. */
136
+ supportsThinking: boolean;
137
+ /** Whether the model supports the "max" (xhigh) thinking level. */
138
+ supportsMax: boolean;
139
+ /** Exact thinking levels this model accepts, using Cortex's public names. */
140
+ supportedLevels: ThinkingLevel[];
141
+ }
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // Tool Permissions
145
+ // ---------------------------------------------------------------------------
146
+
147
+ export type CortexToolPermissionDecision = 'allow' | 'block' | 'ask';
148
+
149
+ export interface CortexToolPermissionResult {
150
+ decision: CortexToolPermissionDecision;
151
+ reason?: string;
152
+ }
153
+
154
+ // ---------------------------------------------------------------------------
155
+ // Agent Configuration
156
+ // ---------------------------------------------------------------------------
157
+
158
+ /**
159
+ * Configuration for creating a CortexAgent instance.
160
+ *
161
+ * The `model` field uses CortexModel as the public boundary.
162
+ * Consumers obtain these handles from ProviderManager and pass them back to
163
+ * CortexAgent. Raw pi-ai model objects stay inside Cortex.
164
+ */
165
+ export interface CortexAgentConfig {
166
+ /** Primary model for the agentic loop, THOUGHT, REFLECT, and all consumer-facing work. */
167
+ model: CortexModel;
168
+
169
+ /**
170
+ * Initial application/base prompt.
171
+ * Cortex composes its operational sections around this prompt.
172
+ */
173
+ initialBasePrompt?: string;
174
+
175
+ /**
176
+ * Utility model for internal operations (WebFetch summarization, safety classifier).
177
+ * - `'default'`: Cortex selects from a built-in mapping based on the primary model's provider.
178
+ * - A CortexModel: explicit utility model (must be same provider as primary).
179
+ * - `undefined`: same as `'default'`.
180
+ */
181
+ utilityModel?: CortexModel | 'default';
182
+
183
+ /** Working directory for file operations (Bash, Read, Write, Edit, Glob, Grep). */
184
+ workingDirectory: string;
185
+
186
+ /**
187
+ * Callback to resolve API keys by provider name.
188
+ * Throws on failure (classified as authentication error).
189
+ * Returns the API key string on success. Must never return empty string.
190
+ */
191
+ getApiKey?: (provider: string) => Promise<string>;
192
+
193
+ /** Ordered list of context slot names. Order defines position in the message array. */
194
+ slots?: string[];
195
+
196
+ /** Working tags configuration. */
197
+ workingTags?: {
198
+ /** Whether to enable working tags. Default: true. */
199
+ enabled?: boolean;
200
+ };
201
+
202
+ /** Budget guard configuration. */
203
+ budgetGuard?: {
204
+ /** Maximum number of LLM turns before force-stopping the loop. Default: Infinity. */
205
+ maxTurns?: number;
206
+ /** Maximum cost in USD before force-stopping the loop. Default: Infinity. */
207
+ maxCost?: number;
208
+ };
209
+
210
+ /** Maximum number of concurrent sub-agents. */
211
+ maxConcurrentSubAgents?: number;
212
+
213
+ /**
214
+ * Tool execution strategy for assistant messages with multiple tool calls.
215
+ * Defaults to sequential for deterministic permission, logging, and UI order.
216
+ */
217
+ toolExecution?: 'sequential' | 'parallel';
218
+
219
+ /** WebFetch tool configuration. */
220
+ webFetch?: {
221
+ /** Maximum number of web fetches per agentic loop. */
222
+ maxPerLoop?: number;
223
+ };
224
+
225
+ /** Bash tool configuration. */
226
+ bash?: {
227
+ /** Token threshold at which Bash auto-yields control back to the agent. */
228
+ autoYieldThreshold?: number;
229
+ /** Path to the shell executable. */
230
+ shellPath?: string;
231
+ };
232
+
233
+ /**
234
+ * Disable specific built-in tools by name.
235
+ * Built-in tools (Read, Write, Edit, Glob, Grep, Bash, WebFetch, TaskOutput)
236
+ * are registered automatically. Use this to exclude tools the agent should not have.
237
+ * SubAgent and load_skill are controlled separately via enableSubAgentTool/enableLoadSkillTool.
238
+ */
239
+ disableTools?: string[];
240
+
241
+ /**
242
+ * Structured permission result for a tool call.
243
+ * - `allow`: proceed immediately
244
+ * - `block`: deny the call
245
+ * - `ask`: consumer requires approval before the call can proceed
246
+ */
247
+ resolvePermission?: (
248
+ toolName: string,
249
+ toolArgs: unknown,
250
+ ) => Promise<boolean | CortexToolPermissionResult>;
251
+
252
+ /**
253
+ * Initial thinking/effort level for the agentic loop.
254
+ * Omit to use the pi-agent-core default (medium).
255
+ * "max" maps to pi-ai/pi-agent-core's "xhigh" internally.
256
+ * Consumers can use getModelThinkingCapabilities() and clampThinkingLevel()
257
+ * to avoid exposing unsupported levels.
258
+ */
259
+ thinkingLevel?: ThinkingLevel;
260
+
261
+ /**
262
+ * Limit the effective context window for compaction calculations.
263
+ * Clamped to min(limit, model.contextWindow) with a floor of MINIMUM_CONTEXT_WINDOW (16K).
264
+ * null or undefined = use the model's full context window.
265
+ */
266
+ contextWindowLimit?: number | null;
267
+
268
+ /** Compaction configuration. All layers are always active. */
269
+ compaction?: Partial<CortexCompactionConfig>;
270
+
271
+ /**
272
+ * Deferred tool loading. When enabled, tools marked for deferral are NOT
273
+ * included in the `tools` array sent on every API turn. Instead, their
274
+ * names appear in an internally-managed `_available_tools` slot, and the
275
+ * agent uses the auto-registered `ToolSearch` tool to load specific tools
276
+ * on demand.
277
+ *
278
+ * Useful when consumers connect MCP servers with many tools: schemas are
279
+ * only paid for once a tool is actually needed, instead of every turn.
280
+ */
281
+ deferredTools?: DeferredToolsConfig;
282
+
283
+ /**
284
+ * Persists oversized tool results to disk and returns the file path.
285
+ *
286
+ * When configured, large tool results (>25K tokens by default) are
287
+ * replaced in the conversation with a bookend preview (head + tail)
288
+ * plus a file reference, so the model can use the Read tool to access
289
+ * the full content on demand.
290
+ *
291
+ * Used by both the proactive tool execution interceptor and the
292
+ * reactive compaction paths (microcompaction trim, aggregate budget
293
+ * enforcement). Consumer owns the storage location and cleanup.
294
+ *
295
+ * If both this and `compaction.microcompaction.persistResult` are set,
296
+ * this top-level setting wins (and is propagated to microcompaction).
297
+ */
298
+ persistResult?: PersistResultFn;
299
+
300
+ /**
301
+ * Per-tool token threshold overrides for the result-persistence interceptor.
302
+ *
303
+ * Tools not listed here use the built-in defaults (Bash: 7,500 to keep
304
+ * verbose command output tight; everything else: 25,000).
305
+ *
306
+ * Useful for tuning specific MCP tools or custom tools whose output has
307
+ * unusual size characteristics (e.g., a tool that returns large JSON payloads
308
+ * where you want a smaller cap, or a research tool whose output you want to
309
+ * keep more of in context).
310
+ */
311
+ toolResultThresholds?: Record<string, number>;
312
+
313
+ /**
314
+ * Consumer-set environment variables that propagate to ALL subprocesses
315
+ * (Bash tool, MCP stdio servers), bypassing the security blocklist.
316
+ *
317
+ * Use case: macOS dock icon suppression requires DYLD_INSERT_LIBRARIES
318
+ * and ANIMUS_DOCK_SUPPRESS_ADDON to propagate to child processes, but
319
+ * the safe-env blocklist strips DYLD_ prefixed variables by default.
320
+ * envOverrides are merged ON TOP of the sanitized environment, restoring
321
+ * these specific variables.
322
+ */
323
+ envOverrides?: Record<string, string>;
324
+
325
+ /**
326
+ * Optional logger for Cortex internal diagnostics.
327
+ * If omitted, all internal logging is silently discarded (no-op).
328
+ * The library never decides where logs go; only the consumer does.
329
+ *
330
+ * Compatible with `console` for quick development: `{ logger: console }`.
331
+ */
332
+ logger?: CortexLogger;
333
+
334
+ /**
335
+ * Optional diagnostics for investigating prompt or provider stalls.
336
+ * All diagnostics are opt-in and should remain disabled in normal use.
337
+ */
338
+ diagnostics?: CortexDiagnosticsConfig;
339
+ }
340
+
341
+ /**
342
+ * Prompt watchdog diagnostics configuration.
343
+ *
344
+ * Emits bounded lifecycle and heartbeat logs around prompt() and abort().
345
+ * Intended for investigating freezes or hung provider calls.
346
+ */
347
+ export interface PromptWatchdogDiagnosticsConfig {
348
+ /** Whether prompt watchdog diagnostics are enabled. Default: false. */
349
+ enabled?: boolean;
350
+ /** Heartbeat interval while a prompt is in flight. Default: 1000ms. */
351
+ heartbeatIntervalMs?: number;
352
+ /** Warn if abort waits longer than this for idle. Default: 2000ms. */
353
+ abortWaitWarningMs?: number;
354
+ }
355
+
356
+ /**
357
+ * Optional diagnostics for Cortex internals.
358
+ *
359
+ * These are intentionally narrow and structured so consumers can opt into
360
+ * targeted investigations without turning normal debug logging into trace spam.
361
+ */
362
+ export interface CortexDiagnosticsConfig {
363
+ /** Prompt and abort watchdog logs for freeze investigation. */
364
+ promptWatchdog?: PromptWatchdogDiagnosticsConfig;
365
+ }
366
+
367
+ // ---------------------------------------------------------------------------
368
+ // Deferred Tools
369
+ // ---------------------------------------------------------------------------
370
+
371
+ /**
372
+ * Configuration for deferred tool loading.
373
+ *
374
+ * Reference: docs/cortex/tools/tool-search.md (TBD)
375
+ */
376
+ export interface DeferredToolsConfig {
377
+ /**
378
+ * Master switch. When false (default), all tools are sent on every turn
379
+ * exactly as before. When true, tools marked for deferral are pulled out
380
+ * of the per-turn tools array and announced by name in the
381
+ * `_available_tools` slot instead.
382
+ */
383
+ enabled?: boolean;
384
+
385
+ /**
386
+ * When true (default), all MCP tools are deferred. When false, MCP tools
387
+ * are sent in full like built-ins. Has no effect when `enabled` is false.
388
+ */
389
+ deferMcp?: boolean;
390
+
391
+ /**
392
+ * Tool names that should never be deferred even if they match deferral
393
+ * criteria (overrides `shouldDefer` and `deferMcp` for the named tools).
394
+ * Use this to keep specific MCP tools always loaded.
395
+ */
396
+ alwaysLoad?: string[];
397
+ }
398
+
399
+ // ---------------------------------------------------------------------------
400
+ // Context Manager
401
+ // ---------------------------------------------------------------------------
402
+
403
+ /**
404
+ * Configuration for the ContextManager.
405
+ *
406
+ * Slots define the ordered list of persistent content blocks at the start
407
+ * of the message array. Order determines position (first = most stable,
408
+ * best prefix cache hit rate).
409
+ */
410
+ export interface ContextManagerConfig {
411
+ /** Ordered list of slot names. */
412
+ slots: string[];
413
+ }
414
+
415
+ // ---------------------------------------------------------------------------
416
+ // Error Classification
417
+ // ---------------------------------------------------------------------------
418
+
419
+ /**
420
+ * Error categories for classifying LLM and network errors.
421
+ * Checked in priority order (first match wins).
422
+ */
423
+ export type ErrorCategory =
424
+ | 'authentication'
425
+ | 'rate_limit'
426
+ | 'context_overflow'
427
+ | 'server_error'
428
+ | 'network'
429
+ | 'cancelled'
430
+ | 'unknown';
431
+
432
+ /**
433
+ * Error severity levels.
434
+ * - fatal: unrecoverable, stop processing (e.g., invalid API key)
435
+ * - retry: transient, can be retried (e.g., rate limit, server error, network)
436
+ * - recoverable: can be handled without retry (e.g., context overflow triggers compaction)
437
+ */
438
+ export type ErrorSeverity = 'fatal' | 'retry' | 'recoverable';
439
+
440
+ /**
441
+ * A classified error with category, severity, original message, and suggested action.
442
+ */
443
+ export interface ClassifiedError {
444
+ /** The error category determined by pattern matching. */
445
+ category: ErrorCategory;
446
+ /** The severity level for the category. */
447
+ severity: ErrorSeverity;
448
+ /** The original error message string. */
449
+ originalMessage: string;
450
+ /** Human-readable suggested action, or undefined if no action is needed. */
451
+ suggestedAction?: string;
452
+ }
453
+
454
+ // ---------------------------------------------------------------------------
455
+ // Working Tags
456
+ // ---------------------------------------------------------------------------
457
+
458
+ /**
459
+ * Structured output from parsing working tags in agent text.
460
+ *
461
+ * Working tags separate internal reasoning (<working>...</working>) from
462
+ * user-facing communication. Both remain in conversation history; the
463
+ * difference is only in delivery.
464
+ */
465
+ export interface AgentTextOutput {
466
+ /** Text intended for the user (working tag content stripped, whitespace normalized). */
467
+ userFacing: string;
468
+ /** Content from inside <working> tags, concatenated. Null if no working tags present. */
469
+ working: string | null;
470
+ /** The original unparsed text exactly as the agent produced it. */
471
+ raw: string;
472
+ }
473
+
474
+ // ---------------------------------------------------------------------------
475
+ // Tool Results
476
+ // ---------------------------------------------------------------------------
477
+
478
+ /**
479
+ * Structured tool result with content array and typed details.
480
+ */
481
+ export interface ToolContentDetails<T> {
482
+ content: Array<
483
+ | { type: 'text'; text: string }
484
+ | { type: 'image'; data: string; mimeType: string }
485
+ >;
486
+ details: T;
487
+ }
488
+
489
+ // ---------------------------------------------------------------------------
490
+ // Tool Execute Context
491
+ // ---------------------------------------------------------------------------
492
+
493
+ /**
494
+ * Context passed to tool execute functions by the pi-agent-core adapter.
495
+ *
496
+ * Tools that want streaming support accept this as an optional second parameter.
497
+ * Tools that don't need it simply ignore it (backward compatible).
498
+ */
499
+ export interface ToolExecuteContext {
500
+ /** Unique identifier for this tool call. */
501
+ toolCallId: string;
502
+ /** Abort signal for cancellation. */
503
+ signal?: AbortSignal;
504
+ /**
505
+ * Callback for emitting incremental results during execution.
506
+ * Pi-agent-core emits these as tool_execution_update events.
507
+ * Useful for long-running tools (bash, sub-agents) that want to
508
+ * stream progress to the consumer's UI.
509
+ */
510
+ onUpdate?: (partialResult: ToolContentDetails<unknown>) => void;
511
+ }
512
+
513
+ // ---------------------------------------------------------------------------
514
+ // Event Payloads
515
+ // ---------------------------------------------------------------------------
516
+
517
+ /**
518
+ * Typed payload for tool_call_start events.
519
+ */
520
+ export interface ToolCallStartPayload {
521
+ toolCallId: string;
522
+ toolName: string;
523
+ args: Record<string, unknown>;
524
+ }
525
+
526
+ /**
527
+ * Typed payload for tool_call_update events.
528
+ */
529
+ export interface ToolCallUpdatePayload {
530
+ toolCallId: string;
531
+ toolName: string;
532
+ args: Record<string, unknown>;
533
+ partialResult: ToolContentDetails<unknown>;
534
+ }
535
+
536
+ /**
537
+ * Typed payload for tool_call_end events.
538
+ */
539
+ export interface ToolCallEndPayload {
540
+ toolCallId: string;
541
+ toolName: string;
542
+ result: ToolContentDetails<unknown>;
543
+ durationMs: number;
544
+ isError: boolean;
545
+ error?: string;
546
+ }
547
+
548
+ // ---------------------------------------------------------------------------
549
+ // Budget Guard
550
+ // ---------------------------------------------------------------------------
551
+
552
+ /**
553
+ * Budget guard configuration with explicit limits.
554
+ * Both default to Infinity (no enforcement).
555
+ */
556
+ export interface BudgetGuardConfig {
557
+ /** Maximum number of LLM turns. Default: Infinity. */
558
+ maxTurns: number;
559
+ /** Maximum cost in USD. Default: Infinity. */
560
+ maxCost: number;
561
+ }
562
+
563
+ // ---------------------------------------------------------------------------
564
+ // Compaction
565
+ // ---------------------------------------------------------------------------
566
+
567
+ /**
568
+ * Tool category for microcompaction retention decisions.
569
+ * - rereadable: agent can re-read the source (files, directories)
570
+ * - non-reproducible: output may change or cost to re-fetch (web, APIs)
571
+ * - ephemeral: stale quickly, trivially re-runnable (ls, git status)
572
+ * - computational: small results from computations, non-reproducible without re-running
573
+ */
574
+ export type ToolCategory = 'rereadable' | 'non-reproducible' | 'ephemeral' | 'computational';
575
+
576
+ /**
577
+ * Microcompaction configuration: progressive tool result trimming.
578
+ */
579
+ /**
580
+ * Callback invoked when microcompaction persists a cleared tool result to disk.
581
+ * The consumer implements the actual I/O and returns the file path.
582
+ *
583
+ * @param content - The full original tool result content
584
+ * @param metadata - Information about the result being persisted
585
+ * @returns The file path where the content was saved
586
+ */
587
+ export type PersistResultFn = (
588
+ content: string,
589
+ metadata: {
590
+ toolName: string;
591
+ category: ToolCategory;
592
+ /** Present when called from the proactive tool execution interceptor. */
593
+ toolCallId?: string;
594
+ /** Present when called from compaction (reactive paths). */
595
+ messageIndex?: number;
596
+ },
597
+ ) => Promise<string>;
598
+
599
+ export interface MicrocompactionConfig {
600
+ /** Maximum tokens for a single tool result at insertion time. Default: 50000. */
601
+ maxResultTokens: number;
602
+
603
+ // --- Cache-aware gating ---
604
+ /**
605
+ * Minimum context utilization ratio below which L1 never trims, even when
606
+ * the cache is cold. Prevents pointless work on nearly empty contexts.
607
+ * Default: 0.25 (25%).
608
+ */
609
+ trimFloorRatio: number;
610
+
611
+ // --- Hot zone (token-offset recency window) ---
612
+ /**
613
+ * Absolute floor for the hot zone size (in tokens). Tool results within the
614
+ * hot zone of the most recent message are never trimmed. The effective hot
615
+ * zone is `max(hotZoneMinTokens, contextWindow * hotZoneRatio)`.
616
+ * Default: 16000.
617
+ */
618
+ hotZoneMinTokens: number;
619
+ /**
620
+ * Hot zone as a fraction of the context window. Wins over the floor on
621
+ * very large windows. Default: 0.05 (5%).
622
+ */
623
+ hotZoneRatio: number;
624
+ /**
625
+ * Multiplier applied to the hot zone for non-reproducible tools. When
626
+ * undefined, resolves to 1.0 if a persistResult callback is configured
627
+ * (full content recoverable from disk) or 1.5 if not (some buffer since
628
+ * content is lost on trim).
629
+ */
630
+ extendedRetentionMultiplier?: number;
631
+
632
+ // --- Progressive bookend degradation ---
633
+ /** Bookend size at the hot zone boundary (chars per side). Default: 2000. */
634
+ bookendMaxChars: number;
635
+ /** Bookend size at the far end of the degradation span (chars per side). Default: 256. */
636
+ bookendMinChars: number;
637
+ /**
638
+ * The degradation span as a fraction of the context window. Bookend size
639
+ * interpolates linearly from bookendMaxChars to bookendMinChars across this
640
+ * span. Beyond the span, results become placeholder or clear based on tool
641
+ * category. Default: 0.40 (40%).
642
+ */
643
+ degradationSpanRatio: number;
644
+
645
+ // --- Tool categorization ---
646
+ /** Tool name to category mapping. Unregistered tools default to standard retention. */
647
+ toolCategories?: Record<string, ToolCategory>;
648
+
649
+ // --- Persistence ---
650
+ /**
651
+ * Callback to persist tool results to disk before destructive trim actions
652
+ * (bookend, placeholder, clear). When set, the in-context replacement
653
+ * includes a file path reference the agent can Read to recover full content.
654
+ * Only fires for non-reproducible and computational tools.
655
+ *
656
+ * Typically set at the top-level CortexAgentConfig.persistResult and
657
+ * propagated here automatically.
658
+ */
659
+ persistResult?: PersistResultFn;
660
+
661
+ /** Maximum aggregate tokens for all tool results in a single turn. Default: 150000. */
662
+ maxAggregateTurnTokens?: number;
663
+ }
664
+
665
+ /**
666
+ * Conversation summarization (Layer 2) configuration.
667
+ */
668
+ export interface CompactionConfig {
669
+ /** Context usage ratio that triggers summarization. Default: 0.70. */
670
+ threshold: number;
671
+ /** Number of recent turns preserved verbatim. Default: 6. */
672
+ preserveRecentTurns: number;
673
+ /** Custom summarization prompt. If provided, replaces the default prompt. */
674
+ customPrompt?: string;
675
+ /** Maximum Layer 2 retry attempts before falling through to Layer 3. Default: 3. */
676
+ maxRetries?: number;
677
+ /** Delay in ms between Layer 2 retry attempts. Default: 2000. */
678
+ retryDelayMs?: number;
679
+ }
680
+
681
+ /**
682
+ * Emergency truncation (Layer 3) configuration.
683
+ */
684
+ export interface FailsafeConfig {
685
+ /** Context usage ratio that triggers emergency truncation. Default: 0.90. */
686
+ threshold: number;
687
+ }
688
+
689
+ /**
690
+ * Adaptive threshold configuration for Layer 2 compaction.
691
+ *
692
+ * Adjusts the compaction trigger point based on how recently the user last
693
+ * interacted. When the user is idle (no messages for a while), the threshold
694
+ * is lowered so compaction fires earlier, reducing token costs during interval
695
+ * ticks where the agent is thinking to itself.
696
+ *
697
+ * Three windows:
698
+ * - Recent (< recentWindowMs): no threshold reduction
699
+ * - Moderate (recentWindowMs .. idleWindowMs): moderateReduction applied
700
+ * - Idle (> idleWindowMs): idleReduction applied
701
+ *
702
+ * The effective threshold is: config.compaction.threshold - reduction
703
+ */
704
+ export interface AdaptiveThresholdConfig {
705
+ /** Whether adaptive thresholds are enabled. Default: true. */
706
+ enabled: boolean;
707
+ /** Milliseconds within which interaction is considered "recent". Default: 300000 (5 min). */
708
+ recentWindowMs: number;
709
+ /** Milliseconds beyond which interaction is considered "idle". Default: 1800000 (30 min). */
710
+ idleWindowMs: number;
711
+ /** Threshold reduction when interaction is recent. Default: 0.0. */
712
+ recentReduction: number;
713
+ /** Threshold reduction when interaction is moderate. Default: 0.10. */
714
+ moderateReduction: number;
715
+ /** Threshold reduction when interaction is idle. Default: 0.20. */
716
+ idleReduction: number;
717
+ }
718
+
719
+ /**
720
+ * Full compaction configuration for CortexAgent.
721
+ *
722
+ * Supports two strategies:
723
+ * - `'observational'` (default): Observer/Reflector background compression
724
+ * replaces L1 threshold trimming and L2 summarization. L3 emergency
725
+ * truncation remains active as a safety valve.
726
+ * - `'classic'`: The existing L1 + L2 + L3 system operates unchanged.
727
+ *
728
+ * The failsafe (L3) is always active regardless of strategy.
729
+ */
730
+ export interface CortexCompactionConfig {
731
+ /**
732
+ * Compaction strategy selection.
733
+ * - `'observational'`: Background observer/reflector compression (default).
734
+ * - `'classic'`: Traditional L1 microcompaction + L2 summarization.
735
+ * @default 'observational'
736
+ */
737
+ strategy?: 'observational' | 'classic';
738
+
739
+ /** Microcompaction (L1) configuration. Used when strategy is 'classic'. */
740
+ microcompaction: MicrocompactionConfig;
741
+ /** Conversation summarization (L2) configuration. Used when strategy is 'classic'. */
742
+ compaction: CompactionConfig;
743
+ /** Emergency truncation (L3) configuration. Always active regardless of strategy. */
744
+ failsafe: FailsafeConfig;
745
+ /** Adaptive threshold configuration. Adjusts Layer 2 trigger based on interaction recency. Used when strategy is 'classic'. */
746
+ adaptive: AdaptiveThresholdConfig;
747
+
748
+ /**
749
+ * Observational memory configuration. Used when strategy is 'observational'
750
+ * (or omitted, since observational is the default).
751
+ */
752
+ observational?: Partial<ObservationalMemoryConfig>;
753
+ }
754
+
755
+ /**
756
+ * Information about the compaction target passed to onBeforeCompaction.
757
+ */
758
+ export interface CompactionTarget {
759
+ /** Number of turns that will be summarized. */
760
+ turnsToCompact: number;
761
+ /** Estimated tokens in the compaction target. */
762
+ estimatedTokens: number;
763
+ }
764
+
765
+ /**
766
+ * Result of a compaction operation.
767
+ */
768
+ export interface CompactionResult {
769
+ /** Total tokens before compaction. */
770
+ tokensBefore: number;
771
+ /** Total tokens after compaction. */
772
+ tokensAfter: number;
773
+ /** Number of conversation turns that were compacted (summarized/removed). */
774
+ turnsCompacted: number;
775
+ /** Number of conversation turns preserved after compaction. */
776
+ turnsPreserved: number;
777
+ /** Token count of the generated summary. */
778
+ summaryTokens: number;
779
+ /**
780
+ * ISO timestamp of the oldest preserved turn, or null if no timestamp
781
+ * could be determined. The consumer (backend) should use
782
+ * `oldestPreservedIndex` to map back to a database timestamp when
783
+ * this is null.
784
+ */
785
+ oldestPreservedTimestamp: string | null;
786
+ /**
787
+ * Index of the oldest preserved turn in the original (pre-compaction)
788
+ * conversation history. The consumer can map this index back to a
789
+ * database timestamp via messages.db. Always present and accurate.
790
+ */
791
+ oldestPreservedIndex: number;
792
+ /** The generated summary text. */
793
+ summary: string;
794
+ }
795
+
796
+ /**
797
+ * Info passed to onCompactionDegraded when Layer 2 failed and Layer 3 was used.
798
+ */
799
+ export interface CompactionDegradedInfo {
800
+ /** Number of consecutive Layer 2 failures (including this episode). */
801
+ layer2Failures: number;
802
+ /** Number of turns dropped by emergency truncation. */
803
+ turnsDropped: number;
804
+ }
805
+
806
+ /**
807
+ * Info passed to onCompactionExhausted when all compaction layers have failed.
808
+ */
809
+ export interface CompactionExhaustedInfo {
810
+ /** The error from the last Layer 2 attempt. */
811
+ error: Error;
812
+ /** Number of consecutive Layer 2 failures. */
813
+ layer2Failures: number;
814
+ }
815
+
816
+ // ---------------------------------------------------------------------------
817
+ // Events
818
+ // ---------------------------------------------------------------------------
819
+
820
+ /**
821
+ * Event handlers emitted by CortexAgent during the agentic loop lifecycle.
822
+ */
823
+ export interface CortexEvents {
824
+ /** Fired when the full agentic loop finishes (agent_end, not turn_end). */
825
+ onLoopComplete: () => void;
826
+ /** Fired before compaction starts. Awaited. Consumer should flush state. */
827
+ onBeforeCompaction: (target: CompactionTarget) => Promise<void>;
828
+ /** Fired after compaction completes. Consumer can re-seed messages, update state. */
829
+ onPostCompaction: (result: CompactionResult) => void;
830
+ /** Fired when context compaction fails. */
831
+ onCompactionError: (error: Error) => void;
832
+ /** Fired when Layer 2 compaction failed and Layer 3 (emergency truncation) was used as fallback. */
833
+ onCompactionDegraded: (info: CompactionDegradedInfo) => void;
834
+ /** Fired when all compaction layers have failed. Consumer should take recovery action. */
835
+ onCompactionExhausted: (info: CompactionExhaustedInfo) => void;
836
+ /** Fired when an error is classified during the agentic loop. */
837
+ onError: (error: ClassifiedError) => void;
838
+ /** Fired at the end of each turn with parsed working tag output. */
839
+ onTurnComplete: (output: AgentTextOutput) => void;
840
+ /** Fired when a sub-agent is spawned for delegated work. */
841
+ onSubAgentSpawned: (taskId: string, instructions: string, background: boolean) => void;
842
+ /** Fired when a sub-agent completes successfully. */
843
+ onSubAgentCompleted: (taskId: string, result: string, status: string, usage: unknown) => void;
844
+ /** Fired when a sub-agent fails. */
845
+ onSubAgentFailed: (taskId: string, error: string) => void;
846
+ /** Fired when observational memory activates (messages compressed and removed). Only fires when strategy is 'observational'. */
847
+ onObservation: (event: ObservationEvent) => void;
848
+ /** Fired when the reflector condenses observations. Only fires when strategy is 'observational'. */
849
+ onReflection: (event: ReflectionEvent) => void;
850
+ }
851
+
852
+ // ---------------------------------------------------------------------------
853
+ // MCP Client
854
+ // ---------------------------------------------------------------------------
855
+
856
+ /**
857
+ * Transport configuration for connecting to an MCP server.
858
+ * Either stdio (spawn subprocess) or HTTP (connect to running server).
859
+ */
860
+ export type McpTransportConfig = McpStdioConfig | McpHttpConfig;
861
+
862
+ /**
863
+ * Stdio transport: spawn a subprocess and communicate via stdin/stdout.
864
+ */
865
+ export interface McpStdioConfig {
866
+ transport: 'stdio';
867
+ /** The executable to run (e.g., 'node', '/path/to/tsx'). */
868
+ command: string;
869
+ /** Command line arguments. */
870
+ args?: string[];
871
+ /** Environment variables for the subprocess. */
872
+ env?: Record<string, string>;
873
+ /** Working directory for the subprocess. */
874
+ cwd?: string;
875
+ }
876
+
877
+ /**
878
+ * HTTP transport: connect to an already-running MCP server via Streamable HTTP.
879
+ */
880
+ export interface McpHttpConfig {
881
+ transport: 'http';
882
+ /** The URL of the MCP server endpoint. */
883
+ url: string;
884
+ /** Optional HTTP headers (e.g., for authentication). */
885
+ headers?: Record<string, string>;
886
+ }
887
+
888
+ /**
889
+ * State of a single MCP server connection.
890
+ */
891
+ export interface McpConnectionState {
892
+ /** The server name used for namespacing tools. */
893
+ serverName: string;
894
+ /** Transport configuration used for this connection. */
895
+ config: McpTransportConfig;
896
+ /** Whether the connection is currently active. */
897
+ connected: boolean;
898
+ /** Number of reconnect attempts since last successful connection. */
899
+ reconnectAttempts: number;
900
+ /** Names of tools discovered from this server (namespaced). */
901
+ toolNames: string[];
902
+ }
903
+
904
+ // ---------------------------------------------------------------------------
905
+ // Model Tiers
906
+ // ---------------------------------------------------------------------------
907
+
908
+ /**
909
+ * Default utility model mapping per provider.
910
+ * Keys are provider names, values are model IDs.
911
+ */
912
+ export interface UtilityModelDefaults {
913
+ [provider: string]: string;
914
+ }
915
+
916
+ // ---------------------------------------------------------------------------
917
+ // Skill System
918
+ // ---------------------------------------------------------------------------
919
+
920
+ /**
921
+ * Configuration for registering a skill with the SkillRegistry.
922
+ * The consumer provides these at startup and dynamically as plugins install/uninstall.
923
+ */
924
+ export interface SkillConfig {
925
+ /** Absolute path to the SKILL.md file. */
926
+ path: string;
927
+ /** Where this skill came from. Used for display and debugging. */
928
+ source: string; // e.g., 'plugin:weather', 'plugin:discord', 'user', 'builtin'
929
+ /**
930
+ * Per-skill variables for ${VAR} substitution in the SKILL.md body.
931
+ * Merged into the preprocessor variables when getSkillBody() runs.
932
+ * Useful for plugin skills that reference ${PLUGIN_ROOT}.
933
+ */
934
+ variables?: Record<string, string>;
935
+ }
936
+
937
+ /**
938
+ * Internal skill index entry built from parsing a SKILL.md file.
939
+ */
940
+ export interface SkillEntry {
941
+ /** Skill name from frontmatter (kebab-case). */
942
+ name: string;
943
+ /** Skill description from frontmatter (for agent activation). */
944
+ description: string;
945
+ /** Absolute path to the SKILL.md file. */
946
+ path: string;
947
+ /** Absolute path to the skill directory (parent of SKILL.md). */
948
+ dir: string;
949
+ /** Source identifier from SkillConfig. */
950
+ source: string;
951
+ /** Full parsed YAML frontmatter (preserved for forward compatibility). */
952
+ frontmatter: Record<string, unknown>;
953
+ /** Whether the agent can auto-load this skill. Derived from disable-model-invocation. */
954
+ modelInvocable: boolean;
955
+ /** Per-skill variables for ${VAR} substitution. */
956
+ variables?: Record<string, string>;
957
+ }
958
+
959
+ /**
960
+ * A loaded skill in the skill buffer (preprocessed body ready for injection).
961
+ */
962
+ export interface LoadedSkill {
963
+ /** The skill name. */
964
+ name: string;
965
+ /** The preprocessed SKILL.md body content. */
966
+ content: string;
967
+ }
968
+
969
+ /**
970
+ * Context object passed to skill preprocessor scripts (!{script: path}).
971
+ * Cortex owns the built-in fields; the consumer provides everything else.
972
+ */
973
+ export interface CortexScriptContext {
974
+ /** Absolute path to the skill's directory. */
975
+ skillDir: string;
976
+ /** Arguments passed to the skill (split by whitespace). */
977
+ args: string[];
978
+ /** Raw arguments string. */
979
+ rawArgs: string;
980
+ /** Additional key-value pairs from !{script: path, key: value} syntax. */
981
+ scriptArgs: Record<string, string>;
982
+ /** Consumer-provided context fields (Cortex does not inspect these). */
983
+ [key: string]: unknown;
984
+ }
985
+
986
+ // ---------------------------------------------------------------------------
987
+ // Sub-Agent
988
+ // ---------------------------------------------------------------------------
989
+
990
+ /**
991
+ * Configuration for spawning a sub-agent via the SubAgent tool.
992
+ */
993
+ export interface SubAgentSpawnConfig {
994
+ /** What the sub-agent should do. Becomes the initial prompt. */
995
+ instructions: string;
996
+ /** Tool names to make available. Default: inherits parent's tools. */
997
+ tools?: string[];
998
+ /** Custom system prompt. Default: inherits parent's system prompt. */
999
+ systemPrompt?: string;
1000
+ /** Maximum LLM turns. Default: inherits parent's budget guard config. */
1001
+ maxTurns?: number;
1002
+ /** Maximum cost in USD. Default: inherits parent's budget guard config. */
1003
+ maxCost?: number;
1004
+ /** Run asynchronously. Default: false (blocks until complete). */
1005
+ background?: boolean;
1006
+ }
1007
+
1008
+ /**
1009
+ * Result returned by a completed sub-agent.
1010
+ */
1011
+ export interface SubAgentResult {
1012
+ /** The sub-agent's final text output. */
1013
+ output: string;
1014
+ /** Completion status. */
1015
+ status: 'completed' | 'failed' | 'timed_out' | 'cancelled';
1016
+ /** Usage summary. */
1017
+ usage: {
1018
+ turns: number;
1019
+ cost: number;
1020
+ durationMs: number;
1021
+ contextTokens: number;
1022
+ };
1023
+ /** Summary of tool calls made by the sub-agent (extracted from conversation history on completion). */
1024
+ toolCalls?: Array<{ name: string; durationMs: number; error?: string }>;
1025
+ }
1026
+
1027
+ /**
1028
+ * Tracked sub-agent record managed by SubAgentManager.
1029
+ */
1030
+ export interface TrackedSubAgent {
1031
+ /** Unique task identifier. */
1032
+ taskId: string;
1033
+ /** The sub-agent CortexAgent instance. */
1034
+ agent: unknown; // CortexAgent (avoid circular import)
1035
+ /** The instructions the sub-agent was spawned with. */
1036
+ instructions: string;
1037
+ /** Whether this is a background sub-agent. */
1038
+ background: boolean;
1039
+ /** Spawn timestamp. */
1040
+ spawnedAt: number;
1041
+ /** Promise that resolves when the sub-agent completes. */
1042
+ completion: Promise<SubAgentResult>;
1043
+ /** Resolve function for the completion promise. */
1044
+ resolve: (result: SubAgentResult) => void;
1045
+
1046
+ // Live activity tracking (updated via EventBridge forwarding)
1047
+ /** Number of tool calls executed so far. */
1048
+ toolCount: number;
1049
+ /** Name of the most recently started tool. */
1050
+ lastToolName: string | null;
1051
+ /** Summary/args of the most recently started tool. */
1052
+ lastToolSummary: string | null;
1053
+ /** Timestamp when the most recent tool started. */
1054
+ lastToolStartedAt: number | null;
1055
+ /** Set while the sub-agent is blocked awaiting a permission decision. */
1056
+ pendingPermission: { toolName: string; args: unknown } | null;
1057
+ }