clementine-agent 1.18.8 → 1.18.9

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 (368) hide show
  1. package/dist/agent/assistant.d.ts +4 -2
  2. package/dist/agent/assistant.js +59 -20
  3. package/dist/agent/self-improve.d.ts +34 -0
  4. package/dist/agent/self-improve.js +282 -42
  5. package/dist/gateway/router.js +1 -0
  6. package/dist/memory/store.d.ts +12 -0
  7. package/dist/memory/store.js +51 -0
  8. package/dist/tools/shared.d.ts +12 -0
  9. package/dist/types.d.ts +3 -1
  10. package/package.json +1 -1
  11. package/dist/agent/advisor-rules/context.d.ts.map +0 -1
  12. package/dist/agent/advisor-rules/context.js.map +0 -1
  13. package/dist/agent/advisor-rules/engine.d.ts.map +0 -1
  14. package/dist/agent/advisor-rules/engine.js.map +0 -1
  15. package/dist/agent/advisor-rules/loader.d.ts.map +0 -1
  16. package/dist/agent/advisor-rules/loader.js.map +0 -1
  17. package/dist/agent/advisor-rules/types.d.ts.map +0 -1
  18. package/dist/agent/advisor-rules/types.js.map +0 -1
  19. package/dist/agent/agent-manager.d.ts.map +0 -1
  20. package/dist/agent/agent-manager.js.map +0 -1
  21. package/dist/agent/assistant.d.ts.map +0 -1
  22. package/dist/agent/assistant.js.map +0 -1
  23. package/dist/agent/auto-skills.d.ts.map +0 -1
  24. package/dist/agent/auto-skills.js.map +0 -1
  25. package/dist/agent/auto-update.d.ts.map +0 -1
  26. package/dist/agent/auto-update.js.map +0 -1
  27. package/dist/agent/background-tasks.d.ts.map +0 -1
  28. package/dist/agent/background-tasks.js.map +0 -1
  29. package/dist/agent/brain-digest.d.ts.map +0 -1
  30. package/dist/agent/brain-digest.js.map +0 -1
  31. package/dist/agent/budget-enforcement.d.ts.map +0 -1
  32. package/dist/agent/budget-enforcement.js.map +0 -1
  33. package/dist/agent/complexity-classifier.d.ts.map +0 -1
  34. package/dist/agent/complexity-classifier.js.map +0 -1
  35. package/dist/agent/contradiction-validator.d.ts.map +0 -1
  36. package/dist/agent/contradiction-validator.js.map +0 -1
  37. package/dist/agent/crash-forensics.d.ts.map +0 -1
  38. package/dist/agent/crash-forensics.js.map +0 -1
  39. package/dist/agent/daily-planner.d.ts.map +0 -1
  40. package/dist/agent/daily-planner.js.map +0 -1
  41. package/dist/agent/decision-reflection.d.ts.map +0 -1
  42. package/dist/agent/decision-reflection.js.map +0 -1
  43. package/dist/agent/execution-advisor.d.ts.map +0 -1
  44. package/dist/agent/execution-advisor.js.map +0 -1
  45. package/dist/agent/hooks.d.ts.map +0 -1
  46. package/dist/agent/hooks.js.map +0 -1
  47. package/dist/agent/insight-engine.d.ts.map +0 -1
  48. package/dist/agent/insight-engine.js.map +0 -1
  49. package/dist/agent/intent-classifier.d.ts.map +0 -1
  50. package/dist/agent/intent-classifier.js.map +0 -1
  51. package/dist/agent/link-extractor.d.ts.map +0 -1
  52. package/dist/agent/link-extractor.js.map +0 -1
  53. package/dist/agent/mcp-bridge.d.ts.map +0 -1
  54. package/dist/agent/mcp-bridge.js.map +0 -1
  55. package/dist/agent/mcp-circuit-breaker.d.ts.map +0 -1
  56. package/dist/agent/mcp-circuit-breaker.js.map +0 -1
  57. package/dist/agent/mcp-schemas.d.ts.map +0 -1
  58. package/dist/agent/mcp-schemas.js.map +0 -1
  59. package/dist/agent/metacognition.d.ts.map +0 -1
  60. package/dist/agent/metacognition.js.map +0 -1
  61. package/dist/agent/orchestrator.d.ts.map +0 -1
  62. package/dist/agent/orchestrator.js.map +0 -1
  63. package/dist/agent/proactive-engine.d.ts.map +0 -1
  64. package/dist/agent/proactive-engine.js.map +0 -1
  65. package/dist/agent/proactive-ledger.d.ts.map +0 -1
  66. package/dist/agent/proactive-ledger.js.map +0 -1
  67. package/dist/agent/prompt-cache.d.ts.map +0 -1
  68. package/dist/agent/prompt-cache.js.map +0 -1
  69. package/dist/agent/prompt-evolver.d.ts.map +0 -1
  70. package/dist/agent/prompt-evolver.js.map +0 -1
  71. package/dist/agent/prompt-overrides/loader.d.ts.map +0 -1
  72. package/dist/agent/prompt-overrides/loader.js.map +0 -1
  73. package/dist/agent/prompt-overrides/types.d.ts.map +0 -1
  74. package/dist/agent/prompt-overrides/types.js.map +0 -1
  75. package/dist/agent/role-scaffolds.d.ts.map +0 -1
  76. package/dist/agent/role-scaffolds.js.map +0 -1
  77. package/dist/agent/route-classifier.d.ts.map +0 -1
  78. package/dist/agent/route-classifier.js.map +0 -1
  79. package/dist/agent/safe-restart.d.ts.map +0 -1
  80. package/dist/agent/safe-restart.js.map +0 -1
  81. package/dist/agent/self-improve-loop.d.ts.map +0 -1
  82. package/dist/agent/self-improve-loop.js.map +0 -1
  83. package/dist/agent/self-improve.d.ts.map +0 -1
  84. package/dist/agent/self-improve.js.map +0 -1
  85. package/dist/agent/session-event-log.d.ts.map +0 -1
  86. package/dist/agent/session-event-log.js.map +0 -1
  87. package/dist/agent/session-store-adapter.d.ts.map +0 -1
  88. package/dist/agent/session-store-adapter.js.map +0 -1
  89. package/dist/agent/skill-extractor.d.ts.map +0 -1
  90. package/dist/agent/skill-extractor.js.map +0 -1
  91. package/dist/agent/source-mods.d.ts.map +0 -1
  92. package/dist/agent/source-mods.js.map +0 -1
  93. package/dist/agent/source-preflight.d.ts.map +0 -1
  94. package/dist/agent/source-preflight.js.map +0 -1
  95. package/dist/agent/stall-guard.d.ts.map +0 -1
  96. package/dist/agent/stall-guard.js.map +0 -1
  97. package/dist/agent/strategic-planner.d.ts.map +0 -1
  98. package/dist/agent/strategic-planner.js.map +0 -1
  99. package/dist/agent/team-bus.d.ts.map +0 -1
  100. package/dist/agent/team-bus.js.map +0 -1
  101. package/dist/agent/team-router.d.ts.map +0 -1
  102. package/dist/agent/team-router.js.map +0 -1
  103. package/dist/agent/tool-loop-detector.d.ts.map +0 -1
  104. package/dist/agent/tool-loop-detector.js.map +0 -1
  105. package/dist/agent/tool-router.d.ts.map +0 -1
  106. package/dist/agent/tool-router.js.map +0 -1
  107. package/dist/agent/turn-policy.d.ts.map +0 -1
  108. package/dist/agent/turn-policy.js.map +0 -1
  109. package/dist/agent/webhook-actions.d.ts.map +0 -1
  110. package/dist/agent/webhook-actions.js.map +0 -1
  111. package/dist/agent/workflow-runner.d.ts.map +0 -1
  112. package/dist/agent/workflow-runner.js.map +0 -1
  113. package/dist/agent/workflow-variables.d.ts.map +0 -1
  114. package/dist/agent/workflow-variables.js.map +0 -1
  115. package/dist/analytics/tool-usage.d.ts.map +0 -1
  116. package/dist/analytics/tool-usage.js.map +0 -1
  117. package/dist/brain/adapters/common.d.ts.map +0 -1
  118. package/dist/brain/adapters/common.js.map +0 -1
  119. package/dist/brain/adapters/csv.d.ts.map +0 -1
  120. package/dist/brain/adapters/csv.js.map +0 -1
  121. package/dist/brain/adapters/docx.d.ts.map +0 -1
  122. package/dist/brain/adapters/docx.js.map +0 -1
  123. package/dist/brain/adapters/email.d.ts.map +0 -1
  124. package/dist/brain/adapters/email.js.map +0 -1
  125. package/dist/brain/adapters/index.d.ts.map +0 -1
  126. package/dist/brain/adapters/index.js.map +0 -1
  127. package/dist/brain/adapters/json.d.ts.map +0 -1
  128. package/dist/brain/adapters/json.js.map +0 -1
  129. package/dist/brain/adapters/markdown.d.ts.map +0 -1
  130. package/dist/brain/adapters/markdown.js.map +0 -1
  131. package/dist/brain/adapters/pdf.d.ts.map +0 -1
  132. package/dist/brain/adapters/pdf.js.map +0 -1
  133. package/dist/brain/adapters/rest.d.ts.map +0 -1
  134. package/dist/brain/adapters/rest.js.map +0 -1
  135. package/dist/brain/batch-summary.d.ts.map +0 -1
  136. package/dist/brain/batch-summary.js.map +0 -1
  137. package/dist/brain/connector-recipes.d.ts.map +0 -1
  138. package/dist/brain/connector-recipes.js.map +0 -1
  139. package/dist/brain/format-detector.d.ts.map +0 -1
  140. package/dist/brain/format-detector.js.map +0 -1
  141. package/dist/brain/graph-extractor.d.ts.map +0 -1
  142. package/dist/brain/graph-extractor.js.map +0 -1
  143. package/dist/brain/ingest-scheduler.d.ts.map +0 -1
  144. package/dist/brain/ingest-scheduler.js.map +0 -1
  145. package/dist/brain/ingestion-pipeline.d.ts.map +0 -1
  146. package/dist/brain/ingestion-pipeline.js.map +0 -1
  147. package/dist/brain/intelligence.d.ts.map +0 -1
  148. package/dist/brain/intelligence.js.map +0 -1
  149. package/dist/brain/llm-client.d.ts.map +0 -1
  150. package/dist/brain/llm-client.js.map +0 -1
  151. package/dist/brain/source-registry.d.ts.map +0 -1
  152. package/dist/brain/source-registry.js.map +0 -1
  153. package/dist/channels/discord-agent-bot.d.ts.map +0 -1
  154. package/dist/channels/discord-agent-bot.js.map +0 -1
  155. package/dist/channels/discord-bot-manager.d.ts.map +0 -1
  156. package/dist/channels/discord-bot-manager.js.map +0 -1
  157. package/dist/channels/discord-utils.d.ts.map +0 -1
  158. package/dist/channels/discord-utils.js.map +0 -1
  159. package/dist/channels/discord.d.ts.map +0 -1
  160. package/dist/channels/discord.js.map +0 -1
  161. package/dist/channels/slack-agent-bot.d.ts.map +0 -1
  162. package/dist/channels/slack-agent-bot.js.map +0 -1
  163. package/dist/channels/slack-bot-manager.d.ts.map +0 -1
  164. package/dist/channels/slack-bot-manager.js.map +0 -1
  165. package/dist/channels/slack-utils.d.ts.map +0 -1
  166. package/dist/channels/slack-utils.js.map +0 -1
  167. package/dist/channels/slack.d.ts.map +0 -1
  168. package/dist/channels/slack.js.map +0 -1
  169. package/dist/channels/telegram.d.ts.map +0 -1
  170. package/dist/channels/telegram.js.map +0 -1
  171. package/dist/channels/webhook.d.ts.map +0 -1
  172. package/dist/channels/webhook.js.map +0 -1
  173. package/dist/channels/whatsapp.d.ts.map +0 -1
  174. package/dist/channels/whatsapp.js.map +0 -1
  175. package/dist/cli/browser.d.ts.map +0 -1
  176. package/dist/cli/browser.js.map +0 -1
  177. package/dist/cli/chat.d.ts.map +0 -1
  178. package/dist/cli/chat.js.map +0 -1
  179. package/dist/cli/cron.d.ts.map +0 -1
  180. package/dist/cli/cron.js.map +0 -1
  181. package/dist/cli/dashboard.d.ts.map +0 -1
  182. package/dist/cli/dashboard.js.map +0 -1
  183. package/dist/cli/index.d.ts.map +0 -1
  184. package/dist/cli/index.js.map +0 -1
  185. package/dist/cli/ingest.d.ts.map +0 -1
  186. package/dist/cli/ingest.js.map +0 -1
  187. package/dist/cli/routes/delegations.d.ts.map +0 -1
  188. package/dist/cli/routes/delegations.js.map +0 -1
  189. package/dist/cli/routes/digest.d.ts.map +0 -1
  190. package/dist/cli/routes/digest.js.map +0 -1
  191. package/dist/cli/routes/goals.d.ts.map +0 -1
  192. package/dist/cli/routes/goals.js.map +0 -1
  193. package/dist/cli/routes/workflows.d.ts.map +0 -1
  194. package/dist/cli/routes/workflows.js.map +0 -1
  195. package/dist/cli/setup.d.ts.map +0 -1
  196. package/dist/cli/setup.js.map +0 -1
  197. package/dist/cli/tunnel.d.ts.map +0 -1
  198. package/dist/cli/tunnel.js.map +0 -1
  199. package/dist/cli/version-check.d.ts.map +0 -1
  200. package/dist/cli/version-check.js.map +0 -1
  201. package/dist/config/clementine-json.d.ts.map +0 -1
  202. package/dist/config/clementine-json.js.map +0 -1
  203. package/dist/config/config-doctor.d.ts.map +0 -1
  204. package/dist/config/config-doctor.js.map +0 -1
  205. package/dist/config/effective-config.d.ts.map +0 -1
  206. package/dist/config/effective-config.js.map +0 -1
  207. package/dist/config/env-parser.d.ts.map +0 -1
  208. package/dist/config/env-parser.js.map +0 -1
  209. package/dist/config/harden-permissions.d.ts.map +0 -1
  210. package/dist/config/harden-permissions.js.map +0 -1
  211. package/dist/config/integrations-registry.d.ts.map +0 -1
  212. package/dist/config/integrations-registry.js.map +0 -1
  213. package/dist/config/keychain-first-run-wizard.d.ts.map +0 -1
  214. package/dist/config/keychain-first-run-wizard.js.map +0 -1
  215. package/dist/config/keychain-fix-acl.d.ts.map +0 -1
  216. package/dist/config/keychain-fix-acl.js.map +0 -1
  217. package/dist/config/migrate-from-keychain.d.ts.map +0 -1
  218. package/dist/config/migrate-from-keychain.js.map +0 -1
  219. package/dist/config/migrate-keychain.d.ts.map +0 -1
  220. package/dist/config/migrate-keychain.js.map +0 -1
  221. package/dist/config.d.ts.map +0 -1
  222. package/dist/config.js.map +0 -1
  223. package/dist/dashboard/builder/dry-run.d.ts.map +0 -1
  224. package/dist/dashboard/builder/dry-run.js.map +0 -1
  225. package/dist/dashboard/builder/events.d.ts.map +0 -1
  226. package/dist/dashboard/builder/events.js.map +0 -1
  227. package/dist/dashboard/builder/mcp-invoke.d.ts.map +0 -1
  228. package/dist/dashboard/builder/mcp-invoke.js.map +0 -1
  229. package/dist/dashboard/builder/runner.d.ts.map +0 -1
  230. package/dist/dashboard/builder/runner.js.map +0 -1
  231. package/dist/dashboard/builder/serializer.d.ts.map +0 -1
  232. package/dist/dashboard/builder/serializer.js.map +0 -1
  233. package/dist/dashboard/builder/snapshots.d.ts.map +0 -1
  234. package/dist/dashboard/builder/snapshots.js.map +0 -1
  235. package/dist/dashboard/builder/validation.d.ts.map +0 -1
  236. package/dist/dashboard/builder/validation.js.map +0 -1
  237. package/dist/events/bus.d.ts.map +0 -1
  238. package/dist/events/bus.js.map +0 -1
  239. package/dist/gateway/agent-heartbeat-manager.d.ts.map +0 -1
  240. package/dist/gateway/agent-heartbeat-manager.js.map +0 -1
  241. package/dist/gateway/agent-heartbeat-scheduler.d.ts.map +0 -1
  242. package/dist/gateway/agent-heartbeat-scheduler.js.map +0 -1
  243. package/dist/gateway/claim-tracker.d.ts.map +0 -1
  244. package/dist/gateway/claim-tracker.js.map +0 -1
  245. package/dist/gateway/cron-scheduler.d.ts.map +0 -1
  246. package/dist/gateway/cron-scheduler.js.map +0 -1
  247. package/dist/gateway/delivery-queue.d.ts.map +0 -1
  248. package/dist/gateway/delivery-queue.js.map +0 -1
  249. package/dist/gateway/failure-diagnostics.d.ts.map +0 -1
  250. package/dist/gateway/failure-diagnostics.js.map +0 -1
  251. package/dist/gateway/failure-monitor.d.ts.map +0 -1
  252. package/dist/gateway/failure-monitor.js.map +0 -1
  253. package/dist/gateway/fix-applier.d.ts.map +0 -1
  254. package/dist/gateway/fix-applier.js.map +0 -1
  255. package/dist/gateway/fix-verification.d.ts.map +0 -1
  256. package/dist/gateway/fix-verification.js.map +0 -1
  257. package/dist/gateway/heartbeat-scheduler.d.ts.map +0 -1
  258. package/dist/gateway/heartbeat-scheduler.js.map +0 -1
  259. package/dist/gateway/heartbeat.d.ts.map +0 -1
  260. package/dist/gateway/heartbeat.js.map +0 -1
  261. package/dist/gateway/lanes.d.ts.map +0 -1
  262. package/dist/gateway/lanes.js.map +0 -1
  263. package/dist/gateway/notifications.d.ts.map +0 -1
  264. package/dist/gateway/notifications.js.map +0 -1
  265. package/dist/gateway/outcome-grader.d.ts.map +0 -1
  266. package/dist/gateway/outcome-grader.js.map +0 -1
  267. package/dist/gateway/router.d.ts.map +0 -1
  268. package/dist/gateway/router.js.map +0 -1
  269. package/dist/index.d.ts.map +0 -1
  270. package/dist/index.js.map +0 -1
  271. package/dist/integrations/composio/client.d.ts.map +0 -1
  272. package/dist/integrations/composio/client.js.map +0 -1
  273. package/dist/integrations/composio/mcp-bridge.d.ts.map +0 -1
  274. package/dist/integrations/composio/mcp-bridge.js.map +0 -1
  275. package/dist/integrations/tool-preferences.d.ts.map +0 -1
  276. package/dist/integrations/tool-preferences.js.map +0 -1
  277. package/dist/memory/chunker.d.ts.map +0 -1
  278. package/dist/memory/chunker.js.map +0 -1
  279. package/dist/memory/consolidation.d.ts.map +0 -1
  280. package/dist/memory/consolidation.js.map +0 -1
  281. package/dist/memory/context-assembler.d.ts.map +0 -1
  282. package/dist/memory/context-assembler.js.map +0 -1
  283. package/dist/memory/embeddings.d.ts.map +0 -1
  284. package/dist/memory/embeddings.js.map +0 -1
  285. package/dist/memory/graph-store.d.ts.map +0 -1
  286. package/dist/memory/graph-store.js.map +0 -1
  287. package/dist/memory/hot-cache.d.ts.map +0 -1
  288. package/dist/memory/hot-cache.js.map +0 -1
  289. package/dist/memory/integrity.d.ts.map +0 -1
  290. package/dist/memory/integrity.js.map +0 -1
  291. package/dist/memory/maintenance.d.ts.map +0 -1
  292. package/dist/memory/maintenance.js.map +0 -1
  293. package/dist/memory/mmr.d.ts.map +0 -1
  294. package/dist/memory/mmr.js.map +0 -1
  295. package/dist/memory/search.d.ts.map +0 -1
  296. package/dist/memory/search.js.map +0 -1
  297. package/dist/memory/seed-user-model.d.ts.map +0 -1
  298. package/dist/memory/seed-user-model.js.map +0 -1
  299. package/dist/memory/store.d.ts.map +0 -1
  300. package/dist/memory/store.js.map +0 -1
  301. package/dist/memory/write-queue.d.ts.map +0 -1
  302. package/dist/memory/write-queue.js.map +0 -1
  303. package/dist/secrets/auth-profiles.d.ts.map +0 -1
  304. package/dist/secrets/auth-profiles.js.map +0 -1
  305. package/dist/secrets/keychain.d.ts.map +0 -1
  306. package/dist/secrets/keychain.js.map +0 -1
  307. package/dist/secrets/resolver.d.ts.map +0 -1
  308. package/dist/secrets/resolver.js.map +0 -1
  309. package/dist/secrets/sensitivity.d.ts.map +0 -1
  310. package/dist/secrets/sensitivity.js.map +0 -1
  311. package/dist/security/integrity.d.ts.map +0 -1
  312. package/dist/security/integrity.js.map +0 -1
  313. package/dist/security/patterns.d.ts.map +0 -1
  314. package/dist/security/patterns.js.map +0 -1
  315. package/dist/security/redact.d.ts.map +0 -1
  316. package/dist/security/redact.js.map +0 -1
  317. package/dist/security/scanner.d.ts.map +0 -1
  318. package/dist/security/scanner.js.map +0 -1
  319. package/dist/tools/admin-tools.d.ts.map +0 -1
  320. package/dist/tools/admin-tools.js.map +0 -1
  321. package/dist/tools/agent-heartbeat-tools.d.ts.map +0 -1
  322. package/dist/tools/agent-heartbeat-tools.js.map +0 -1
  323. package/dist/tools/artifact-tools.d.ts.map +0 -1
  324. package/dist/tools/artifact-tools.js.map +0 -1
  325. package/dist/tools/background-task-tools.d.ts.map +0 -1
  326. package/dist/tools/background-task-tools.js.map +0 -1
  327. package/dist/tools/brain-tools.d.ts.map +0 -1
  328. package/dist/tools/brain-tools.js.map +0 -1
  329. package/dist/tools/builder-tools.d.ts.map +0 -1
  330. package/dist/tools/builder-tools.js.map +0 -1
  331. package/dist/tools/decision-reflection-tools.d.ts.map +0 -1
  332. package/dist/tools/decision-reflection-tools.js.map +0 -1
  333. package/dist/tools/external-tools.d.ts.map +0 -1
  334. package/dist/tools/external-tools.js.map +0 -1
  335. package/dist/tools/goal-tools.d.ts.map +0 -1
  336. package/dist/tools/goal-tools.js.map +0 -1
  337. package/dist/tools/mcp-server.d.ts.map +0 -1
  338. package/dist/tools/mcp-server.js.map +0 -1
  339. package/dist/tools/memory-tools.d.ts.map +0 -1
  340. package/dist/tools/memory-tools.js.map +0 -1
  341. package/dist/tools/session-tools.d.ts.map +0 -1
  342. package/dist/tools/session-tools.js.map +0 -1
  343. package/dist/tools/shared.d.ts.map +0 -1
  344. package/dist/tools/shared.js.map +0 -1
  345. package/dist/tools/team-tools.d.ts.map +0 -1
  346. package/dist/tools/team-tools.js.map +0 -1
  347. package/dist/tools/tool-meta.d.ts.map +0 -1
  348. package/dist/tools/tool-meta.js.map +0 -1
  349. package/dist/tools/vault-tools.d.ts.map +0 -1
  350. package/dist/tools/vault-tools.js.map +0 -1
  351. package/dist/types.d.ts.map +0 -1
  352. package/dist/types.js.map +0 -1
  353. package/dist/vault-migrations/0001-add-execution-framework.d.ts.map +0 -1
  354. package/dist/vault-migrations/0001-add-execution-framework.js.map +0 -1
  355. package/dist/vault-migrations/0002-add-agentic-communication.d.ts.map +0 -1
  356. package/dist/vault-migrations/0002-add-agentic-communication.js.map +0 -1
  357. package/dist/vault-migrations/0003-update-execution-pipeline-narration.d.ts.map +0 -1
  358. package/dist/vault-migrations/0003-update-execution-pipeline-narration.js.map +0 -1
  359. package/dist/vault-migrations/0004-backfill-schema-versions.d.ts.map +0 -1
  360. package/dist/vault-migrations/0004-backfill-schema-versions.js.map +0 -1
  361. package/dist/vault-migrations/0005-create-clementine-json.d.ts.map +0 -1
  362. package/dist/vault-migrations/0005-create-clementine-json.js.map +0 -1
  363. package/dist/vault-migrations/helpers.d.ts.map +0 -1
  364. package/dist/vault-migrations/helpers.js.map +0 -1
  365. package/dist/vault-migrations/runner.d.ts.map +0 -1
  366. package/dist/vault-migrations/runner.js.map +0 -1
  367. package/dist/vault-migrations/types.d.ts.map +0 -1
  368. package/dist/vault-migrations/types.js.map +0 -1
