clementine-agent 1.18.8 → 1.18.10

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 (386) hide show
  1. package/dist/agent/assistant.d.ts +9 -2
  2. package/dist/agent/assistant.js +246 -44
  3. package/dist/agent/local-turn.d.ts +32 -0
  4. package/dist/agent/local-turn.js +107 -0
  5. package/dist/agent/self-improve-loop.js +1 -0
  6. package/dist/agent/self-improve.d.ts +34 -0
  7. package/dist/agent/self-improve.js +282 -42
  8. package/dist/agent/turn-policy.d.ts +5 -0
  9. package/dist/agent/turn-policy.js +39 -0
  10. package/dist/channels/discord-agent-bot.js +2 -0
  11. package/dist/channels/slack-agent-bot.js +1 -1
  12. package/dist/channels/slack.js +1 -1
  13. package/dist/channels/telegram.js +10 -3
  14. package/dist/cli/dashboard.js +540 -51
  15. package/dist/config/clementine-json.d.ts +30 -0
  16. package/dist/config/clementine-json.js +39 -1
  17. package/dist/config/effective-config.js +5 -0
  18. package/dist/config.d.ts +6 -0
  19. package/dist/config.js +6 -0
  20. package/dist/gateway/cron-scheduler.d.ts +1 -1
  21. package/dist/gateway/cron-scheduler.js +17 -3
  22. package/dist/gateway/router.d.ts +8 -0
  23. package/dist/gateway/router.js +254 -7
  24. package/dist/memory/store.d.ts +12 -0
  25. package/dist/memory/store.js +51 -0
  26. package/dist/tools/shared.d.ts +12 -0
  27. package/dist/types.d.ts +3 -1
  28. package/package.json +2 -2
  29. package/dist/agent/advisor-rules/context.d.ts.map +0 -1
  30. package/dist/agent/advisor-rules/context.js.map +0 -1
  31. package/dist/agent/advisor-rules/engine.d.ts.map +0 -1
  32. package/dist/agent/advisor-rules/engine.js.map +0 -1
  33. package/dist/agent/advisor-rules/loader.d.ts.map +0 -1
  34. package/dist/agent/advisor-rules/loader.js.map +0 -1
  35. package/dist/agent/advisor-rules/types.d.ts.map +0 -1
  36. package/dist/agent/advisor-rules/types.js.map +0 -1
  37. package/dist/agent/agent-manager.d.ts.map +0 -1
  38. package/dist/agent/agent-manager.js.map +0 -1
  39. package/dist/agent/assistant.d.ts.map +0 -1
  40. package/dist/agent/assistant.js.map +0 -1
  41. package/dist/agent/auto-skills.d.ts.map +0 -1
  42. package/dist/agent/auto-skills.js.map +0 -1
  43. package/dist/agent/auto-update.d.ts.map +0 -1
  44. package/dist/agent/auto-update.js.map +0 -1
  45. package/dist/agent/background-tasks.d.ts.map +0 -1
  46. package/dist/agent/background-tasks.js.map +0 -1
  47. package/dist/agent/brain-digest.d.ts.map +0 -1
  48. package/dist/agent/brain-digest.js.map +0 -1
  49. package/dist/agent/budget-enforcement.d.ts.map +0 -1
  50. package/dist/agent/budget-enforcement.js.map +0 -1
  51. package/dist/agent/complexity-classifier.d.ts.map +0 -1
  52. package/dist/agent/complexity-classifier.js.map +0 -1
  53. package/dist/agent/contradiction-validator.d.ts.map +0 -1
  54. package/dist/agent/contradiction-validator.js.map +0 -1
  55. package/dist/agent/crash-forensics.d.ts.map +0 -1
  56. package/dist/agent/crash-forensics.js.map +0 -1
  57. package/dist/agent/daily-planner.d.ts.map +0 -1
  58. package/dist/agent/daily-planner.js.map +0 -1
  59. package/dist/agent/decision-reflection.d.ts.map +0 -1
  60. package/dist/agent/decision-reflection.js.map +0 -1
  61. package/dist/agent/execution-advisor.d.ts.map +0 -1
  62. package/dist/agent/execution-advisor.js.map +0 -1
  63. package/dist/agent/hooks.d.ts.map +0 -1
  64. package/dist/agent/hooks.js.map +0 -1
  65. package/dist/agent/insight-engine.d.ts.map +0 -1
  66. package/dist/agent/insight-engine.js.map +0 -1
  67. package/dist/agent/intent-classifier.d.ts.map +0 -1
  68. package/dist/agent/intent-classifier.js.map +0 -1
  69. package/dist/agent/link-extractor.d.ts.map +0 -1
  70. package/dist/agent/link-extractor.js.map +0 -1
  71. package/dist/agent/mcp-bridge.d.ts.map +0 -1
  72. package/dist/agent/mcp-bridge.js.map +0 -1
  73. package/dist/agent/mcp-circuit-breaker.d.ts.map +0 -1
  74. package/dist/agent/mcp-circuit-breaker.js.map +0 -1
  75. package/dist/agent/mcp-schemas.d.ts.map +0 -1
  76. package/dist/agent/mcp-schemas.js.map +0 -1
  77. package/dist/agent/metacognition.d.ts.map +0 -1
  78. package/dist/agent/metacognition.js.map +0 -1
  79. package/dist/agent/orchestrator.d.ts.map +0 -1
  80. package/dist/agent/orchestrator.js.map +0 -1
  81. package/dist/agent/proactive-engine.d.ts.map +0 -1
  82. package/dist/agent/proactive-engine.js.map +0 -1
  83. package/dist/agent/proactive-ledger.d.ts.map +0 -1
  84. package/dist/agent/proactive-ledger.js.map +0 -1
  85. package/dist/agent/prompt-cache.d.ts.map +0 -1
  86. package/dist/agent/prompt-cache.js.map +0 -1
  87. package/dist/agent/prompt-evolver.d.ts.map +0 -1
  88. package/dist/agent/prompt-evolver.js.map +0 -1
  89. package/dist/agent/prompt-overrides/loader.d.ts.map +0 -1
  90. package/dist/agent/prompt-overrides/loader.js.map +0 -1
  91. package/dist/agent/prompt-overrides/types.d.ts.map +0 -1
  92. package/dist/agent/prompt-overrides/types.js.map +0 -1
  93. package/dist/agent/role-scaffolds.d.ts.map +0 -1
  94. package/dist/agent/role-scaffolds.js.map +0 -1
  95. package/dist/agent/route-classifier.d.ts.map +0 -1
  96. package/dist/agent/route-classifier.js.map +0 -1
  97. package/dist/agent/safe-restart.d.ts.map +0 -1
  98. package/dist/agent/safe-restart.js.map +0 -1
  99. package/dist/agent/self-improve-loop.d.ts.map +0 -1
  100. package/dist/agent/self-improve-loop.js.map +0 -1
  101. package/dist/agent/self-improve.d.ts.map +0 -1
  102. package/dist/agent/self-improve.js.map +0 -1
  103. package/dist/agent/session-event-log.d.ts.map +0 -1
  104. package/dist/agent/session-event-log.js.map +0 -1
  105. package/dist/agent/session-store-adapter.d.ts.map +0 -1
  106. package/dist/agent/session-store-adapter.js.map +0 -1
  107. package/dist/agent/skill-extractor.d.ts.map +0 -1
  108. package/dist/agent/skill-extractor.js.map +0 -1
  109. package/dist/agent/source-mods.d.ts.map +0 -1
  110. package/dist/agent/source-mods.js.map +0 -1
  111. package/dist/agent/source-preflight.d.ts.map +0 -1
  112. package/dist/agent/source-preflight.js.map +0 -1
  113. package/dist/agent/stall-guard.d.ts.map +0 -1
  114. package/dist/agent/stall-guard.js.map +0 -1
  115. package/dist/agent/strategic-planner.d.ts.map +0 -1
  116. package/dist/agent/strategic-planner.js.map +0 -1
  117. package/dist/agent/team-bus.d.ts.map +0 -1
  118. package/dist/agent/team-bus.js.map +0 -1
  119. package/dist/agent/team-router.d.ts.map +0 -1
  120. package/dist/agent/team-router.js.map +0 -1
  121. package/dist/agent/tool-loop-detector.d.ts.map +0 -1
  122. package/dist/agent/tool-loop-detector.js.map +0 -1
  123. package/dist/agent/tool-router.d.ts.map +0 -1
  124. package/dist/agent/tool-router.js.map +0 -1
  125. package/dist/agent/turn-policy.d.ts.map +0 -1
  126. package/dist/agent/turn-policy.js.map +0 -1
  127. package/dist/agent/webhook-actions.d.ts.map +0 -1
  128. package/dist/agent/webhook-actions.js.map +0 -1
  129. package/dist/agent/workflow-runner.d.ts.map +0 -1
  130. package/dist/agent/workflow-runner.js.map +0 -1
  131. package/dist/agent/workflow-variables.d.ts.map +0 -1
  132. package/dist/agent/workflow-variables.js.map +0 -1
  133. package/dist/analytics/tool-usage.d.ts.map +0 -1
  134. package/dist/analytics/tool-usage.js.map +0 -1
  135. package/dist/brain/adapters/common.d.ts.map +0 -1
  136. package/dist/brain/adapters/common.js.map +0 -1
  137. package/dist/brain/adapters/csv.d.ts.map +0 -1
  138. package/dist/brain/adapters/csv.js.map +0 -1
  139. package/dist/brain/adapters/docx.d.ts.map +0 -1
  140. package/dist/brain/adapters/docx.js.map +0 -1
  141. package/dist/brain/adapters/email.d.ts.map +0 -1
  142. package/dist/brain/adapters/email.js.map +0 -1
  143. package/dist/brain/adapters/index.d.ts.map +0 -1
  144. package/dist/brain/adapters/index.js.map +0 -1
  145. package/dist/brain/adapters/json.d.ts.map +0 -1
  146. package/dist/brain/adapters/json.js.map +0 -1
  147. package/dist/brain/adapters/markdown.d.ts.map +0 -1
  148. package/dist/brain/adapters/markdown.js.map +0 -1
  149. package/dist/brain/adapters/pdf.d.ts.map +0 -1
  150. package/dist/brain/adapters/pdf.js.map +0 -1
  151. package/dist/brain/adapters/rest.d.ts.map +0 -1
  152. package/dist/brain/adapters/rest.js.map +0 -1
  153. package/dist/brain/batch-summary.d.ts.map +0 -1
  154. package/dist/brain/batch-summary.js.map +0 -1
  155. package/dist/brain/connector-recipes.d.ts.map +0 -1
  156. package/dist/brain/connector-recipes.js.map +0 -1
  157. package/dist/brain/format-detector.d.ts.map +0 -1
  158. package/dist/brain/format-detector.js.map +0 -1
  159. package/dist/brain/graph-extractor.d.ts.map +0 -1
  160. package/dist/brain/graph-extractor.js.map +0 -1
  161. package/dist/brain/ingest-scheduler.d.ts.map +0 -1
  162. package/dist/brain/ingest-scheduler.js.map +0 -1
  163. package/dist/brain/ingestion-pipeline.d.ts.map +0 -1
  164. package/dist/brain/ingestion-pipeline.js.map +0 -1
  165. package/dist/brain/intelligence.d.ts.map +0 -1
  166. package/dist/brain/intelligence.js.map +0 -1
  167. package/dist/brain/llm-client.d.ts.map +0 -1
  168. package/dist/brain/llm-client.js.map +0 -1
  169. package/dist/brain/source-registry.d.ts.map +0 -1
  170. package/dist/brain/source-registry.js.map +0 -1
  171. package/dist/channels/discord-agent-bot.d.ts.map +0 -1
  172. package/dist/channels/discord-agent-bot.js.map +0 -1
  173. package/dist/channels/discord-bot-manager.d.ts.map +0 -1
  174. package/dist/channels/discord-bot-manager.js.map +0 -1
  175. package/dist/channels/discord-utils.d.ts.map +0 -1
  176. package/dist/channels/discord-utils.js.map +0 -1
  177. package/dist/channels/discord.d.ts.map +0 -1
  178. package/dist/channels/discord.js.map +0 -1
  179. package/dist/channels/slack-agent-bot.d.ts.map +0 -1
  180. package/dist/channels/slack-agent-bot.js.map +0 -1
  181. package/dist/channels/slack-bot-manager.d.ts.map +0 -1
  182. package/dist/channels/slack-bot-manager.js.map +0 -1
  183. package/dist/channels/slack-utils.d.ts.map +0 -1
  184. package/dist/channels/slack-utils.js.map +0 -1
  185. package/dist/channels/slack.d.ts.map +0 -1
  186. package/dist/channels/slack.js.map +0 -1
  187. package/dist/channels/telegram.d.ts.map +0 -1
  188. package/dist/channels/telegram.js.map +0 -1
  189. package/dist/channels/webhook.d.ts.map +0 -1
  190. package/dist/channels/webhook.js.map +0 -1
  191. package/dist/channels/whatsapp.d.ts.map +0 -1
  192. package/dist/channels/whatsapp.js.map +0 -1
  193. package/dist/cli/browser.d.ts.map +0 -1
  194. package/dist/cli/browser.js.map +0 -1
  195. package/dist/cli/chat.d.ts.map +0 -1
  196. package/dist/cli/chat.js.map +0 -1
  197. package/dist/cli/cron.d.ts.map +0 -1
  198. package/dist/cli/cron.js.map +0 -1
  199. package/dist/cli/dashboard.d.ts.map +0 -1
  200. package/dist/cli/dashboard.js.map +0 -1
  201. package/dist/cli/index.d.ts.map +0 -1
  202. package/dist/cli/index.js.map +0 -1
  203. package/dist/cli/ingest.d.ts.map +0 -1
  204. package/dist/cli/ingest.js.map +0 -1
  205. package/dist/cli/routes/delegations.d.ts.map +0 -1
  206. package/dist/cli/routes/delegations.js.map +0 -1
  207. package/dist/cli/routes/digest.d.ts.map +0 -1
  208. package/dist/cli/routes/digest.js.map +0 -1
  209. package/dist/cli/routes/goals.d.ts.map +0 -1
  210. package/dist/cli/routes/goals.js.map +0 -1
  211. package/dist/cli/routes/workflows.d.ts.map +0 -1
  212. package/dist/cli/routes/workflows.js.map +0 -1
  213. package/dist/cli/setup.d.ts.map +0 -1
  214. package/dist/cli/setup.js.map +0 -1
  215. package/dist/cli/tunnel.d.ts.map +0 -1
  216. package/dist/cli/tunnel.js.map +0 -1
  217. package/dist/cli/version-check.d.ts.map +0 -1
  218. package/dist/cli/version-check.js.map +0 -1
  219. package/dist/config/clementine-json.d.ts.map +0 -1
  220. package/dist/config/clementine-json.js.map +0 -1
  221. package/dist/config/config-doctor.d.ts.map +0 -1
  222. package/dist/config/config-doctor.js.map +0 -1
  223. package/dist/config/effective-config.d.ts.map +0 -1
  224. package/dist/config/effective-config.js.map +0 -1
  225. package/dist/config/env-parser.d.ts.map +0 -1
  226. package/dist/config/env-parser.js.map +0 -1
  227. package/dist/config/harden-permissions.d.ts.map +0 -1
  228. package/dist/config/harden-permissions.js.map +0 -1
  229. package/dist/config/integrations-registry.d.ts.map +0 -1
  230. package/dist/config/integrations-registry.js.map +0 -1
  231. package/dist/config/keychain-first-run-wizard.d.ts.map +0 -1
  232. package/dist/config/keychain-first-run-wizard.js.map +0 -1
  233. package/dist/config/keychain-fix-acl.d.ts.map +0 -1
  234. package/dist/config/keychain-fix-acl.js.map +0 -1
  235. package/dist/config/migrate-from-keychain.d.ts.map +0 -1
  236. package/dist/config/migrate-from-keychain.js.map +0 -1
  237. package/dist/config/migrate-keychain.d.ts.map +0 -1
  238. package/dist/config/migrate-keychain.js.map +0 -1
  239. package/dist/config.d.ts.map +0 -1
  240. package/dist/config.js.map +0 -1
  241. package/dist/dashboard/builder/dry-run.d.ts.map +0 -1
  242. package/dist/dashboard/builder/dry-run.js.map +0 -1
  243. package/dist/dashboard/builder/events.d.ts.map +0 -1
  244. package/dist/dashboard/builder/events.js.map +0 -1
  245. package/dist/dashboard/builder/mcp-invoke.d.ts.map +0 -1
  246. package/dist/dashboard/builder/mcp-invoke.js.map +0 -1
  247. package/dist/dashboard/builder/runner.d.ts.map +0 -1
  248. package/dist/dashboard/builder/runner.js.map +0 -1
  249. package/dist/dashboard/builder/serializer.d.ts.map +0 -1
  250. package/dist/dashboard/builder/serializer.js.map +0 -1
  251. package/dist/dashboard/builder/snapshots.d.ts.map +0 -1
  252. package/dist/dashboard/builder/snapshots.js.map +0 -1
  253. package/dist/dashboard/builder/validation.d.ts.map +0 -1
  254. package/dist/dashboard/builder/validation.js.map +0 -1
  255. package/dist/events/bus.d.ts.map +0 -1
  256. package/dist/events/bus.js.map +0 -1
  257. package/dist/gateway/agent-heartbeat-manager.d.ts.map +0 -1
  258. package/dist/gateway/agent-heartbeat-manager.js.map +0 -1
  259. package/dist/gateway/agent-heartbeat-scheduler.d.ts.map +0 -1
  260. package/dist/gateway/agent-heartbeat-scheduler.js.map +0 -1
  261. package/dist/gateway/claim-tracker.d.ts.map +0 -1
  262. package/dist/gateway/claim-tracker.js.map +0 -1
  263. package/dist/gateway/cron-scheduler.d.ts.map +0 -1
  264. package/dist/gateway/cron-scheduler.js.map +0 -1
  265. package/dist/gateway/delivery-queue.d.ts.map +0 -1
  266. package/dist/gateway/delivery-queue.js.map +0 -1
  267. package/dist/gateway/failure-diagnostics.d.ts.map +0 -1
  268. package/dist/gateway/failure-diagnostics.js.map +0 -1
  269. package/dist/gateway/failure-monitor.d.ts.map +0 -1
  270. package/dist/gateway/failure-monitor.js.map +0 -1
  271. package/dist/gateway/fix-applier.d.ts.map +0 -1
  272. package/dist/gateway/fix-applier.js.map +0 -1
  273. package/dist/gateway/fix-verification.d.ts.map +0 -1
  274. package/dist/gateway/fix-verification.js.map +0 -1
  275. package/dist/gateway/heartbeat-scheduler.d.ts.map +0 -1
  276. package/dist/gateway/heartbeat-scheduler.js.map +0 -1
  277. package/dist/gateway/heartbeat.d.ts.map +0 -1
  278. package/dist/gateway/heartbeat.js.map +0 -1
  279. package/dist/gateway/lanes.d.ts.map +0 -1
  280. package/dist/gateway/lanes.js.map +0 -1
  281. package/dist/gateway/notifications.d.ts.map +0 -1
  282. package/dist/gateway/notifications.js.map +0 -1
  283. package/dist/gateway/outcome-grader.d.ts.map +0 -1
  284. package/dist/gateway/outcome-grader.js.map +0 -1
  285. package/dist/gateway/router.d.ts.map +0 -1
  286. package/dist/gateway/router.js.map +0 -1
  287. package/dist/index.d.ts.map +0 -1
  288. package/dist/index.js.map +0 -1
  289. package/dist/integrations/composio/client.d.ts.map +0 -1
  290. package/dist/integrations/composio/client.js.map +0 -1
  291. package/dist/integrations/composio/mcp-bridge.d.ts.map +0 -1
  292. package/dist/integrations/composio/mcp-bridge.js.map +0 -1
  293. package/dist/integrations/tool-preferences.d.ts.map +0 -1
  294. package/dist/integrations/tool-preferences.js.map +0 -1
  295. package/dist/memory/chunker.d.ts.map +0 -1
  296. package/dist/memory/chunker.js.map +0 -1
  297. package/dist/memory/consolidation.d.ts.map +0 -1
  298. package/dist/memory/consolidation.js.map +0 -1
  299. package/dist/memory/context-assembler.d.ts.map +0 -1
  300. package/dist/memory/context-assembler.js.map +0 -1
  301. package/dist/memory/embeddings.d.ts.map +0 -1
  302. package/dist/memory/embeddings.js.map +0 -1
  303. package/dist/memory/graph-store.d.ts.map +0 -1
  304. package/dist/memory/graph-store.js.map +0 -1
  305. package/dist/memory/hot-cache.d.ts.map +0 -1
  306. package/dist/memory/hot-cache.js.map +0 -1
  307. package/dist/memory/integrity.d.ts.map +0 -1
  308. package/dist/memory/integrity.js.map +0 -1
  309. package/dist/memory/maintenance.d.ts.map +0 -1
  310. package/dist/memory/maintenance.js.map +0 -1
  311. package/dist/memory/mmr.d.ts.map +0 -1
  312. package/dist/memory/mmr.js.map +0 -1
  313. package/dist/memory/search.d.ts.map +0 -1
  314. package/dist/memory/search.js.map +0 -1
  315. package/dist/memory/seed-user-model.d.ts.map +0 -1
  316. package/dist/memory/seed-user-model.js.map +0 -1
  317. package/dist/memory/store.d.ts.map +0 -1
  318. package/dist/memory/store.js.map +0 -1
  319. package/dist/memory/write-queue.d.ts.map +0 -1
  320. package/dist/memory/write-queue.js.map +0 -1
  321. package/dist/secrets/auth-profiles.d.ts.map +0 -1
  322. package/dist/secrets/auth-profiles.js.map +0 -1
  323. package/dist/secrets/keychain.d.ts.map +0 -1
  324. package/dist/secrets/keychain.js.map +0 -1
  325. package/dist/secrets/resolver.d.ts.map +0 -1
  326. package/dist/secrets/resolver.js.map +0 -1
  327. package/dist/secrets/sensitivity.d.ts.map +0 -1
  328. package/dist/secrets/sensitivity.js.map +0 -1
  329. package/dist/security/integrity.d.ts.map +0 -1
  330. package/dist/security/integrity.js.map +0 -1
  331. package/dist/security/patterns.d.ts.map +0 -1
  332. package/dist/security/patterns.js.map +0 -1
  333. package/dist/security/redact.d.ts.map +0 -1
  334. package/dist/security/redact.js.map +0 -1
  335. package/dist/security/scanner.d.ts.map +0 -1
  336. package/dist/security/scanner.js.map +0 -1
  337. package/dist/tools/admin-tools.d.ts.map +0 -1
  338. package/dist/tools/admin-tools.js.map +0 -1
  339. package/dist/tools/agent-heartbeat-tools.d.ts.map +0 -1
  340. package/dist/tools/agent-heartbeat-tools.js.map +0 -1
  341. package/dist/tools/artifact-tools.d.ts.map +0 -1
  342. package/dist/tools/artifact-tools.js.map +0 -1
  343. package/dist/tools/background-task-tools.d.ts.map +0 -1
  344. package/dist/tools/background-task-tools.js.map +0 -1
  345. package/dist/tools/brain-tools.d.ts.map +0 -1
  346. package/dist/tools/brain-tools.js.map +0 -1
  347. package/dist/tools/builder-tools.d.ts.map +0 -1
  348. package/dist/tools/builder-tools.js.map +0 -1
  349. package/dist/tools/decision-reflection-tools.d.ts.map +0 -1
  350. package/dist/tools/decision-reflection-tools.js.map +0 -1
  351. package/dist/tools/external-tools.d.ts.map +0 -1
  352. package/dist/tools/external-tools.js.map +0 -1
  353. package/dist/tools/goal-tools.d.ts.map +0 -1
  354. package/dist/tools/goal-tools.js.map +0 -1
  355. package/dist/tools/mcp-server.d.ts.map +0 -1
  356. package/dist/tools/mcp-server.js.map +0 -1
  357. package/dist/tools/memory-tools.d.ts.map +0 -1
  358. package/dist/tools/memory-tools.js.map +0 -1
  359. package/dist/tools/session-tools.d.ts.map +0 -1
  360. package/dist/tools/session-tools.js.map +0 -1
  361. package/dist/tools/shared.d.ts.map +0 -1
  362. package/dist/tools/shared.js.map +0 -1
  363. package/dist/tools/team-tools.d.ts.map +0 -1
  364. package/dist/tools/team-tools.js.map +0 -1
  365. package/dist/tools/tool-meta.d.ts.map +0 -1
  366. package/dist/tools/tool-meta.js.map +0 -1
  367. package/dist/tools/vault-tools.d.ts.map +0 -1
  368. package/dist/tools/vault-tools.js.map +0 -1
  369. package/dist/types.d.ts.map +0 -1
  370. package/dist/types.js.map +0 -1
  371. package/dist/vault-migrations/0001-add-execution-framework.d.ts.map +0 -1
  372. package/dist/vault-migrations/0001-add-execution-framework.js.map +0 -1
  373. package/dist/vault-migrations/0002-add-agentic-communication.d.ts.map +0 -1
  374. package/dist/vault-migrations/0002-add-agentic-communication.js.map +0 -1
  375. package/dist/vault-migrations/0003-update-execution-pipeline-narration.d.ts.map +0 -1
  376. package/dist/vault-migrations/0003-update-execution-pipeline-narration.js.map +0 -1
  377. package/dist/vault-migrations/0004-backfill-schema-versions.d.ts.map +0 -1
  378. package/dist/vault-migrations/0004-backfill-schema-versions.js.map +0 -1
  379. package/dist/vault-migrations/0005-create-clementine-json.d.ts.map +0 -1
  380. package/dist/vault-migrations/0005-create-clementine-json.js.map +0 -1
  381. package/dist/vault-migrations/helpers.d.ts.map +0 -1
  382. package/dist/vault-migrations/helpers.js.map +0 -1
  383. package/dist/vault-migrations/runner.d.ts.map +0 -1
  384. package/dist/vault-migrations/runner.js.map +0 -1
  385. package/dist/vault-migrations/types.d.ts.map +0 -1
  386. package/dist/vault-migrations/types.js.map +0 -1