@@ -251,8 +251,10 @@ export declare class PersonalAssistant {
251
251
  /** Fire-and-forget: extract a reusable skill from a successful execution. */
252
252
  private extractSkillFromExecution;
253
253
  private preRotationFlush;
254
- private lastExtractionTime;
255
- private worthExtracting;
254
+ private lastExtractionTimes;
255
+ private memoryExtractionKey;
256
+ private assessMemoryExtraction;
257
+ private logMemoryExtractionSkip;
256
258
  private spawnMemoryExtraction;
257
259
  private static readonly MEMORY_TOOL_NAMES;
258
260
  private extractMemory;
@@ -2872,12 +2872,16 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2872
2872
  logger.warn({ err, sessionKey: key }, 'Transcript save failed');
2873
2873
  }
2874
2874
  }
2875
- // Fire background memory extraction (non-blocking)
2876
- if (text.length >= AUTO_MEMORY_MIN_LENGTH &&
2877
- responseText &&
2878
- !responseText.startsWith('Error:') &&
2879
- this.worthExtracting(text, responseText)) {
2880
- this.spawnMemoryExtraction(text, responseText, key, profile).catch(err => logger.debug({ err }, 'Memory extraction failed'));
2875
+ // Fire background memory extraction (non-blocking). Skips are logged with
2876
+ // structured reasons so memory gaps are diagnosable without reading chats.
2877
+ if (responseText && !responseText.startsWith('Error:')) {
2878
+ const extractionDecision = this.assessMemoryExtraction(text, responseText, key, profile);
2879
+ if (extractionDecision.ok) {
2880
+ this.spawnMemoryExtraction(text, responseText, key, profile).catch(err => logger.debug({ err }, 'Memory extraction failed'));
2881
+ }
2882
+ else {
2883
+ this.logMemoryExtractionSkip(extractionDecision.reason, text, responseText, key, profile);
2884
+ }
2881
2885
  }
2882
2886
  // Score outcome-driven salience: for the chunks we retrieved this turn,
2883
2887
  // check which actually showed up in the response and adjust their
@@ -4188,14 +4192,15 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
4188
4192
  catch { /* non-fatal */ }
4189
4193
  }
4190
4194
  // ── Auto-Memory Extraction ────────────────────────────────────────
4191
- lastExtractionTime = 0;
4192
- worthExtracting(prompt, response) {
4193
- if (response.length < 100)
4194
- return false;
4195
- // Skip very short acknowledgment responses
4196
- if (response.length < 100)
4197
- return false;
4198
- // Only skip pure greetings with no substance at all
4195
+ lastExtractionTimes = new Map();
4196
+ memoryExtractionKey(sessionKey, profile) {
4197
+ return `${profile?.slug ?? 'global'}:${sessionKey ?? 'no-session'}`;
4198
+ }
4199
+ assessMemoryExtraction(prompt, response, sessionKey, profile) {
4200
+ if (!this.memoryStore)
4201
+ return { ok: false, reason: 'no_memory_store' };
4202
+ // Only skip pure greetings with no substance at all. Check this before
4203
+ // length so "hey" is diagnosable as intent, not generic shortness.
4199
4204
  const pureGreetings = [
4200
4205
  'hello', 'hi', 'hey', 'thanks', 'thank you',
4201
4206
  'ok', 'okay', 'sure', 'got it', 'sounds good',
@@ -4203,20 +4208,54 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
4203
4208
  ];
4204
4209
  const lower = prompt.toLowerCase().trim();
4205
4210
  if (pureGreetings.some((g) => lower === g || lower === g + '!' || lower === g + '.')) {
4206
- return false;
4211
+ return { ok: false, reason: 'pure_greeting' };
4212
+ }
4213
+ if (prompt.length < AUTO_MEMORY_MIN_LENGTH || response.length < 100) {
4214
+ return { ok: false, reason: 'too_short' };
4207
4215
  }
4208
- // Rate limit: max 1 extraction per 45 seconds per session
4216
+ // Rate limit per session/agent. The old process-wide throttle meant one
4217
+ // active chat could suppress memory extraction for unrelated agents.
4209
4218
  const now = Date.now();
4210
- if (now - this.lastExtractionTime < 45_000)
4211
- return false;
4212
- this.lastExtractionTime = now;
4213
- return true;
4219
+ const key = this.memoryExtractionKey(sessionKey, profile);
4220
+ const last = this.lastExtractionTimes.get(key) ?? 0;
4221
+ if (now - last < 45_000)
4222
+ return { ok: false, reason: 'rate_limited' };
4223
+ this.lastExtractionTimes.set(key, now);
4224
+ return { ok: true };
4225
+ }
4226
+ logMemoryExtractionSkip(reason, userMessage, assistantResponse, sessionKey, profile) {
4227
+ logger.debug({
4228
+ reason,
4229
+ sessionKey,
4230
+ agentSlug: profile?.slug,
4231
+ promptChars: userMessage.length,
4232
+ responseChars: assistantResponse.length,
4233
+ }, 'Auto-memory extraction skipped');
4234
+ if (!this.memoryStore)
4235
+ return;
4236
+ try {
4237
+ this.memoryStore.logExtraction({
4238
+ sessionKey: sessionKey ?? 'unknown',
4239
+ userMessage: userMessage.slice(0, 500),
4240
+ toolName: 'auto_memory_skip',
4241
+ toolInput: JSON.stringify({
4242
+ reason,
4243
+ promptChars: userMessage.length,
4244
+ responseChars: assistantResponse.length,
4245
+ }),
4246
+ extractedAt: new Date().toISOString(),
4247
+ status: `skipped:${reason}`,
4248
+ agentSlug: profile?.slug,
4249
+ });
4250
+ }
4251
+ catch { /* telemetry only */ }
4214
4252
  }
4215
4253
  async spawnMemoryExtraction(userMessage, assistantResponse, sessionKey, profile) {
4216
4254
  // Guard: skip memory extraction if the user message looks like injection
4217
4255
  const memScan = scanner.scan(userMessage);
4218
4256
  if (memScan.verdict === 'block') {
4219
4257
  logger.info('Skipping memory extraction — message was flagged as injection');
4258
+ this.logMemoryExtractionSkip('injection_blocked', userMessage, assistantResponse, sessionKey, profile);
4220
4259
  return;
4221
4260
  }
4222
4261
  let currentMemory = '';
@@ -10,6 +10,37 @@
10
10
  */
11
11
  import type { SelfImproveConfig, SelfImproveExperiment, SelfImproveState } from '../types.js';
12
12
  import type { PersonalAssistant } from './assistant.js';
13
+ export declare const USER_MODEL_SLOT_KEYS: readonly ["user_facts", "goals", "relationships", "agent_persona"];
14
+ export type UserModelSlotKey = typeof USER_MODEL_SLOT_KEYS[number];
15
+ export interface SelfImproveEvidenceSnapshot {
16
+ feedbackCreatedAt?: string[];
17
+ reflectionCreatedAt?: string[];
18
+ cronErrorStartedAt?: string[];
19
+ cronReflectionAt?: string[];
20
+ triggerUpdatedAt?: string[];
21
+ triggerCount?: number;
22
+ userModelNeedsSeed?: boolean;
23
+ }
24
+ export declare function isPlateauExperiment(entry: Partial<SelfImproveExperiment>): boolean;
25
+ export declare function latestPlateauTime(history: Array<Partial<SelfImproveExperiment>>): number;
26
+ export declare function newestSelfImproveEvidenceTime(evidence: SelfImproveEvidenceSnapshot): number;
27
+ export declare function shouldSkipSelfImproveForPlateau(history: Array<Partial<SelfImproveExperiment>>, evidence: SelfImproveEvidenceSnapshot): {
28
+ skip: boolean;
29
+ reason?: string;
30
+ };
31
+ export declare function shouldAppendPlateauMarker(history: Array<Partial<SelfImproveExperiment>>, nowMs?: number, windowMs?: number): boolean;
32
+ export declare function reconcileSelfImproveStateSnapshot(state: SelfImproveState, actualPending: number, opts?: {
33
+ nowMs?: number;
34
+ maxDurationMs?: number;
35
+ graceMs?: number;
36
+ }): {
37
+ state: SelfImproveState;
38
+ changed: boolean;
39
+ diagnostics: string[];
40
+ };
41
+ export declare function normalizeUserModelSlots(slots: unknown): Partial<Record<UserModelSlotKey, string>>;
42
+ export declare function sanitizeUserModelFrontmatter(frontmatterYaml: string): string;
43
+ export declare function buildUserModelMarkdown(frontmatterYaml: string, slots: Partial<Record<UserModelSlotKey, string>>, updatedAt?: string): string;
13
44
  export declare class SelfImproveLoop {
14
45
  private config;
15
46
  private assistant;
@@ -18,6 +49,9 @@ export declare class SelfImproveLoop {
18
49
  /** Run a focused self-improvement cycle for a specific agent. */
19
50
  runForAgent(agentSlug: string, onProposal?: (experiment: SelfImproveExperiment) => Promise<void>): Promise<SelfImproveState>;
20
51
  private gatherMetrics;
52
+ private evidenceSnapshot;
53
+ private pendingTriggerEvidence;
54
+ private userModelNeedsSeed;
21
55
  private hypothesize;
22
56
  private readCurrentState;
23
57
  private evaluate;
@@ -9,13 +9,14 @@
9
9
  * All proposed changes require Discord approval before being applied.
10
10
  */
11
11
  import { randomBytes } from 'node:crypto';
12
- import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync, } from 'node:fs';
12
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync, } from 'node:fs';
13
13
  import matter from 'gray-matter';
14
14
  import { load as yamlLoad } from 'js-yaml';
15
15
  import path from 'node:path';
16
16
  import pino from 'pino';
17
17
  import { BASE_DIR, SELF_IMPROVE_DIR, SOUL_FILE, AGENTS_FILE, CRON_FILE, WORKFLOWS_DIR, VAULT_DIR, MEMORY_DB_PATH, AGENTS_DIR, CRON_REFLECTIONS_DIR, GOALS_DIR, } from '../config.js';
18
18
  import { listAllGoals } from '../tools/shared.js';
19
+ import { MemoryStore } from '../memory/store.js';
19
20
  const logger = pino({ name: 'clementine.self-improve' });
20
21
  // ── Defaults ─────────────────────────────────────────────────────────
21
22
  const DEFAULT_CONFIG = {
@@ -157,6 +158,129 @@ function classifyRisk(area) {
157
158
  default: return 'high';
158
159
  }
159
160
  }
161
+ export const USER_MODEL_SLOT_KEYS = ['user_facts', 'goals', 'relationships', 'agent_persona'];
162
+ export function isPlateauExperiment(entry) {
163
+ return entry.reason?.startsWith('Plateau') === true
164
+ || entry.hypothesis?.startsWith('No new hypothesis') === true;
165
+ }
166
+ function entryTimeMs(entry) {
167
+ const ts = Date.parse(entry.finishedAt ?? entry.startedAt ?? '');
168
+ return Number.isFinite(ts) ? ts : 0;
169
+ }
170
+ export function latestPlateauTime(history) {
171
+ let latest = 0;
172
+ for (const entry of history) {
173
+ if (!isPlateauExperiment(entry))
174
+ continue;
175
+ latest = Math.max(latest, entryTimeMs(entry));
176
+ }
177
+ return latest;
178
+ }
179
+ function latestIsoTime(values = []) {
180
+ let latest = 0;
181
+ for (const value of values) {
182
+ const ts = Date.parse(value ?? '');
183
+ if (Number.isFinite(ts))
184
+ latest = Math.max(latest, ts);
185
+ }
186
+ return latest;
187
+ }
188
+ export function newestSelfImproveEvidenceTime(evidence) {
189
+ if (evidence.userModelNeedsSeed)
190
+ return Date.now();
191
+ return Math.max(latestIsoTime(evidence.feedbackCreatedAt), latestIsoTime(evidence.reflectionCreatedAt), latestIsoTime(evidence.cronErrorStartedAt), latestIsoTime(evidence.cronReflectionAt), latestIsoTime(evidence.triggerUpdatedAt));
192
+ }
193
+ export function shouldSkipSelfImproveForPlateau(history, evidence) {
194
+ const plateauAt = latestPlateauTime(history);
195
+ if (plateauAt === 0)
196
+ return { skip: false };
197
+ const newestEvidenceAt = newestSelfImproveEvidenceTime(evidence);
198
+ if (newestEvidenceAt > plateauAt)
199
+ return { skip: false };
200
+ return {
201
+ skip: true,
202
+ reason: `No new self-improvement evidence since latest plateau at ${new Date(plateauAt).toISOString()}`,
203
+ };
204
+ }
205
+ export function shouldAppendPlateauMarker(history, nowMs = Date.now(), windowMs = 24 * 60 * 60 * 1000) {
206
+ const plateauAt = latestPlateauTime(history);
207
+ return plateauAt === 0 || nowMs - plateauAt > windowMs;
208
+ }
209
+ export function reconcileSelfImproveStateSnapshot(state, actualPending, opts = {}) {
210
+ const next = { ...state };
211
+ const diagnostics = [];
212
+ let changed = false;
213
+ if (next.pendingApprovals !== actualPending) {
214
+ next.pendingApprovals = actualPending;
215
+ diagnostics.push(`Pending approvals reconciled to ${actualPending}`);
216
+ changed = true;
217
+ }
218
+ if (next.status === 'running' && next.lastRunAt) {
219
+ const started = Date.parse(next.lastRunAt);
220
+ const now = opts.nowMs ?? Date.now();
221
+ const staleAfter = (opts.maxDurationMs ?? DEFAULT_CONFIG.maxDurationMs) + (opts.graceMs ?? 5 * 60 * 1000);
222
+ if (Number.isFinite(started) && now - started > staleAfter) {
223
+ next.status = 'failed';
224
+ next.currentIteration = 0;
225
+ next.lastDiagnostic = `Stale self-improve run cleared after ${Math.round((now - started) / 60_000)} minutes`;
226
+ diagnostics.push(next.lastDiagnostic);
227
+ changed = true;
228
+ }
229
+ }
230
+ return { state: next, changed, diagnostics };
231
+ }
232
+ export function normalizeUserModelSlots(slots) {
233
+ if (!slots || typeof slots !== 'object')
234
+ return {};
235
+ const input = slots;
236
+ const out = {};
237
+ for (const key of USER_MODEL_SLOT_KEYS) {
238
+ const value = input[key];
239
+ if (typeof value === 'string' && value.trim()) {
240
+ out[key] = value.trim();
241
+ }
242
+ else if (Array.isArray(value)) {
243
+ const lines = value
244
+ .map(v => typeof v === 'string' ? v.trim() : '')
245
+ .filter(Boolean);
246
+ if (lines.length > 0)
247
+ out[key] = lines.map(v => `- ${v.replace(/^[-*]\s*/, '')}`).join('\n');
248
+ }
249
+ }
250
+ return out;
251
+ }
252
+ export function sanitizeUserModelFrontmatter(frontmatterYaml) {
253
+ const lines = frontmatterYaml
254
+ .trim()
255
+ .split(/\r?\n/)
256
+ .map(line => line.replace(/\s+$/, ''));
257
+ if (/^```(?:ya?ml)?\s*$/i.test(lines[0]?.trim() ?? '')) {
258
+ lines.shift();
259
+ }
260
+ if (/^```\s*$/.test(lines[lines.length - 1]?.trim() ?? '')) {
261
+ lines.pop();
262
+ }
263
+ while (lines[0]?.trim() === '---') {
264
+ lines.shift();
265
+ }
266
+ while (lines[lines.length - 1]?.trim() === '---') {
267
+ lines.pop();
268
+ }
269
+ const sanitized = lines
270
+ .filter(line => !/^\s*last_updated\s*:/i.test(line))
271
+ .join('\n')
272
+ .trim();
273
+ return sanitized || 'confidence_scores: {}';
274
+ }
275
+ export function buildUserModelMarkdown(frontmatterYaml, slots, updatedAt = new Date().toISOString()) {
276
+ const body = USER_MODEL_SLOT_KEYS
277
+ .filter(key => slots[key])
278
+ .map(key => `## ${key}\n\n${slots[key]}`)
279
+ .join('\n\n');
280
+ return `---\n${sanitizeUserModelFrontmatter(frontmatterYaml)}\nlast_updated: "${updatedAt}"\n---\n\n# User Model\n\n` +
281
+ `This file is auto-generated by the self-improvement loop. The DB-backed user_model_blocks table is the prompt source of truth.\n\n` +
282
+ `${body}\n`;
283
+ }
160
284
  // ── SelfImproveLoop ──────────────────────────────────────────────────
161
285
  export class SelfImproveLoop {
162
286
  config;
@@ -204,6 +328,7 @@ export class SelfImproveLoop {
204
328
  state.status = 'running';
205
329
  state.lastRunAt = new Date().toISOString();
206
330
  state.currentIteration = 0;
331
+ delete state.lastDiagnostic;
207
332
  this.saveState(state);
208
333
  const loopStart = Date.now();
209
334
  const history = this.loadExperimentLog();
@@ -223,6 +348,15 @@ export class SelfImproveLoop {
223
348
  cronSuccessRate: metrics.cronSuccessRate,
224
349
  avgResponseQuality: 0, // Updated as we evaluate
225
350
  };
351
+ const plateauSkip = shouldSkipSelfImproveForPlateau(history, this.evidenceSnapshot(metrics));
352
+ if (plateauSkip.skip) {
353
+ logger.info({ reason: plateauSkip.reason }, 'Self-improve skipped after plateau — no new evidence');
354
+ state.status = 'completed';
355
+ state.currentIteration = 0;
356
+ state.lastDiagnostic = plateauSkip.reason;
357
+ this.saveState(state);
358
+ return state;
359
+ }
226
360
  // Synthesize feedback patterns and update user model before experiment loop
227
361
  await this.synthesizeFeedbackPatterns();
228
362
  await this.updateUserModel();
@@ -238,23 +372,31 @@ export class SelfImproveLoop {
238
372
  // Record the plateau in the experiment log so it's not silently
239
373
  // invisible. Helps the dashboard and failure monitor distinguish
240
374
  // "exhausted diverse hypotheses" from "crashed mid-run".
241
- const plateauExperiment = {
242
- id: randomBytes(4).toString('hex'),
243
- iteration: i,
244
- startedAt: new Date(loopStart).toISOString(),
245
- finishedAt: new Date().toISOString(),
246
- durationMs: Date.now() - loopStart,
247
- area: 'soul',
248
- target: 'n/a',
249
- hypothesis: 'No new hypothesis — diversity constraint exhausted',
250
- proposedChange: '',
251
- baselineScore: 0,
252
- score: 0,
253
- accepted: false,
254
- approvalStatus: 'denied',
255
- reason: 'Plateau: no novel improvement area remaining',
256
- };
257
- this.appendExperimentLog(plateauExperiment);
375
+ if (shouldAppendPlateauMarker(history)) {
376
+ const plateauExperiment = {
377
+ id: randomBytes(4).toString('hex'),
378
+ iteration: i,
379
+ startedAt: new Date(loopStart).toISOString(),
380
+ finishedAt: new Date().toISOString(),
381
+ durationMs: Date.now() - loopStart,
382
+ area: 'soul',
383
+ target: 'n/a',
384
+ hypothesis: 'No new hypothesis — diversity constraint exhausted',
385
+ proposedChange: '',
386
+ baselineScore: 0,
387
+ score: 0,
388
+ accepted: false,
389
+ approvalStatus: 'denied',
390
+ reason: 'Plateau: no novel improvement area remaining',
391
+ };
392
+ this.appendExperimentLog(plateauExperiment);
393
+ history.push(plateauExperiment);
394
+ state.totalExperiments++;
395
+ }
396
+ else {
397
+ logger.info('Recent plateau marker already exists — not appending duplicate');
398
+ }
399
+ state.lastDiagnostic = 'Plateau: no novel improvement area remaining';
258
400
  break;
259
401
  }
260
402
  state.currentIteration = i;
@@ -644,6 +786,58 @@ export class SelfImproveLoop {
644
786
  advisorInsights,
645
787
  };
646
788
  }
789
+ evidenceSnapshot(metrics) {
790
+ const triggerEvidence = this.pendingTriggerEvidence();
791
+ return {
792
+ feedbackCreatedAt: metrics.negativeFeedback.map(f => f.createdAt).filter((v) => !!v),
793
+ reflectionCreatedAt: metrics.cronReflections.map(r => r.timestamp).filter(Boolean),
794
+ cronErrorStartedAt: metrics.cronErrors.map(e => e.startedAt).filter((v) => !!v),
795
+ cronReflectionAt: metrics.cronReflections.map(r => r.timestamp).filter(Boolean),
796
+ triggerUpdatedAt: triggerEvidence.updatedAt,
797
+ triggerCount: triggerEvidence.count,
798
+ userModelNeedsSeed: this.userModelNeedsSeed(metrics),
799
+ };
800
+ }
801
+ pendingTriggerEvidence() {
802
+ const triggersDir = path.join(SELF_IMPROVE_DIR, 'triggers');
803
+ try {
804
+ if (!existsSync(triggersDir))
805
+ return { count: 0, updatedAt: [] };
806
+ const files = readdirSync(triggersDir).filter(f => f.endsWith('.json'));
807
+ return {
808
+ count: files.length,
809
+ updatedAt: files.map(f => {
810
+ try {
811
+ return statSync(path.join(triggersDir, f)).mtime.toISOString();
812
+ }
813
+ catch {
814
+ return '';
815
+ }
816
+ }).filter(Boolean),
817
+ };
818
+ }
819
+ catch {
820
+ return { count: 0, updatedAt: [] };
821
+ }
822
+ }
823
+ userModelNeedsSeed(metrics) {
824
+ try {
825
+ const store = new MemoryStore(MEMORY_DB_PATH, VAULT_DIR);
826
+ store.initialize();
827
+ try {
828
+ const signalCount = store.getRecentReflections(30).length + store.getRecentFeedback(30).length;
829
+ if (signalCount < 5 && metrics.negativeFeedback.length + metrics.cronReflections.length < 5)
830
+ return false;
831
+ return store.getAllUserModelBlocks().filter(b => b.content.trim()).length === 0;
832
+ }
833
+ finally {
834
+ store.close();
835
+ }
836
+ }
837
+ catch {
838
+ return false;
839
+ }
840
+ }
647
841
  // ── Steps 2-3: Diagnose + Hypothesize ────────────────────────────
648
842
  async hypothesize(metrics, history) {
649
843
  // Read targeted triggers (written by cron scheduler when jobs fail repeatedly)
@@ -948,11 +1142,17 @@ export class SelfImproveLoop {
948
1142
  : rawParsed ? [rawParsed] : [];
949
1143
  if (opportunities.length === 0)
950
1144
  return null;
951
- // Pick the first opportunity that isn't over-targeted
952
- const selected = opportunities.find((o) => {
1145
+ // Pick the first opportunity that isn't over-targeted. Down-rank SOUL.md
1146
+ // after plateau/denied loops unless feedback synthesis produced fresh
1147
+ // SOUL candidates; most operational signals should become prompt
1148
+ // overrides, advisor rules, agent changes, or cron fixes.
1149
+ const isViableOpportunity = (o) => {
953
1150
  const key = `${o.area}:${o.target}`;
954
1151
  return !overTargeted.includes(key) && !overTargetedAreas.includes(o.area);
955
- }) ?? opportunities[0];
1152
+ };
1153
+ const hasSoulCandidates = !!soulCandidatesText && !/No candidates/i.test(soulCandidatesText);
1154
+ const recentSoulPlateau = history.slice(-10).some(e => e.area === 'soul' && isPlateauExperiment(e));
1155
+ const selected = opportunities.find((o) => isViableOpportunity(o) && (o.area !== 'soul' || hasSoulCandidates || !recentSoulPlateau)) ?? opportunities.find(isViableOpportunity) ?? opportunities[0];
956
1156
  // ── Step 2: Proposal — load only the target file, generate specific change ──
957
1157
  const currentContent = await this.readCurrentState(selected.area, selected.target);
958
1158
  const proposalPrompt = `You identified this as the highest-impact improvement:\n` +
@@ -1373,12 +1573,12 @@ export class SelfImproveLoop {
1373
1573
  /** Update the structured user model from interaction data. */
1374
1574
  async updateUserModel() {
1375
1575
  try {
1376
- const { MemoryStore } = await import('../memory/store.js');
1377
1576
  const store = new MemoryStore(MEMORY_DB_PATH, VAULT_DIR);
1378
1577
  store.initialize();
1379
1578
  const reflections = store.getRecentReflections(30);
1380
1579
  const feedback = store.getRecentFeedback(30);
1381
1580
  const patterns = store.getBehavioralPatterns(1);
1581
+ const existingDbModel = store.renderUserModel();
1382
1582
  store.close();
1383
1583
  if (reflections.length + feedback.length < 5) {
1384
1584
  logger.info('Not enough interaction data for user model update');
@@ -1397,36 +1597,74 @@ export class SelfImproveLoop {
1397
1597
  const feedbackSummary = feedback.slice(0, 15).map(f => `- [${f.rating}] ${f.channel}: ${f.comment || f.messageSnippet || '(no detail)'}`.slice(0, 120)).join('\n');
1398
1598
  const patternSummary = patterns.map(p => `- "${p.correction}" [${p.category}] x${p.count}`).join('\n');
1399
1599
  const prompt = `You are updating a structured user model based on interaction data. The model tracks the owner's expertise, priorities, communication preferences, and behavioral patterns.\n\n` +
1400
- `## Current Model\n${existingModel || '(empty — first synthesis)'}\n\n` +
1600
+ `## Current Markdown Model\n${existingModel || '(empty — first synthesis)'}\n\n` +
1601
+ `## Current DB Slots\n${existingDbModel || '(empty — no user_model_blocks populated yet)'}\n\n` +
1401
1602
  `## Recent Session Reflections (${reflections.length})\n${reflectionSummary || '(none)'}\n\n` +
1402
1603
  `## Recent Feedback (${feedback.length})\n${feedbackSummary || '(none)'}\n\n` +
1403
1604
  `## Recurring Behavioral Patterns\n${patternSummary || '(none)'}\n\n` +
1404
1605
  `## Instructions\n` +
1405
- `Output a YAML frontmatter block for USER_MODEL.md. Include these sections:\n` +
1406
- `- expertise: map of domain level (beginner/intermediate/expert) based on how they interact\n` +
1407
- `- priorities: list of current focus areas with priority level\n` +
1408
- `- communication: style, verbosity, decision_making, time_sensitivity\n` +
1409
- `- patterns: morning/afternoon/evening behavioral patterns\n` +
1410
- `- confidence_scores: how confident each section is (0-1)\n\n` +
1411
- `Preserve existing data that's still accurate. Only update fields where new evidence supports a change.\n` +
1412
- `Output ONLY the YAML frontmatter block (--- delimited), no other text.`;
1606
+ `Return a JSON object with:\n` +
1607
+ `- frontmatterYaml: YAML body for USER_MODEL.md, without --- delimiters. Include expertise, priorities, communication, patterns, confidence_scores.\n` +
1608
+ `- slots: object with exactly these keys: user_facts, goals, relationships, agent_persona.\n\n` +
1609
+ `Slot guidance:\n` +
1610
+ `- user_facts: durable facts about the owner, expertise, working style, identifiers that should always be top-of-mind.\n` +
1611
+ `- goals: active intents/priorities only; omit stale or weakly inferred goals.\n` +
1612
+ `- relationships: people, companies, agents, projects, and how they relate to the owner.\n` +
1613
+ `- agent_persona: durable guidance for Clementine's behavior with this owner.\n\n` +
1614
+ `Keep each slot concise (prefer under 1200 chars). Preserve existing data that's still accurate. Only update fields where evidence supports a change. Use an empty string for a slot with no evidence.\n` +
1615
+ `Output ONLY valid JSON, no markdown.`;
1413
1616
  const result = await this.assistant.runPlanStep('si-user-model', prompt, {
1414
1617
  tier: 1,
1415
1618
  maxTurns: 1,
1416
1619
  disableTools: true,
1620
+ outputFormat: {
1621
+ type: 'json_schema',
1622
+ schema: {
1623
+ type: 'object',
1624
+ properties: {
1625
+ frontmatterYaml: { type: 'string' },
1626
+ slots: {
1627
+ type: 'object',
1628
+ properties: {
1629
+ user_facts: { type: 'string' },
1630
+ goals: { type: 'string' },
1631
+ relationships: { type: 'string' },
1632
+ agent_persona: { type: 'string' },
1633
+ },
1634
+ required: ['user_facts', 'goals', 'relationships', 'agent_persona'],
1635
+ },
1636
+ },
1637
+ required: ['frontmatterYaml', 'slots'],
1638
+ },
1639
+ },
1417
1640
  });
1418
- // Extract YAML frontmatter from response
1419
- const yamlMatch = result.match(/---\s*\n([\s\S]*?)\n---/);
1420
- if (!yamlMatch) {
1421
- logger.warn('User model synthesis returned no YAML block');
1641
+ const parsed = this.parseJsonResponse(result);
1642
+ const slots = normalizeUserModelSlots(parsed?.slots);
1643
+ const frontmatterYaml = typeof parsed?.frontmatterYaml === 'string' && parsed.frontmatterYaml.trim()
1644
+ ? parsed.frontmatterYaml.trim()
1645
+ : 'confidence_scores: {}';
1646
+ if (Object.keys(slots).length === 0) {
1647
+ logger.warn('User model synthesis returned no populated DB slots');
1422
1648
  return;
1423
1649
  }
1424
1650
  const modelDir = path.join(VAULT_DIR, '00-System');
1425
1651
  if (!existsSync(modelDir))
1426
1652
  mkdirSync(modelDir, { recursive: true });
1427
- const content = `---\n${yamlMatch[1].trim()}\nlast_updated: "${new Date().toISOString()}"\n---\n\n# User Model\n\nThis file is auto-generated by the self-improvement loop. It captures a structured understanding of the owner based on interaction patterns, feedback, and behavioral corrections.\n`;
1653
+ const writeStore = new MemoryStore(MEMORY_DB_PATH, VAULT_DIR);
1654
+ writeStore.initialize();
1655
+ try {
1656
+ for (const key of USER_MODEL_SLOT_KEYS) {
1657
+ const content = slots[key];
1658
+ if (content)
1659
+ writeStore.setUserModelBlock({ slot: key, content });
1660
+ }
1661
+ }
1662
+ finally {
1663
+ writeStore.close();
1664
+ }
1665
+ const content = buildUserModelMarkdown(frontmatterYaml, slots);
1428
1666
  writeFileSync(modelFile, content);
1429
- logger.info('User model updated: USER_MODEL.md');
1667
+ logger.info({ slots: Object.keys(slots) }, 'User model updated: DB slots + USER_MODEL.md');
1430
1668
  }
1431
1669
  catch (err) {
1432
1670
  logger.error({ err }, 'User model update failed');
@@ -1481,12 +1719,14 @@ export class SelfImproveLoop {
1481
1719
  reconcileState() {
1482
1720
  const state = this.loadState();
1483
1721
  const actualPending = this.getPendingChanges().length;
1484
- if (state.pendingApprovals !== actualPending) {
1485
- logger.warn({ stored: state.pendingApprovals, actual: actualPending }, 'Pending approvals counter drift — reconciling');
1486
- state.pendingApprovals = actualPending;
1487
- this.saveState(state);
1722
+ const reconciled = reconcileSelfImproveStateSnapshot(state, actualPending, {
1723
+ maxDurationMs: this.config.maxDurationMs,
1724
+ });
1725
+ if (reconciled.changed) {
1726
+ logger.warn({ diagnostics: reconciled.diagnostics, storedPending: state.pendingApprovals, actualPending }, 'Self-improve state drift — reconciling');
1727
+ this.saveState(reconciled.state);
1488
1728
  }
1489
- return state;
1729
+ return reconciled.state;
1490
1730
  }
1491
1731
  /** Expire pending proposals older than APPROVAL_TTL_MS. */
1492
1732
  expireStaleProposals() {
@@ -1684,6 +1684,7 @@ export class Gateway {
1684
1684
  `Last run: ${state.lastRunAt || 'never'}\n` +
1685
1685
  `Total experiments: ${state.totalExperiments}\n` +
1686
1686
  `Pending approvals: ${state.pendingApprovals}\n` +
1687
+ (state.lastDiagnostic ? `Diagnostic: ${state.lastDiagnostic}\n` : '') +
1687
1688
  `Baseline — Feedback: ${(m.feedbackPositiveRatio * 100).toFixed(0)}% positive, ` +
1688
1689
  `Cron: ${(m.cronSuccessRate * 100).toFixed(0)}% success, ` +
1689
1690
  `Quality: ${m.avgResponseQuality.toFixed(2)}`;
@@ -1282,12 +1282,23 @@ export declare class MemoryStore {
1282
1282
  count: number;
1283
1283
  }>;
1284
1284
  tableRowCounts: Record<string, number>;
1285
+ recentActivity: {
1286
+ recallTracesLast7d: number;
1287
+ recallTracesLast30d: number;
1288
+ extractionSkipsLast30d: number;
1289
+ };
1285
1290
  topCitedLast30d: Array<{
1286
1291
  chunkId: number;
1287
1292
  sourceFile: string;
1288
1293
  section: string;
1289
1294
  refCount: number;
1290
1295
  }>;
1296
+ userModelSlots: {
1297
+ total: number;
1298
+ populated: number;
1299
+ global: number;
1300
+ agentScoped: number;
1301
+ };
1291
1302
  staleUserModelSlots: Array<{
1292
1303
  slot: string;
1293
1304
  ageDays: number;
@@ -1300,6 +1311,7 @@ export declare class MemoryStore {
1300
1311
  salience: number;
1301
1312
  lastOutcomeScore: number;
1302
1313
  }>;
1314
+ selfImprovePlateausLast7d: number;
1303
1315
  chunkCacheStats: ReturnType<HotCache<number, unknown>['stats']>;
1304
1316
  writeQueue: {
1305
1317
  size: number;