@@ -27,6 +27,11 @@ import { AgentManager } from './agent-manager.js';
27
27
  * SDK result; this function is for pre-flight planning only.
28
28
  */
29
29
  export declare function estimateTokens(text: string): number;
30
+ export declare function looksLikeContextThrashText(value: unknown): boolean;
31
+ export declare function contextThrashRecoveryNotice(): string;
32
+ export declare function buildContextThrashRecoveryPrompt(userRequest: string, priorFailureText?: string): string;
33
+ /** Autonomous jobs use this sentinel to mean "completed, but do not notify the owner." */
34
+ export declare function isAutonomousNothingOutput(response: string): boolean;
30
35
  export interface ProjectMeta {
31
36
  path: string;
32
37
  description?: string;
@@ -251,8 +256,10 @@ export declare class PersonalAssistant {
251
256
  /** Fire-and-forget: extract a reusable skill from a successful execution. */
252
257
  private extractSkillFromExecution;
253
258
  private preRotationFlush;
254
- private lastExtractionTime;
255
- private worthExtracting;
259
+ private lastExtractionTimes;
260
+ private memoryExtractionKey;
261
+ private assessMemoryExtraction;
262
+ private logMemoryExtractionSkip;
256
263
  private spawnMemoryExtraction;
257
264
  private static readonly MEMORY_TOOL_NAMES;
258
265
  private extractMemory;
@@ -35,6 +35,7 @@ import { classifyIntent, getStrategyGuidance } from './intent-classifier.js';
35
35
  import { getEventLog } from './session-event-log.js';
36
36
  import { routeToolSurface, TOOL_SURFACE_WARN_THRESHOLD } from './tool-router.js';
37
37
  import { decideTurnPolicy } from './turn-policy.js';
38
+ import { loadClementineJson } from '../config/clementine-json.js';
38
39
  // ── Channel capabilities ────────────────────────────────────────────
39
40
  /** Map channel label to its capabilities so the agent adapts its responses. */
40
41
  function getChannelCapabilities(channel) {
@@ -172,6 +173,37 @@ export function estimateTokens(text) {
172
173
  return 0;
173
174
  return Math.ceil(text.length / 3.3);
174
175
  }
176
+ export function looksLikeContextThrashText(value) {
177
+ const text = String(value ?? '');
178
+ return /autocompact\s+is\s+thrashing|context\s+refilled\s+to\s+the\s+limit|refilled\s+to\s+the\s+limit\s+within/i.test(text);
179
+ }
180
+ export function contextThrashRecoveryNotice() {
181
+ return [
182
+ 'I hit a context-size recovery issue while working on that.',
183
+ 'I saved the request and reset the session so I can continue with smaller reads instead of repeating the same large-output path.',
184
+ ].join(' ');
185
+ }
186
+ export function buildContextThrashRecoveryPrompt(userRequest, priorFailureText = '') {
187
+ const parts = [
188
+ '[CONTEXT-THRASH RECOVERY]',
189
+ '',
190
+ 'The previous interactive attempt failed because tool output filled the context window and SDK autocompact thrashed. Continue the user request, but use a small diagnostic pass.',
191
+ '',
192
+ 'User request:',
193
+ userRequest,
194
+ '',
195
+ 'Recovery rules:',
196
+ '- Do not repeat broad reads, full log dumps, full JSON dumps, or unbounded API/list commands.',
197
+ '- Prefer status files, summaries, indexes, `rg`, `tail -80`, `head -80`, and `sed -n` slices.',
198
+ '- For cron or unleashed jobs, inspect only `status.json`, the tail of `progress.jsonl`, and the latest run preview first. Do not read full run logs unless a short slice identifies the exact file and range.',
199
+ '- Preserve the user intent. Identify what failed, what you changed or verified, and the next action.',
200
+ '- Finish with `TASK_COMPLETE:` followed by a concise user-facing summary.',
201
+ ];
202
+ if (priorFailureText.trim()) {
203
+ parts.push('', 'Prior failure excerpt:', priorFailureText.trim().slice(0, 1200));
204
+ }
205
+ return parts.join('\n');
206
+ }
175
207
  /**
176
208
  * Strip lone Unicode surrogates (U+D800–U+DFFF) from a string so it can be
177
209
  * safely serialized to JSON. Lone surrogates are valid in JS strings but
@@ -640,6 +672,27 @@ function yesterdayISO() {
640
672
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
641
673
  }
642
674
  // ── Cron Output Extraction ──────────────────────────────────────────
675
+ /** Autonomous jobs use this sentinel to mean "completed, but do not notify the owner." */
676
+ export function isAutonomousNothingOutput(response) {
677
+ const trimmed = response.trim();
678
+ if (!trimmed)
679
+ return false;
680
+ if (trimmed === '__NOTHING__')
681
+ return true;
682
+ if (/^_*NOTHING_*$/i.test(trimmed))
683
+ return true;
684
+ if (/^_*NOTHING_*\s*(\(|$)/im.test(trimmed))
685
+ return true;
686
+ if (/^(_*NOTHING_*\s*)?\[MONITORING\]\s*$/i.test(trimmed))
687
+ return true;
688
+ if (trimmed.length > 80)
689
+ return false;
690
+ const lower = trimmed.toLowerCase();
691
+ return lower === 'nothing to report'
692
+ || lower === 'nothing new to report'
693
+ || lower === 'no updates'
694
+ || lower === 'all clear';
695
+ }
643
696
  /** Return the last non-empty text block that came after the last tool call, or '' if nothing/sentinel. */
644
697
  function extractDeliverable(trace) {
645
698
  if (trace.length === 0)
@@ -657,7 +710,7 @@ function extractDeliverable(trace) {
657
710
  for (let i = trace.length - 1; i > lastToolIdx; i--) {
658
711
  if (trace[i].type === 'text') {
659
712
  const text = trace[i].content.trim();
660
- if (text === '__NOTHING__')
713
+ if (isAutonomousNothingOutput(text))
661
714
  return '';
662
715
  if (text.length > 0)
663
716
  return text;
@@ -1609,6 +1662,54 @@ Never spawn a sub-agent with vague instructions like "handle this brief."
1609
1662
 
1610
1663
  When ${owner} expresses satisfaction ("nice", "perfect", "great job", "thanks") or dissatisfaction ("no", "wrong", "that's not right", "ugh"), call \`feedback_log\` with an appropriate rating ('positive' or 'negative') and a brief comment summarizing the context. This helps me learn from interactions.`);
1611
1664
  }
1665
+ try {
1666
+ const jsonExperience = loadClementineJson(BASE_DIR).assistant ?? {};
1667
+ const pick = (value, allowed) => allowed.includes(value) ? value : undefined;
1668
+ const experience = {
1669
+ proactivity: pick(process.env.ASSISTANT_PROACTIVITY, ['quiet', 'balanced', 'proactive', 'operator']) ?? jsonExperience.proactivity,
1670
+ responseStyle: pick(process.env.ASSISTANT_RESPONSE_STYLE, ['concise', 'balanced', 'detailed']) ?? jsonExperience.responseStyle,
1671
+ progressVisibility: pick(process.env.ASSISTANT_PROGRESS_VISIBILITY, ['quiet', 'normal', 'detailed']) ?? jsonExperience.progressVisibility,
1672
+ autonomy: pick(process.env.ASSISTANT_AUTONOMY, ['ask_first', 'balanced', 'act_when_safe']) ?? jsonExperience.autonomy,
1673
+ };
1674
+ const lines = [];
1675
+ if (experience.proactivity) {
1676
+ const guidance = {
1677
+ quiet: 'Only interrupt for urgent or explicitly requested work. Avoid unsolicited next steps.',
1678
+ balanced: 'Offer useful next steps when natural, but do not create extra work without a clear reason.',
1679
+ proactive: 'Surface likely next actions, risks, and background-work opportunities before the owner has to ask.',
1680
+ operator: 'Operate forward: propose plans, queue safe background work, monitor progress, and keep the owner informed.',
1681
+ };
1682
+ lines.push(`- Proactivity: ${experience.proactivity}. ${guidance[experience.proactivity]}`);
1683
+ }
1684
+ if (experience.responseStyle) {
1685
+ const guidance = {
1686
+ concise: 'Default to short, direct answers. Expand only when the task needs it.',
1687
+ balanced: 'Match detail to task complexity.',
1688
+ detailed: 'Include more reasoning, context, and verification detail for substantive work.',
1689
+ };
1690
+ lines.push(`- Response style: ${experience.responseStyle}. ${guidance[experience.responseStyle]}`);
1691
+ }
1692
+ if (experience.progressVisibility) {
1693
+ const guidance = {
1694
+ quiet: 'Minimize process narration unless work is slow, blocked, or risky.',
1695
+ normal: 'Share important progress and decision points.',
1696
+ detailed: 'Keep the owner posted during background or multi-tool work, including failures and recoveries.',
1697
+ };
1698
+ lines.push(`- Progress visibility: ${experience.progressVisibility}. ${guidance[experience.progressVisibility]}`);
1699
+ }
1700
+ if (experience.autonomy) {
1701
+ const guidance = {
1702
+ ask_first: 'Ask before taking actions that change external systems or user data.',
1703
+ balanced: 'Act on low-risk reversible steps; ask on irreversible, costly, or ambiguous steps.',
1704
+ act_when_safe: 'Use judgment and proceed on safe, reversible, clearly beneficial work.',
1705
+ };
1706
+ lines.push(`- Autonomy: ${experience.autonomy}. ${guidance[experience.autonomy]}`);
1707
+ }
1708
+ if (lines.length > 0) {
1709
+ parts.push(`## Owner Experience Preferences\n\n${lines.join('\n')}`);
1710
+ }
1711
+ }
1712
+ catch { /* config preferences are optional */ }
1612
1713
  // Verbose level overrides
1613
1714
  if (verboseLevel === 'quiet') {
1614
1715
  parts.push(`## Verbosity: Quiet\n\nGive results directly. Skip reasoning and progress updates unless asked.`);
@@ -2667,8 +2768,22 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2667
2768
  }
2668
2769
  // Lone-surrogate sanitization happens at the SDK boundary (see query() wrapper).
2669
2770
  let effectivePrompt = text;
2771
+ const recentExchangesForIntent = key ? this.lastExchanges.get(key) : undefined;
2772
+ const intent = classifyIntent(text, recentExchangesForIntent);
2773
+ const turnPolicy = decideTurnPolicy({
2774
+ text,
2775
+ intent,
2776
+ hasRecentContext: !!(recentExchangesForIntent?.length || (key && this.sessions.has(key))),
2777
+ });
2778
+ const suppressContextInjection = turnPolicy.suppressContextInjection === true;
2779
+ if (key && turnPolicy.suppressSessionResume) {
2780
+ this.sessions.delete(key);
2781
+ this.exchangeCounts.set(key, 0);
2782
+ this.restoredSessions.delete(key);
2783
+ this._compactedSessions.delete(key);
2784
+ }
2670
2785
  // If session rotated, use instant local summary + handoff + kick off LLM summary in background
2671
- if (sessionRotated && key) {
2786
+ if (sessionRotated && key && !suppressContextInjection) {
2672
2787
  const summary = this.buildLocalSummary(key);
2673
2788
  const handoff = this.loadHandoff(key);
2674
2789
  const contextParts = [];
@@ -2687,7 +2802,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2687
2802
  this.summarizeSessionAsync(key).catch(err => logger.debug({ err, key }, 'Session summarization failed'));
2688
2803
  }
2689
2804
  // Resilience: inject exchange history if no session_id stored
2690
- if (key && !this.sessions.has(key) && !sessionRotated) {
2805
+ if (key && !suppressContextInjection && !this.sessions.has(key) && !sessionRotated) {
2691
2806
  const exchanges = this.lastExchanges.get(key) ?? [];
2692
2807
  if (exchanges.length > 0) {
2693
2808
  const historyLines = [];
@@ -2700,7 +2815,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2700
2815
  }
2701
2816
  }
2702
2817
  // Inject context on first message after a daemon restart (session restored from disk)
2703
- if (key && this.restoredSessions.has(key)) {
2818
+ if (key && !suppressContextInjection && this.restoredSessions.has(key)) {
2704
2819
  const exchanges = this.lastExchanges.get(key) ?? [];
2705
2820
  if (exchanges.length > 0) {
2706
2821
  const olderSummary = this.buildOlderTurnsContext(key, exchanges);
@@ -2720,7 +2835,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2720
2835
  this.restoredSessions.delete(key); // Only inject once per restored session
2721
2836
  }
2722
2837
  // Fresh session with no history — inject last conversation context
2723
- if (key && !sessionRotated && !this.restoredSessions.has(key)) {
2838
+ if (key && !suppressContextInjection && !sessionRotated && !this.restoredSessions.has(key)) {
2724
2839
  const exchanges = this.lastExchanges.get(key) ?? [];
2725
2840
  if (exchanges.length === 0 && this.memoryStore) {
2726
2841
  try {
@@ -2741,7 +2856,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2741
2856
  }
2742
2857
  }
2743
2858
  // Time-gap awareness: let the agent know how long it's been
2744
- if (key && this.sessionTimestamps.has(key)) {
2859
+ if (key && !suppressContextInjection && this.sessionTimestamps.has(key)) {
2745
2860
  const gapMs = Date.now() - this.sessionTimestamps.get(key).getTime();
2746
2861
  const gapHours = Math.round(gapMs / 3_600_000);
2747
2862
  if (gapHours >= 8) {
@@ -2753,7 +2868,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2753
2868
  // injectContext uses the base session key (e.g. discord:user:123) but
2754
2869
  // chat may use a profile-suffixed key (discord:user:123:sales-agent),
2755
2870
  // so also check any pending key that the current key starts with.
2756
- if (key) {
2871
+ if (key && !suppressContextInjection) {
2757
2872
  const allPending = [];
2758
2873
  for (const [pendingKey, pending] of this.pendingContext) {
2759
2874
  if (key === pendingKey || key.startsWith(pendingKey + ':')) {
@@ -2771,7 +2886,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2771
2886
  }
2772
2887
  }
2773
2888
  // Inject stall nudge if the previous query for this session showed stall signals
2774
- if (key && this.stallNudges.has(key)) {
2889
+ if (key && !suppressContextInjection && this.stallNudges.has(key)) {
2775
2890
  const nudge = this.stallNudges.get(key);
2776
2891
  this.stallNudges.delete(key);
2777
2892
  effectivePrompt =
@@ -2780,16 +2895,6 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2780
2895
  `Either take the action NOW using your tools, or tell the user exactly what is blocking you. ` +
2781
2896
  `If a file can't be read, say so. If you're stuck, say so. Never stall silently.]\n\n${effectivePrompt}`;
2782
2897
  }
2783
- // ── Intent classification ─────────────────────────────────────
2784
- // Classify intent before the main query to dynamically tune response
2785
- // strategy, maxTurns, and effort level
2786
- const recentExchanges = key ? this.lastExchanges.get(key) : undefined;
2787
- const intent = classifyIntent(text, recentExchanges);
2788
- const turnPolicy = decideTurnPolicy({
2789
- text,
2790
- intent,
2791
- hasRecentContext: !!(recentExchanges?.length || (key && this.sessions.has(key))),
2792
- });
2793
2898
  logger.debug({
2794
2899
  intent: intent.type,
2795
2900
  confidence: intent.confidence,
@@ -2833,7 +2938,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2833
2938
  if (key && !isApiError) {
2834
2939
  this.exchangeCounts.set(key, (this.exchangeCounts.get(key) ?? 0) + 1);
2835
2940
  this.sessionTimestamps.set(key, new Date());
2836
- const history = this.lastExchanges.get(key) ?? [];
2941
+ const history = turnPolicy.suppressContextInjection ? [] : (this.lastExchanges.get(key) ?? []);
2837
2942
  history.push({ user: text, assistant: responseText });
2838
2943
  if (history.length > SESSION_EXCHANGE_HISTORY_SIZE) {
2839
2944
  this.lastExchanges.set(key, history.slice(-SESSION_EXCHANGE_HISTORY_SIZE));
@@ -2872,12 +2977,16 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
2872
2977
  logger.warn({ err, sessionKey: key }, 'Transcript save failed');
2873
2978
  }
2874
2979
  }
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'));
2980
+ // Fire background memory extraction (non-blocking). Skips are logged with
2981
+ // structured reasons so memory gaps are diagnosable without reading chats.
2982
+ if (responseText && !responseText.startsWith('Error:')) {
2983
+ const extractionDecision = this.assessMemoryExtraction(text, responseText, key, profile);
2984
+ if (extractionDecision.ok) {
2985
+ this.spawnMemoryExtraction(text, responseText, key, profile).catch(err => logger.debug({ err }, 'Memory extraction failed'));
2986
+ }
2987
+ else {
2988
+ this.logMemoryExtractionSkip(extractionDecision.reason, text, responseText, key, profile);
2989
+ }
2881
2990
  }
2882
2991
  // Score outcome-driven salience: for the chunks we retrieved this turn,
2883
2992
  // check which actually showed up in the response and adjust their
@@ -3030,7 +3139,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
3030
3139
  sdkOptions.cwd = matchedProject.path;
3031
3140
  }
3032
3141
  // Set resume session if available
3033
- if (sessionKey && this.sessions.has(sessionKey)) {
3142
+ if (sessionKey && this.sessions.has(sessionKey) && !effectiveTurnPolicy?.suppressSessionResume) {
3034
3143
  sdkOptions.resume = this.sessions.get(sessionKey);
3035
3144
  }
3036
3145
  // Context window guard: estimate token usage and bail if too tight.
@@ -3253,7 +3362,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
3253
3362
  // Auth errors — throw so the gateway circuit breaker catches it
3254
3363
  throw new Error(errorText);
3255
3364
  }
3256
- else if (lower.includes('autocompact') || lower.includes('thrash') || lower.includes('context refilled to the limit')) {
3365
+ else if (looksLikeContextThrashText(errorText)) {
3257
3366
  // Autocompact thrashing — treat like the exception path
3258
3367
  logger.warn({ sessionKey }, 'Autocompact thrashing (result error) — will rotate session');
3259
3368
  // Capture mid-task state BEFORE rotating, so the retry
@@ -3293,6 +3402,25 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
3293
3402
  else if ('result' in result && result.result) {
3294
3403
  // Success: use SDK result text if streaming didn't capture a substantive response
3295
3404
  const sdkResult = result.result;
3405
+ if (looksLikeContextThrashText(sdkResult)) {
3406
+ logger.warn({ sessionKey }, 'Autocompact thrashing surfaced as SDK result text — rotating session');
3407
+ preRotationSnapshot = {
3408
+ toolCalls: stallGuard?.getToolCalls() ?? [],
3409
+ partialText: responseText.slice(-1000),
3410
+ };
3411
+ if (sessionKey) {
3412
+ try {
3413
+ this.compactContext(sessionKey);
3414
+ }
3415
+ catch { /* best-effort */ }
3416
+ this.sessions.delete(sessionKey);
3417
+ this.exchangeCounts.set(sessionKey, 0);
3418
+ this._compactedSessions.delete(sessionKey);
3419
+ }
3420
+ staleSession = true;
3421
+ contextRecovery = true;
3422
+ break;
3423
+ }
3296
3424
  logger.info({ sessionKey, streamedLen: responseText.length, resultLen: sdkResult.length }, 'SDK result text available');
3297
3425
  if (!responseText.trim()) {
3298
3426
  responseText = sdkResult;
@@ -3354,7 +3482,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
3354
3482
  }
3355
3483
  }
3356
3484
  }
3357
- else if (errStr.includes('autocompact') || errStr.includes('thrash') || errStr.includes('context refilled to the limit')) {
3485
+ else if (looksLikeContextThrashText(e)) {
3358
3486
  // SDK autocompact thrashing — tool outputs are too large for the context window.
3359
3487
  // Rotate session and retry with a fresh context so the agent can continue.
3360
3488
  logger.warn({ sessionKey }, 'Autocompact thrashing — rotating session and retrying');
@@ -3379,7 +3507,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
3379
3507
  responseText = '';
3380
3508
  continue;
3381
3509
  }
3382
- responseText = responseText || 'The conversation context filled up from large tool outputs. I\'ve reset the session — please try again, and I\'ll keep query results smaller this time.';
3510
+ responseText = responseText || contextThrashRecoveryNotice();
3383
3511
  }
3384
3512
  else if (errStr.includes('prompt is too long') || errStr.includes('prompt too long') || errStr.includes('context_length')) {
3385
3513
  responseText = responseText || ('The conversation got too large to process (tool responses filled the context window). ' +
@@ -3432,6 +3560,9 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
3432
3560
  }
3433
3561
  continue;
3434
3562
  }
3563
+ if (staleSession && contextRecovery && !responseText.trim()) {
3564
+ responseText = contextThrashRecoveryNotice();
3565
+ }
3435
3566
  if (hitRateLimit && attempt < PersonalAssistant.RATE_LIMIT_MAX_RETRIES) {
3436
3567
  const base = rateLimitRetryAfterMs
3437
3568
  ?? PersonalAssistant.RATE_LIMIT_BACKOFF[Math.min(attempt, PersonalAssistant.RATE_LIMIT_BACKOFF.length - 1)];
@@ -3446,6 +3577,27 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
3446
3577
  if (hitRateLimit && !responseText) {
3447
3578
  responseText = "I'm being rate limited right now. Give me a minute and try again.";
3448
3579
  }
3580
+ if (looksLikeContextThrashText(responseText)) {
3581
+ logger.warn({ sessionKey }, 'Autocompact thrashing escaped into response text — rotating session before reply');
3582
+ if (sessionKey) {
3583
+ try {
3584
+ this.compactContext(sessionKey);
3585
+ }
3586
+ catch { /* best-effort */ }
3587
+ this.sessions.delete(sessionKey);
3588
+ this.exchangeCounts.set(sessionKey, 0);
3589
+ this._compactedSessions.delete(sessionKey);
3590
+ }
3591
+ if (attempt < PersonalAssistant.RATE_LIMIT_MAX_RETRIES) {
3592
+ prompt = buildContextRecoveredPrompt(prompt, {
3593
+ toolCalls: stallGuard?.getToolCalls() ?? [],
3594
+ partialText: '',
3595
+ });
3596
+ responseText = '';
3597
+ continue;
3598
+ }
3599
+ responseText = contextThrashRecoveryNotice();
3600
+ }
3449
3601
  // ── Response guarantee ─────────────────────────────────────────
3450
3602
  // The model often generates 30+ tool calls with minimal/no text. Ensure
3451
3603
  // the user always gets a substantive response after real work is done.
@@ -4188,14 +4340,15 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
4188
4340
  catch { /* non-fatal */ }
4189
4341
  }
4190
4342
  // ── 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
4343
+ lastExtractionTimes = new Map();
4344
+ memoryExtractionKey(sessionKey, profile) {
4345
+ return `${profile?.slug ?? 'global'}:${sessionKey ?? 'no-session'}`;
4346
+ }
4347
+ assessMemoryExtraction(prompt, response, sessionKey, profile) {
4348
+ if (!this.memoryStore)
4349
+ return { ok: false, reason: 'no_memory_store' };
4350
+ // Only skip pure greetings with no substance at all. Check this before
4351
+ // length so "hey" is diagnosable as intent, not generic shortness.
4199
4352
  const pureGreetings = [
4200
4353
  'hello', 'hi', 'hey', 'thanks', 'thank you',
4201
4354
  'ok', 'okay', 'sure', 'got it', 'sounds good',
@@ -4203,20 +4356,54 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
4203
4356
  ];
4204
4357
  const lower = prompt.toLowerCase().trim();
4205
4358
  if (pureGreetings.some((g) => lower === g || lower === g + '!' || lower === g + '.')) {
4206
- return false;
4359
+ return { ok: false, reason: 'pure_greeting' };
4360
+ }
4361
+ if (prompt.length < AUTO_MEMORY_MIN_LENGTH || response.length < 100) {
4362
+ return { ok: false, reason: 'too_short' };
4207
4363
  }
4208
- // Rate limit: max 1 extraction per 45 seconds per session
4364
+ // Rate limit per session/agent. The old process-wide throttle meant one
4365
+ // active chat could suppress memory extraction for unrelated agents.
4209
4366
  const now = Date.now();
4210
- if (now - this.lastExtractionTime < 45_000)
4211
- return false;
4212
- this.lastExtractionTime = now;
4213
- return true;
4367
+ const key = this.memoryExtractionKey(sessionKey, profile);
4368
+ const last = this.lastExtractionTimes.get(key) ?? 0;
4369
+ if (now - last < 45_000)
4370
+ return { ok: false, reason: 'rate_limited' };
4371
+ this.lastExtractionTimes.set(key, now);
4372
+ return { ok: true };
4373
+ }
4374
+ logMemoryExtractionSkip(reason, userMessage, assistantResponse, sessionKey, profile) {
4375
+ logger.debug({
4376
+ reason,
4377
+ sessionKey,
4378
+ agentSlug: profile?.slug,
4379
+ promptChars: userMessage.length,
4380
+ responseChars: assistantResponse.length,
4381
+ }, 'Auto-memory extraction skipped');
4382
+ if (!this.memoryStore)
4383
+ return;
4384
+ try {
4385
+ this.memoryStore.logExtraction({
4386
+ sessionKey: sessionKey ?? 'unknown',
4387
+ userMessage: userMessage.slice(0, 500),
4388
+ toolName: 'auto_memory_skip',
4389
+ toolInput: JSON.stringify({
4390
+ reason,
4391
+ promptChars: userMessage.length,
4392
+ responseChars: assistantResponse.length,
4393
+ }),
4394
+ extractedAt: new Date().toISOString(),
4395
+ status: `skipped:${reason}`,
4396
+ agentSlug: profile?.slug,
4397
+ });
4398
+ }
4399
+ catch { /* telemetry only */ }
4214
4400
  }
4215
4401
  async spawnMemoryExtraction(userMessage, assistantResponse, sessionKey, profile) {
4216
4402
  // Guard: skip memory extraction if the user message looks like injection
4217
4403
  const memScan = scanner.scan(userMessage);
4218
4404
  if (memScan.verdict === 'block') {
4219
4405
  logger.info('Skipping memory extraction — message was flagged as injection');
4406
+ this.logMemoryExtractionSkip('injection_blocked', userMessage, assistantResponse, sessionKey, profile);
4220
4407
  return;
4221
4408
  }
4222
4409
  let currentMemory = '';
@@ -4855,7 +5042,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
4855
5042
  if (cronGuard) {
4856
5043
  const summary = cronGuard.getSummary();
4857
5044
  const mc = summary.metacognition;
4858
- if (mc.confidenceFinal === 'low' && deliverable && deliverable !== '__NOTHING__') {
5045
+ if (mc.confidenceFinal === 'low' && deliverable && !isAutonomousNothingOutput(deliverable)) {
4859
5046
  try {
4860
5047
  const escalationsFile = path.join(BASE_DIR, 'escalations.json');
4861
5048
  const escalations = fs.existsSync(escalationsFile)
@@ -5386,6 +5573,21 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
5386
5573
  lastPhaseOutputPreview: lastOutput.slice(0, 300),
5387
5574
  });
5388
5575
  logger.info(`Unleashed task ${jobName}: phase ${phase} complete (${(phaseDurationMs / 1000).toFixed(0)}s)`);
5576
+ // The job explicitly says there is nothing to report. Treat that as a
5577
+ // clean terminal state instead of resuming the same no-op phase until
5578
+ // the max-phase guard fires.
5579
+ if (isAutonomousNothingOutput(lastOutput)) {
5580
+ appendProgress({ event: 'completed_silent', phase });
5581
+ writeStatus({ jobName, status: 'completed', phase, startedAt, finishedAt: new Date().toISOString(), silent: true });
5582
+ logger.info(`Unleashed task ${jobName} completed silently at phase ${phase}`);
5583
+ if (this.onUnleashedComplete) {
5584
+ try {
5585
+ this.onUnleashedComplete(jobName, '__NOTHING__');
5586
+ }
5587
+ catch { /* non-fatal */ }
5588
+ }
5589
+ return '__NOTHING__';
5590
+ }
5389
5591
  // Notify phase progress callback
5390
5592
  if (this.onPhaseComplete) {
5391
5593
  try {
@@ -0,0 +1,32 @@
1
+ import type { ClementineJson } from '../config/clementine-json.js';
2
+ export type ProactivityMode = 'quiet' | 'balanced' | 'proactive' | 'operator';
3
+ export type ResponseStyle = 'concise' | 'balanced' | 'detailed';
4
+ export type ProgressVisibility = 'quiet' | 'normal' | 'detailed';
5
+ export type AutonomyMode = 'ask_first' | 'balanced' | 'act_when_safe';
6
+ export interface AssistantExperienceUpdate {
7
+ proactivity?: ProactivityMode;
8
+ responseStyle?: ResponseStyle;
9
+ progressVisibility?: ProgressVisibility;
10
+ autonomy?: AutonomyMode;
11
+ }
12
+ export type LocalTurnIntent = {
13
+ kind: 'none';
14
+ } | {
15
+ kind: 'ack';
16
+ } | {
17
+ kind: 'greeting';
18
+ } | {
19
+ kind: 'stop';
20
+ } | {
21
+ kind: 'status';
22
+ } | {
23
+ kind: 'preference_update';
24
+ updates: AssistantExperienceUpdate;
25
+ summary: string;
26
+ };
27
+ export declare function isStopRequest(text: string): boolean;
28
+ export declare function isStatusRequest(text: string): boolean;
29
+ export declare function isTinyAcknowledgment(text: string): boolean;
30
+ export declare function detectLocalTurn(text: string): LocalTurnIntent;
31
+ export declare function applyAssistantExperienceUpdate(cfg: ClementineJson, updates: AssistantExperienceUpdate): ClementineJson;
32
+ //# sourceMappingURL=local-turn.d.ts.map
@@ -0,0 +1,107 @@
1
+ import { isStandaloneGreeting } from './turn-policy.js';
2
+ function normalize(text) {
3
+ return text
4
+ .trim()
5
+ .toLowerCase()
6
+ .replace(/[.!?]+$/g, '')
7
+ .replace(/\s+/g, ' ');
8
+ }
9
+ function wordCount(text) {
10
+ const t = text.trim();
11
+ return t ? t.split(/\s+/).length : 0;
12
+ }
13
+ export function isStopRequest(text) {
14
+ const n = normalize(text);
15
+ if (wordCount(n) > 5)
16
+ return false;
17
+ return /^(stop|cancel|abort|halt|pause|nevermind|never mind|wait stop|stop please|cancel that|stop that)$/.test(n);
18
+ }
19
+ export function isStatusRequest(text) {
20
+ const n = normalize(text);
21
+ if (wordCount(n) > 8)
22
+ return false;
23
+ return /^(status|task status|deep status|progress|what'?s happening|what'?s going on|what are you doing|are you working|anything running|what'?s running|background status|check status|where are we)$/.test(n);
24
+ }
25
+ export function isTinyAcknowledgment(text) {
26
+ const n = normalize(text);
27
+ if (wordCount(n) > 4)
28
+ return false;
29
+ return /^(thanks|thank you|thx|ty|nice|great|perfect|awesome|cool|ok|okay|sounds good|got it|makes sense|love it)$/.test(n);
30
+ }
31
+ function parseProactivity(text) {
32
+ if (/\b(operator mode|operator)\b/i.test(text))
33
+ return 'operator';
34
+ if (/\b(more proactive|be proactive|proactive mode|set proactivity to proactive)\b/i.test(text))
35
+ return 'proactive';
36
+ if (/\b(less proactive|quieter|quiet mode|be quiet|only urgent|do not interrupt)\b/i.test(text))
37
+ return 'quiet';
38
+ if (/\b(balanced proactivity|balanced mode|normal proactivity)\b/i.test(text))
39
+ return 'balanced';
40
+ return undefined;
41
+ }
42
+ function parseResponseStyle(text) {
43
+ if (/\b(be concise|keep it concise|shorter replies|brief replies|reply briefly|less verbose)\b/i.test(text))
44
+ return 'concise';
45
+ if (/\b(more detail|detailed replies|be detailed|explain more|more verbose)\b/i.test(text))
46
+ return 'detailed';
47
+ if (/\b(balanced replies|normal replies|balanced detail)\b/i.test(text))
48
+ return 'balanced';
49
+ return undefined;
50
+ }
51
+ function parseProgressVisibility(text) {
52
+ if (/\b(show more progress|keep me posted|more updates|detailed progress|tell me what'?s happening)\b/i.test(text))
53
+ return 'detailed';
54
+ if (/\b(less progress|fewer updates|quiet progress|don'?t narrate)\b/i.test(text))
55
+ return 'quiet';
56
+ if (/\b(normal progress|balanced progress)\b/i.test(text))
57
+ return 'normal';
58
+ return undefined;
59
+ }
60
+ function parseAutonomy(text) {
61
+ if (/\b(ask first|ask me first|ask before acting|do not act without asking)\b/i.test(text))
62
+ return 'ask_first';
63
+ if (/\b(act when safe|more autonomous|use your judgment|handle it when safe)\b/i.test(text))
64
+ return 'act_when_safe';
65
+ if (/\b(balanced autonomy|normal autonomy)\b/i.test(text))
66
+ return 'balanced';
67
+ return undefined;
68
+ }
69
+ export function detectLocalTurn(text) {
70
+ if (isStopRequest(text))
71
+ return { kind: 'stop' };
72
+ if (isStatusRequest(text))
73
+ return { kind: 'status' };
74
+ if (isStandaloneGreeting(text))
75
+ return { kind: 'greeting' };
76
+ if (isTinyAcknowledgment(text))
77
+ return { kind: 'ack' };
78
+ const updates = {};
79
+ const proactivity = parseProactivity(text);
80
+ const responseStyle = parseResponseStyle(text);
81
+ const progressVisibility = parseProgressVisibility(text);
82
+ const autonomy = parseAutonomy(text);
83
+ if (proactivity)
84
+ updates.proactivity = proactivity;
85
+ if (responseStyle)
86
+ updates.responseStyle = responseStyle;
87
+ if (progressVisibility)
88
+ updates.progressVisibility = progressVisibility;
89
+ if (autonomy)
90
+ updates.autonomy = autonomy;
91
+ const entries = Object.entries(updates);
92
+ if (entries.length === 0)
93
+ return { kind: 'none' };
94
+ const summary = entries.map(([k, v]) => `${k}: ${v}`).join(', ');
95
+ return { kind: 'preference_update', updates, summary };
96
+ }
97
+ export function applyAssistantExperienceUpdate(cfg, updates) {
98
+ return {
99
+ ...cfg,
100
+ schemaVersion: 1,
101
+ assistant: {
102
+ ...(cfg.assistant ?? {}),
103
+ ...updates,
104
+ },
105
+ };
106
+ }
107
+ //# sourceMappingURL=local-turn.js.map
@@ -76,6 +76,7 @@ const PATTERNS = [
76
76
  recipe: () => ({
77
77
  category: 'safe-cron-config',
78
78
  description: 'Context window blowing up mid-run. Switching to unleashed mode so each phase starts with a fresh context.',
79
+ fields: ['mode', 'max_hours'],
79
80
  apply: (job) => {
80
81
  let changed = false;
81
82
  if (job.mode !== 'unleashed') {