@vellumai/assistant 0.8.0 → 0.8.1

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 (692) hide show
  1. package/AGENTS.md +11 -0
  2. package/Dockerfile +5 -4
  3. package/README.md +2 -2
  4. package/docker-entrypoint.sh +16 -0
  5. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  6. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  7. package/eslint.config.mjs +12 -0
  8. package/knip.json +2 -1
  9. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  10. package/openapi.yaml +4847 -1698
  11. package/package.json +3 -1
  12. package/scripts/generate-openapi.ts +52 -4
  13. package/scripts/sync-llm-catalog.ts +165 -0
  14. package/scripts/sync-web-search-catalog.ts +107 -0
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  16. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  17. package/src/__tests__/anthropic-provider.test.ts +92 -2
  18. package/src/__tests__/app-control-flow.test.ts +7 -0
  19. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  20. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  22. package/src/__tests__/btw-routes.test.ts +1 -0
  23. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  25. package/src/__tests__/channel-policy.test.ts +12 -0
  26. package/src/__tests__/checker.test.ts +89 -0
  27. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  28. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  29. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  30. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  31. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  32. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  33. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  34. package/src/__tests__/config-schema.test.ts +14 -3
  35. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  36. package/src/__tests__/config-set-route.test.ts +198 -0
  37. package/src/__tests__/config-watcher.test.ts +6 -0
  38. package/src/__tests__/contacts-tools.test.ts +51 -199
  39. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  40. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  41. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  42. package/src/__tests__/context-search-fanout.test.ts +20 -157
  43. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  44. package/src/__tests__/context-search-types.test.ts +7 -2
  45. package/src/__tests__/context-window-manager.test.ts +389 -1
  46. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  47. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  48. package/src/__tests__/conversation-error.test.ts +38 -0
  49. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  50. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  51. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  52. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  54. package/src/__tests__/conversation-process-callsite.test.ts +21 -1
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
  56. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  57. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  58. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  59. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  60. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  61. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  62. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  63. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  64. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  65. package/src/__tests__/filing-service.test.ts +23 -3
  66. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  67. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  68. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  69. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
  70. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  71. package/src/__tests__/heartbeat-service.test.ts +50 -233
  72. package/src/__tests__/history-repair.test.ts +89 -0
  73. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  74. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  75. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  76. package/src/__tests__/host-browser-routes.test.ts +325 -33
  77. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  78. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  79. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  80. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  81. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  82. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  83. package/src/__tests__/install-skill-routing.test.ts +2 -2
  84. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
  85. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  86. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  87. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  88. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  89. package/src/__tests__/llm-resolver.test.ts +46 -0
  90. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  91. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  92. package/src/__tests__/mcp-cli.test.ts +182 -220
  93. package/src/__tests__/mcp-health-check.test.ts +56 -27
  94. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  95. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  96. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  97. package/src/__tests__/oauth-cli.test.ts +38 -2009
  98. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  99. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  100. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  102. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  103. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  104. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  105. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  106. package/src/__tests__/plugin-types.test.ts +13 -11
  107. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  108. package/src/__tests__/profile-entry-status.test.ts +43 -0
  109. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  110. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  111. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  112. package/src/__tests__/relay-server.test.ts +118 -0
  113. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  114. package/src/__tests__/schedule-retry.test.ts +56 -4
  115. package/src/__tests__/schedule-routes.test.ts +104 -0
  116. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  117. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  118. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  119. package/src/__tests__/scheduler-wake.test.ts +0 -63
  120. package/src/__tests__/secret-allowlist.test.ts +1 -0
  121. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  122. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  123. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  124. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  125. package/src/__tests__/skill-load-tool.test.ts +2 -4
  126. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  127. package/src/__tests__/suggestion-routes.test.ts +3 -3
  128. package/src/__tests__/sync-message-contract.test.ts +63 -0
  129. package/src/__tests__/task-scheduler.test.ts +88 -23
  130. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  131. package/src/__tests__/usage-cli.test.ts +11 -73
  132. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  133. package/src/__tests__/vercel-config.test.ts +168 -0
  134. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  135. package/src/__tests__/web-search.test.ts +303 -2
  136. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  137. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  138. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  139. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  140. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  141. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  142. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  143. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  144. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  145. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  146. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  147. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  148. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  149. package/src/acp/resolve-agent.test.ts +25 -0
  150. package/src/acp/resolve-agent.ts +13 -2
  151. package/src/acp/session-manager.ts +14 -0
  152. package/src/approvals/guardian-request-resolvers.ts +32 -87
  153. package/src/calls/relay-server.ts +35 -0
  154. package/src/calls/relay-setup-router.ts +36 -0
  155. package/src/calls/types.ts +1 -0
  156. package/src/calls/voice-session-bridge.ts +23 -4
  157. package/src/channels/config.ts +14 -1
  158. package/src/channels/types.ts +1 -0
  159. package/src/cli/AGENTS.md +164 -4
  160. package/src/cli/__tests__/notifications.test.ts +54 -0
  161. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  162. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  163. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  164. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  165. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  166. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  167. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  168. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  169. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  170. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  171. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  172. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  173. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  174. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  175. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  176. package/src/cli/commands/__tests__/status.test.ts +249 -0
  177. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  178. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  179. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  180. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  181. package/src/cli/commands/attachment.ts +8 -3
  182. package/src/cli/commands/audit.ts +95 -64
  183. package/src/cli/commands/auth.ts +61 -58
  184. package/src/cli/commands/avatar.ts +276 -390
  185. package/src/cli/commands/backup.ts +409 -505
  186. package/src/cli/commands/bash.ts +9 -5
  187. package/src/cli/commands/browser.ts +28 -9
  188. package/src/cli/commands/cache.ts +9 -4
  189. package/src/cli/commands/changelog.ts +414 -0
  190. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  191. package/src/cli/commands/clients.ts +8 -3
  192. package/src/cli/commands/completions.ts +9 -9
  193. package/src/cli/commands/config.ts +102 -72
  194. package/src/cli/commands/contacts.ts +575 -696
  195. package/src/cli/commands/conversations-defer.ts +17 -69
  196. package/src/cli/commands/conversations-import.ts +90 -253
  197. package/src/cli/commands/conversations.ts +346 -436
  198. package/src/cli/commands/credential-execution.ts +9 -6
  199. package/src/cli/commands/credentials.ts +456 -736
  200. package/src/cli/commands/domain.ts +128 -206
  201. package/src/cli/commands/email.ts +606 -794
  202. package/src/cli/commands/gateway.ts +8 -1
  203. package/src/cli/commands/image-generation.ts +157 -205
  204. package/src/cli/commands/inference-providers.ts +352 -0
  205. package/src/cli/commands/inference-session.ts +415 -0
  206. package/src/cli/commands/inference.ts +87 -65
  207. package/src/cli/commands/keys.ts +8 -3
  208. package/src/cli/commands/mcp.ts +103 -287
  209. package/src/cli/commands/memory-v2.ts +162 -516
  210. package/src/cli/commands/notifications.ts +33 -7
  211. package/src/cli/commands/oauth/apps.ts +292 -261
  212. package/src/cli/commands/oauth/connect.ts +176 -297
  213. package/src/cli/commands/oauth/disconnect.ts +16 -215
  214. package/src/cli/commands/oauth/index.ts +49 -45
  215. package/src/cli/commands/oauth/mode.ts +43 -199
  216. package/src/cli/commands/oauth/ping.ts +17 -125
  217. package/src/cli/commands/oauth/providers.ts +732 -921
  218. package/src/cli/commands/oauth/request.ts +60 -350
  219. package/src/cli/commands/oauth/shared.ts +11 -121
  220. package/src/cli/commands/oauth/status.ts +31 -121
  221. package/src/cli/commands/oauth/token.ts +13 -55
  222. package/src/cli/commands/pending.ts +19 -10
  223. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  224. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  225. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  226. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  227. package/src/cli/commands/platform/connect.ts +16 -80
  228. package/src/cli/commands/platform/disconnect.ts +14 -112
  229. package/src/cli/commands/platform/index.ts +177 -246
  230. package/src/cli/commands/routes.ts +153 -336
  231. package/src/cli/commands/sequence.ts +316 -360
  232. package/src/cli/commands/skills.ts +449 -671
  233. package/src/cli/commands/status.ts +58 -37
  234. package/src/cli/commands/stt.ts +94 -262
  235. package/src/cli/commands/task.ts +14 -40
  236. package/src/cli/commands/trust.ts +8 -3
  237. package/src/cli/commands/tts.ts +162 -167
  238. package/src/cli/commands/ui.ts +35 -42
  239. package/src/cli/commands/usage.ts +188 -126
  240. package/src/cli/commands/watchers.ts +8 -3
  241. package/src/cli/commands/webhooks.ts +99 -193
  242. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  243. package/src/cli/lib/daemon-credential-client.ts +4 -5
  244. package/src/cli/lib/nested-value.ts +44 -0
  245. package/src/cli/lib/open-browser.ts +36 -0
  246. package/src/cli/lib/register-command.ts +19 -0
  247. package/src/cli/lib/time-ago.ts +34 -0
  248. package/src/cli/program.ts +2 -4
  249. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  250. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  251. package/src/cli/utils/conversation-id.ts +30 -0
  252. package/src/cli/utils/parse-duration.ts +41 -0
  253. package/src/config/acp-defaults.test.ts +5 -1
  254. package/src/config/acp-defaults.ts +11 -4
  255. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  256. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  258. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  259. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  260. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  261. package/src/config/bundled-tool-registry.ts +0 -2
  262. package/src/config/feature-flag-registry.json +16 -0
  263. package/src/config/llm-resolver.ts +16 -1
  264. package/src/config/loader.ts +76 -14
  265. package/src/config/raw-config-utils.ts +2 -30
  266. package/src/config/schema.ts +4 -0
  267. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  268. package/src/config/schemas/call-site-catalog.ts +29 -7
  269. package/src/config/schemas/llm-request-logs.ts +57 -0
  270. package/src/config/schemas/llm.ts +52 -2
  271. package/src/config/schemas/memory-retrospective.ts +48 -0
  272. package/src/config/schemas/memory-v2.ts +32 -1
  273. package/src/config/schemas/memory.ts +4 -0
  274. package/src/config/schemas/services.ts +15 -12
  275. package/src/config/seed-inference-profiles.ts +195 -134
  276. package/src/contacts/contact-store.ts +0 -61
  277. package/src/context/window-manager.ts +191 -5
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
  279. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  280. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  281. package/src/daemon/approval-generators.ts +23 -29
  282. package/src/daemon/config-watcher.ts +2 -0
  283. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  284. package/src/daemon/conversation-agent-loop.ts +127 -97
  285. package/src/daemon/conversation-error.ts +21 -0
  286. package/src/daemon/conversation-lifecycle.ts +46 -5
  287. package/src/daemon/conversation-process.ts +36 -19
  288. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  289. package/src/daemon/conversation-slash.ts +175 -23
  290. package/src/daemon/conversation-store.ts +17 -10
  291. package/src/daemon/conversation-surfaces.ts +76 -12
  292. package/src/daemon/conversation-tool-setup.ts +24 -14
  293. package/src/daemon/conversation.ts +48 -9
  294. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  295. package/src/daemon/guardian-action-generators.ts +7 -22
  296. package/src/daemon/handlers/config-model.ts +8 -126
  297. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  298. package/src/daemon/handlers/config-vercel.ts +3 -1
  299. package/src/daemon/handlers/skills.ts +84 -5
  300. package/src/daemon/history-repair.ts +33 -6
  301. package/src/daemon/host-app-control-proxy.ts +44 -19
  302. package/src/daemon/host-bash-proxy.ts +85 -158
  303. package/src/daemon/host-browser-proxy.ts +96 -35
  304. package/src/daemon/host-proxy-base.ts +13 -1
  305. package/src/daemon/host-proxy-preactivation.ts +25 -1
  306. package/src/daemon/identity-helpers.ts +19 -0
  307. package/src/daemon/lifecycle.ts +42 -43
  308. package/src/daemon/meet-host-supervisor.ts +15 -15
  309. package/src/daemon/memory-v2-startup.ts +9 -2
  310. package/src/daemon/message-protocol.ts +6 -0
  311. package/src/daemon/message-types/bookmarks.ts +18 -0
  312. package/src/daemon/message-types/conversations.ts +12 -9
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/sync.ts +60 -0
  315. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  316. package/src/daemon/pkb-reminder-builder.ts +21 -7
  317. package/src/daemon/process-message.ts +56 -23
  318. package/src/daemon/server.ts +23 -18
  319. package/src/daemon/shutdown-handlers.ts +0 -2
  320. package/src/daemon/tool-setup-types.ts +9 -0
  321. package/src/daemon/tool-side-effects.ts +6 -4
  322. package/src/daemon/wake-target-adapter.ts +11 -0
  323. package/src/export/transcript-formatter.ts +61 -2
  324. package/src/filing/filing-service.ts +40 -53
  325. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  326. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  327. package/src/heartbeat/heartbeat-service.ts +148 -127
  328. package/src/home/__tests__/feed-types.test.ts +63 -131
  329. package/src/home/__tests__/feed-writer.test.ts +77 -278
  330. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  331. package/src/home/feed-types.ts +19 -73
  332. package/src/home/feed-writer.ts +25 -156
  333. package/src/home/post-connect-feed.ts +1 -3
  334. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  335. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  336. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  337. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  338. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  339. package/src/ipc/assistant-server.ts +55 -6
  340. package/src/ipc/cli-client.ts +370 -50
  341. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  342. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  343. package/src/ipc/skill-routes/events.ts +30 -3
  344. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  345. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  346. package/src/live-voice/live-voice-session-manager.ts +11 -4
  347. package/src/live-voice/live-voice-session.ts +14 -6
  348. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  349. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  350. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  351. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  352. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  353. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  354. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  355. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  356. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  357. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  358. package/src/memory/bookmark-crud.ts +179 -0
  359. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  360. package/src/memory/context-search/agent-protocol.ts +5 -1
  361. package/src/memory/context-search/agent-runner.ts +60 -85
  362. package/src/memory/context-search/limits.ts +1 -4
  363. package/src/memory/context-search/search.ts +23 -113
  364. package/src/memory/context-search/sources/conversations.ts +18 -6
  365. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  366. package/src/memory/context-search/sources/memory.ts +7 -0
  367. package/src/memory/context-search/sources/workspace.ts +13 -10
  368. package/src/memory/context-search/types.ts +1 -1
  369. package/src/memory/conversation-bootstrap.ts +11 -0
  370. package/src/memory/conversation-crud.ts +312 -10
  371. package/src/memory/conversation-queries.ts +9 -5
  372. package/src/memory/conversation-title-service.ts +1 -0
  373. package/src/memory/conversation-types.ts +16 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +2 -1
  376. package/src/memory/embedding-runtime-manager.ts +1 -2
  377. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  378. package/src/memory/graph/conversation-graph-memory.ts +76 -5
  379. package/src/memory/graph/extraction.ts +4 -0
  380. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  381. package/src/memory/graph/tool-handlers.ts +17 -7
  382. package/src/memory/graph/tools.ts +44 -5
  383. package/src/memory/indexer.ts +17 -0
  384. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
  385. package/src/memory/jobs/embed-concept-page.ts +45 -9
  386. package/src/memory/jobs-store.ts +51 -1
  387. package/src/memory/jobs-worker.ts +52 -3
  388. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  389. package/src/memory/llm-request-log-source-local.ts +26 -0
  390. package/src/memory/llm-request-log-source.ts +97 -0
  391. package/src/memory/llm-request-log-store.ts +1 -1
  392. package/src/memory/memory-retrospective-constants.ts +13 -0
  393. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  394. package/src/memory/memory-retrospective-job.ts +351 -0
  395. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  396. package/src/memory/memory-retrospective-state.ts +162 -0
  397. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  398. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  399. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  400. package/src/memory/message-content.ts +38 -1
  401. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  402. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  403. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  404. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  405. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  406. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  407. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  408. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  409. package/src/memory/migrations/243-provider-connections.ts +68 -0
  410. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  411. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  412. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  413. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  414. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  415. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  416. package/src/memory/migrations/index.ts +7 -0
  417. package/src/memory/published-pages-store.ts +16 -0
  418. package/src/memory/schema/bookmarks.ts +38 -0
  419. package/src/memory/schema/conversations.ts +2 -0
  420. package/src/memory/schema/index.ts +2 -0
  421. package/src/memory/schema/inference.ts +29 -0
  422. package/src/memory/schema/memory-core.ts +9 -0
  423. package/src/memory/search/semantic.ts +1 -4
  424. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  425. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  426. package/src/memory/v2/__tests__/activation.test.ts +11 -4
  427. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  428. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  429. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  430. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  431. package/src/memory/v2/__tests__/injection.test.ts +628 -10
  432. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  433. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  434. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  435. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  436. package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
  437. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  438. package/src/memory/v2/__tests__/router.test.ts +516 -0
  439. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  440. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  441. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  442. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  443. package/src/memory/v2/activation-store.ts +34 -5
  444. package/src/memory/v2/activation.ts +40 -27
  445. package/src/memory/v2/backfill-jobs.ts +17 -84
  446. package/src/memory/v2/consolidation-job.ts +85 -78
  447. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  448. package/src/memory/v2/injection.ts +440 -109
  449. package/src/memory/v2/migration.ts +117 -20
  450. package/src/memory/v2/page-index.ts +191 -0
  451. package/src/memory/v2/page-store.ts +3 -0
  452. package/src/memory/v2/prompts/consolidation.ts +9 -7
  453. package/src/memory/v2/prompts/router.ts +192 -0
  454. package/src/memory/v2/qdrant.ts +100 -87
  455. package/src/memory/v2/reranker.ts +14 -7
  456. package/src/memory/v2/router.ts +322 -0
  457. package/src/memory/v2/sim.ts +25 -12
  458. package/src/memory/v2/skill-store.ts +118 -29
  459. package/src/memory/v2/static-context.ts +16 -9
  460. package/src/memory/v2/sweep-job.ts +122 -96
  461. package/src/memory/v2/types.ts +10 -6
  462. package/src/memory/validation.ts +13 -0
  463. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  464. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  465. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  466. package/src/notifications/adapters/platform.ts +171 -0
  467. package/src/notifications/conversation-pairing.ts +2 -2
  468. package/src/notifications/copy-composer.ts +15 -0
  469. package/src/notifications/destination-resolver.ts +21 -0
  470. package/src/notifications/emit-signal.ts +28 -1
  471. package/src/notifications/home-feed-side-effect.ts +111 -0
  472. package/src/notifications/signal.ts +5 -0
  473. package/src/permissions/checker.ts +12 -0
  474. package/src/permissions/ipc-risk-types.ts +2 -0
  475. package/src/plugin-api/index.ts +13 -0
  476. package/src/plugin-api/package.json +12 -0
  477. package/src/plugin-api/types.ts +62 -0
  478. package/src/plugins/defaults/injectors.ts +19 -3
  479. package/src/plugins/external-plugin-loader.ts +294 -0
  480. package/src/plugins/types.ts +46 -30
  481. package/src/plugins/user-loader.ts +64 -41
  482. package/src/proactive-artifact/job.test.ts +12 -4
  483. package/src/proactive-artifact/job.ts +4 -0
  484. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  485. package/src/proactive-artifact/trigger-state.ts +4 -0
  486. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  487. package/src/prompts/system-prompt.ts +22 -1
  488. package/src/prompts/update-bulletin-job.ts +61 -73
  489. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  490. package/src/providers/__tests__/inference.test.ts +288 -0
  491. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  492. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  493. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  494. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  495. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  496. package/src/providers/anthropic/client.ts +95 -26
  497. package/src/providers/call-site-routing.ts +94 -16
  498. package/src/providers/connection-resolution.ts +163 -0
  499. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  500. package/src/providers/inference/adapter-factory.ts +173 -0
  501. package/src/providers/inference/auth.ts +112 -0
  502. package/src/providers/inference/backfill.ts +196 -0
  503. package/src/providers/inference/connections.ts +356 -0
  504. package/src/providers/inference/resolve-auth.ts +65 -0
  505. package/src/providers/model-catalog.ts +104 -6
  506. package/src/providers/openai/responses-provider.ts +4 -2
  507. package/src/providers/provider-env-vars.ts +17 -7
  508. package/src/providers/provider-secret-catalog.ts +49 -30
  509. package/src/providers/provider-send-message.ts +41 -20
  510. package/src/providers/registry.ts +143 -159
  511. package/src/providers/retry.ts +18 -10
  512. package/src/providers/search-provider-catalog.ts +121 -0
  513. package/src/runtime/AGENTS.md +18 -5
  514. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  515. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  516. package/src/runtime/actor-trust-resolver.ts +32 -10
  517. package/src/runtime/agent-wake.ts +35 -6
  518. package/src/runtime/assistant-event-hub.ts +3 -85
  519. package/src/runtime/auth/route-policy.ts +303 -8
  520. package/src/runtime/auth/same-actor.ts +2 -0
  521. package/src/runtime/background-job-runner.ts +339 -0
  522. package/src/runtime/btw-sidechain.ts +1 -0
  523. package/src/runtime/http-router.ts +36 -1
  524. package/src/runtime/http-server.ts +31 -5
  525. package/src/runtime/http-types.ts +2 -0
  526. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  527. package/src/runtime/middleware/request-logger.ts +62 -1
  528. package/src/runtime/pre-first-message-gate.ts +83 -0
  529. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  530. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  531. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  532. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  533. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  534. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  535. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  536. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  537. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  538. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  539. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  540. package/src/runtime/routes/acp-routes.ts +10 -8
  541. package/src/runtime/routes/app-management-routes.ts +228 -3
  542. package/src/runtime/routes/approval-routes.ts +0 -18
  543. package/src/runtime/routes/audit-routes.ts +43 -0
  544. package/src/runtime/routes/auth-routes.ts +72 -0
  545. package/src/runtime/routes/avatar-routes.ts +273 -20
  546. package/src/runtime/routes/backup-routes.ts +406 -2
  547. package/src/runtime/routes/bookmark-routes.ts +154 -0
  548. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  549. package/src/runtime/routes/contact-routes.ts +0 -160
  550. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  551. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  552. package/src/runtime/routes/conversation-query-routes.ts +334 -86
  553. package/src/runtime/routes/conversation-routes.ts +31 -10
  554. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  555. package/src/runtime/routes/credential-routes.ts +540 -0
  556. package/src/runtime/routes/debug-routes.ts +2 -2
  557. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  558. package/src/runtime/routes/domain-routes.ts +167 -0
  559. package/src/runtime/routes/email-routes.ts +603 -0
  560. package/src/runtime/routes/errors.ts +2 -2
  561. package/src/runtime/routes/events-routes.ts +192 -0
  562. package/src/runtime/routes/home-feed-routes.ts +6 -78
  563. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  564. package/src/runtime/routes/host-browser-routes.ts +103 -22
  565. package/src/runtime/routes/http-adapter.ts +2 -0
  566. package/src/runtime/routes/identity-routes.ts +5 -0
  567. package/src/runtime/routes/image-generation-routes.ts +99 -0
  568. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  569. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  570. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  571. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  572. package/src/runtime/routes/index.ts +36 -0
  573. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  574. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  575. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  576. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  577. package/src/runtime/routes/inference-send-routes.ts +115 -0
  578. package/src/runtime/routes/integrations/twilio.ts +1 -0
  579. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  580. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  581. package/src/runtime/routes/notification-routes.ts +2 -0
  582. package/src/runtime/routes/oauth-apps.ts +112 -7
  583. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  584. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  585. package/src/runtime/routes/oauth-providers.ts +298 -8
  586. package/src/runtime/routes/platform-routes.ts +336 -0
  587. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  588. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  589. package/src/runtime/routes/playground/state.ts +2 -1
  590. package/src/runtime/routes/publish-routes.ts +221 -0
  591. package/src/runtime/routes/schedule-routes.ts +82 -0
  592. package/src/runtime/routes/sequence-routes.ts +291 -0
  593. package/src/runtime/routes/settings-routes.ts +2 -10
  594. package/src/runtime/routes/skills-routes.ts +31 -1
  595. package/src/runtime/routes/stt-routes.ts +240 -3
  596. package/src/runtime/routes/surface-action-routes.ts +43 -7
  597. package/src/runtime/routes/tts-routes.ts +67 -0
  598. package/src/runtime/routes/types.ts +32 -0
  599. package/src/runtime/routes/user-routes-cli.ts +243 -0
  600. package/src/runtime/routes/webhook-routes.ts +165 -0
  601. package/src/runtime/sync/resource-sync-events.ts +25 -0
  602. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  603. package/src/runtime/sync/sync-publisher.ts +21 -0
  604. package/src/schedule/scheduler.ts +200 -123
  605. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  606. package/src/security/secret-patterns.ts +3 -0
  607. package/src/sequence/engine.ts +38 -40
  608. package/src/subagent/manager.ts +20 -15
  609. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  610. package/src/tools/browser/browser-execution.ts +15 -4
  611. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  612. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  613. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  614. package/src/tools/browser/cdp-client/factory.ts +66 -5
  615. package/src/tools/browser/runtime-check.ts +77 -0
  616. package/src/tools/memory/register.test.ts +3 -3
  617. package/src/tools/memory/register.ts +9 -1
  618. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  619. package/src/tools/network/web-search.ts +280 -37
  620. package/src/tools/permission-checker.ts +13 -5
  621. package/src/tools/subagent/spawn.ts +3 -3
  622. package/src/tools/terminal/shell.ts +44 -0
  623. package/src/usage/attribution.ts +3 -2
  624. package/src/util/pricing.ts +86 -160
  625. package/src/watcher/__tests__/engine.test.ts +301 -0
  626. package/src/watcher/constants.ts +7 -0
  627. package/src/watcher/engine.ts +90 -90
  628. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  629. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  630. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  631. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  632. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  633. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  634. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  635. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  636. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  637. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  638. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  639. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  640. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  641. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  642. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  643. package/src/workspace/migrations/registry.ts +22 -0
  644. package/src/workspace/migrations/runner.ts +13 -2
  645. package/src/workspace/migrations/types.ts +13 -3
  646. package/src/workspace/provider-commit-message-generator.ts +3 -2
  647. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  648. package/src/__tests__/credentials-cli.test.ts +0 -1225
  649. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  650. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  651. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  652. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  653. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  654. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  655. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  656. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  657. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  658. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  659. package/src/cli/commands/autonomy.ts +0 -365
  660. package/src/cli/commands/memory.ts +0 -424
  661. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  662. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  663. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  664. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  665. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  666. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  667. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  668. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  669. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  670. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  671. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  672. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  673. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  674. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  675. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  676. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  677. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  678. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  679. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  680. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  681. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  682. package/src/home/assistant-feed-authoring.ts +0 -135
  683. package/src/home/emit-feed-event.ts +0 -169
  684. package/src/home/feed-scheduler.ts +0 -281
  685. package/src/home/platform-gmail-digest.ts +0 -163
  686. package/src/home/rewrite-command-preview.ts +0 -66
  687. package/src/home/rewrite-feed-title.ts +0 -58
  688. package/src/home/rollup-producer.ts +0 -426
  689. package/src/memory/admin.ts +0 -326
  690. package/src/memory/context-search/sources/pkb.ts +0 -476
  691. package/src/memory/graph/compaction.ts +0 -299
  692. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -2,16 +2,15 @@
2
2
  * Tests for `assistant/src/memory/v2/consolidation-job.ts`.
3
3
  *
4
4
  * Coverage matrix:
5
- * - v2 disabled in config → no provider/wake calls; returns disabled.
6
- * - v2 on, empty buffer → no wake call; returns empty_buffer.
7
- * - v2 on, non-empty buffer → bootstrap conversation, wake invoked with
8
- * the cutoff-templated prompt, follow-up jobs enqueued.
9
- * - Lock file already present → second call returns locked; first call's
10
- * in-flight semantics preserved by leaving the lock in place.
11
- * - Wake returns invoked: false → orphan conversation cleaned up; no
12
- * follow-up jobs enqueued.
13
- * - Wake throws → orphan conversation cleaned up; lock released; handler
14
- * does NOT propagate the error (treated like any other wake failure).
5
+ * - Flag off → no runner call; returns disabled.
6
+ * - Flag on, empty buffer → no runner call; returns empty_buffer.
7
+ * - Flag on, non-empty buffer → runner invoked with the cutoff-templated
8
+ * prompt and `suppressFailureNotifications: true`; follow-up jobs
9
+ * enqueued on success.
10
+ * - Lock file already present second call returns locked.
11
+ * - Runner returns ok=false → run_failed surfaced; NO follow-up jobs;
12
+ * `emitNotificationSignal` was NOT called as a result of the failure
13
+ * (suppression is honored end-to-end).
15
14
  *
16
15
  * Tests use temp workspaces (mkdtemp) and never touch `~/.vellum/`. Sample
17
16
  * content uses generic placeholders (Alice).
@@ -41,31 +40,49 @@ mock.module("../../../util/logger.js", () => ({
41
40
  getLogger: () => makeMockLogger(),
42
41
  }));
43
42
 
44
- // ── bootstrapConversation mock ──────────────────────────────────────
45
- let bootstrapCalls = 0;
46
- let bootstrapLastArgs: Record<string, unknown> | null = null;
47
-
48
- mock.module("../../conversation-bootstrap.js", () => ({
49
- bootstrapConversation: (opts: Record<string, unknown>) => {
50
- bootstrapCalls += 1;
51
- bootstrapLastArgs = opts;
52
- return { id: `conv-${bootstrapCalls}` };
43
+ // ── runBackgroundJob mock ───────────────────────────────────────────
44
+ //
45
+ // The consolidation handler delegates the bootstrap + processMessage +
46
+ // timeout + classification + suppress-aware emit to runBackgroundJob.
47
+ // We stub it here and assert (a) the runner is called with
48
+ // `suppressFailureNotifications: true`, and (b) the prompt + callSite
49
+ // + trustContext + origin match what the consolidation surface expects.
50
+ let runnerCalls = 0;
51
+ let runnerLastArgs: Record<string, unknown> | null = null;
52
+ let runnerImpl: () => Promise<{
53
+ conversationId: string;
54
+ ok: boolean;
55
+ error?: Error;
56
+ errorKind?: string;
57
+ }> = async () => ({ conversationId: "conv-1", ok: true });
58
+
59
+ mock.module("../../../runtime/background-job-runner.js", () => ({
60
+ runBackgroundJob: async (opts: Record<string, unknown>) => {
61
+ runnerCalls += 1;
62
+ runnerLastArgs = opts;
63
+ return runnerImpl();
53
64
  },
54
65
  }));
55
66
 
56
- // ── deleteConversation mock (orphan cleanup path) ───────────────────
57
- let deleteCalls = 0;
58
- const deletedIds: string[] = [];
59
- let deleteShouldThrow = false;
60
-
61
- mock.module("../../conversation-crud.js", () => ({
62
- deleteConversation: (id: string) => {
63
- deleteCalls += 1;
64
- deletedIds.push(id);
65
- if (deleteShouldThrow) {
66
- throw new Error("simulated delete failure");
67
- }
68
- return { segmentIds: [], deletedSummaryIds: [] };
67
+ // ── emitNotificationSignal spy ──────────────────────────────────────
68
+ //
69
+ // The runner is stubbed above, so the real `emit-signal` module never
70
+ // runs in these tests. We mock it as a defensive belt-and-suspenders
71
+ // assertion: even if the runner stub were swapped out for the real
72
+ // implementation, this counter would catch any path that ends up
73
+ // emitting a signal as a result of consolidation failure.
74
+ const emitCalls: Array<Record<string, unknown>> = [];
75
+
76
+ mock.module("../../../notifications/emit-signal.js", () => ({
77
+ emitNotificationSignal: async (params: Record<string, unknown>) => {
78
+ emitCalls.push(params);
79
+ return {
80
+ signalId: "sig-1",
81
+ deduplicated: false,
82
+ dispatched: true,
83
+ reason: "ok",
84
+ deliveryResults: [],
85
+ };
69
86
  },
70
87
  }));
71
88
 
@@ -87,28 +104,6 @@ mock.module("../../jobs-store.js", () => ({
87
104
  },
88
105
  }));
89
106
 
90
- // ── wakeAgentForOpportunity mock ────────────────────────────────────
91
- let wakeCalls = 0;
92
- let wakeLastArgs: Record<string, unknown> | null = null;
93
- let wakeShouldThrow = false;
94
- let wakeInvoked = true;
95
- let wakeReason: string | undefined;
96
-
97
- mock.module("../../../runtime/agent-wake.js", () => ({
98
- wakeAgentForOpportunity: async (opts: Record<string, unknown>) => {
99
- wakeCalls += 1;
100
- wakeLastArgs = opts;
101
- if (wakeShouldThrow) {
102
- throw new Error("simulated wake failure");
103
- }
104
- return {
105
- invoked: wakeInvoked,
106
- producedToolCalls: false,
107
- ...(wakeReason ? { reason: wakeReason } : {}),
108
- };
109
- },
110
- }));
111
-
112
107
  // ── Workspace pin ───────────────────────────────────────────────────
113
108
  let tmpWorkspace: string;
114
109
  let previousWorkspaceEnv: string | undefined;
@@ -171,31 +166,24 @@ beforeEach(() => {
171
166
  mkdirSync(join(memoryDir(), "concepts"), { recursive: true });
172
167
  mkdirSync(join(memoryDir(), "archive"), { recursive: true });
173
168
 
174
- bootstrapCalls = 0;
175
- bootstrapLastArgs = null;
176
- deleteCalls = 0;
177
- deletedIds.length = 0;
178
- deleteShouldThrow = false;
169
+ runnerCalls = 0;
170
+ runnerLastArgs = null;
171
+ runnerImpl = async () => ({ conversationId: "conv-1", ok: true });
172
+ emitCalls.length = 0;
179
173
  enqueuedJobs.length = 0;
180
174
  nextJobIdCounter = 0;
181
- wakeCalls = 0;
182
- wakeLastArgs = null;
183
- wakeShouldThrow = false;
184
- wakeInvoked = true;
185
- wakeReason = undefined;
186
175
  });
187
176
 
188
177
  // ---------------------------------------------------------------------------
189
178
 
190
179
  describe("memoryV2ConsolidateJob — v2 disabled", () => {
191
- test("returns disabled without invoking the wake when memory.v2.enabled is false", async () => {
180
+ test("returns disabled without invoking the runner when memory.v2.enabled is false", async () => {
192
181
  writeFileSync(bufferPath(), "- [Apr 27, 9:00 AM] Alice prefers VS Code.\n");
193
182
 
194
183
  const result = await memoryV2ConsolidateJob(makeJob(), CONFIG_DISABLED);
195
184
 
196
185
  expect(result).toEqual({ kind: "disabled" });
197
- expect(bootstrapCalls).toBe(0);
198
- expect(wakeCalls).toBe(0);
186
+ expect(runnerCalls).toBe(0);
199
187
  expect(enqueuedJobs).toHaveLength(0);
200
188
  // Lock must NOT linger on the disabled path — the handler bailed before
201
189
  // the lock was acquired.
@@ -210,8 +198,7 @@ describe("memoryV2ConsolidateJob — empty buffer", () => {
210
198
  const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
211
199
 
212
200
  expect(result).toEqual({ kind: "empty_buffer" });
213
- expect(bootstrapCalls).toBe(0);
214
- expect(wakeCalls).toBe(0);
201
+ expect(runnerCalls).toBe(0);
215
202
  expect(enqueuedJobs).toHaveLength(0);
216
203
  });
217
204
 
@@ -221,8 +208,7 @@ describe("memoryV2ConsolidateJob — empty buffer", () => {
221
208
  const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
222
209
 
223
210
  expect(result).toEqual({ kind: "empty_buffer" });
224
- expect(bootstrapCalls).toBe(0);
225
- expect(wakeCalls).toBe(0);
211
+ expect(runnerCalls).toBe(0);
226
212
  expect(enqueuedJobs).toHaveLength(0);
227
213
  });
228
214
 
@@ -242,32 +228,37 @@ describe("memoryV2ConsolidateJob — non-empty buffer", () => {
242
228
  );
243
229
  });
244
230
 
245
- test("bootstraps a background conversation and wakes the assistant with a templated prompt", async () => {
231
+ test("invokes runBackgroundJob with the cutoff-templated prompt and suppressFailureNotifications: true", async () => {
246
232
  const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
247
233
 
248
234
  expect(result.kind).toBe("invoked");
249
- expect(bootstrapCalls).toBe(1);
250
- expect(bootstrapLastArgs).toEqual({
251
- conversationType: "background",
252
- source: "memory_v2_consolidation",
253
- origin: "memory_consolidation",
254
- systemHint: "Running memory consolidation",
255
- groupId: "system:background",
235
+ expect(runnerCalls).toBe(1);
236
+ expect(runnerLastArgs).not.toBeNull();
237
+ expect(runnerLastArgs?.jobName).toBe("memory.consolidate");
238
+ expect(runnerLastArgs?.source).toBe("memory_v2_consolidation");
239
+ expect(runnerLastArgs?.callSite).toBe("mainAgent");
240
+ expect(runnerLastArgs?.origin).toBe("memory_consolidation");
241
+ // The whole point of this PR: opt out of activity.failed notifications
242
+ // because consolidation runs on tight intervals and transient failures
243
+ // would spam the home feed.
244
+ expect(runnerLastArgs?.suppressFailureNotifications).toBe(true);
245
+ expect(runnerLastArgs?.trustContext).toEqual({
246
+ sourceChannel: "vellum",
247
+ trustClass: "guardian",
256
248
  });
257
-
258
- expect(wakeCalls).toBe(1);
259
- expect(wakeLastArgs?.conversationId).toBe("conv-1");
260
- expect(wakeLastArgs?.source).toBe("memory_v2_consolidation");
261
-
262
- // The hint must contain the prompt body with the cutoff timestamp
263
- // substituted in. Asserting the placeholder is GONE catches a regression
264
- // where `replaceAll` is dropped and the model receives `{{CUTOFF}}`.
265
- const hint = wakeLastArgs?.hint as string;
266
- expect(hint).toContain("memory consolidation");
267
- expect(hint).not.toContain(CUTOFF_PLACEHOLDER);
268
- // Cutoff is an ISO-8601 timestamp check the year prefix matches the
269
- // current year so we know the substitution actually happened.
270
- expect(hint).toContain(`${new Date().getFullYear()}`);
249
+ expect(typeof runnerLastArgs?.timeoutMs).toBe("number");
250
+ expect((runnerLastArgs?.timeoutMs as number) > 0).toBe(true);
251
+
252
+ // The prompt must contain the rendered consolidation body with the
253
+ // cutoff substituted in. Asserting the placeholder is GONE catches a
254
+ // regression where `replaceAll` is dropped and the model receives
255
+ // `{{CUTOFF}}` literally.
256
+ const prompt = runnerLastArgs?.prompt as string;
257
+ expect(prompt).toContain("memory consolidation");
258
+ expect(prompt).not.toContain(CUTOFF_PLACEHOLDER);
259
+ // Cutoff is a buffer-entry-format timestamp (`Mon D, h:mm AM/PM`) so it
260
+ // compares like-with-like against `buffer.md` lines at minute precision.
261
+ expect(prompt).toMatch(/\b[A-Z][a-z]{2} \d{1,2}, \d{1,2}:\d{2} (AM|PM)\b/);
271
262
  });
272
263
 
273
264
  test("honors memory.v2.consolidation_prompt_path override when set", async () => {
@@ -284,10 +275,12 @@ describe("memoryV2ConsolidateJob — non-empty buffer", () => {
284
275
  const result = await memoryV2ConsolidateJob(makeJob(), overrideConfig);
285
276
 
286
277
  expect(result.kind).toBe("invoked");
287
- const hint = wakeLastArgs?.hint as string;
288
- expect(hint).toMatch(/^CUSTOM CONSOLIDATION at \d{4}-/);
289
- expect(hint).not.toContain("You are running memory consolidation");
290
- expect(hint).not.toContain(CUTOFF_PLACEHOLDER);
278
+ const prompt = runnerLastArgs?.prompt as string;
279
+ expect(prompt).toMatch(
280
+ /^CUSTOM CONSOLIDATION at [A-Z][a-z]{2} \d{1,2}, \d{1,2}:\d{2} (AM|PM)$/m,
281
+ );
282
+ expect(prompt).not.toContain("You are running memory consolidation");
283
+ expect(prompt).not.toContain(CUTOFF_PLACEHOLDER);
291
284
  });
292
285
 
293
286
  test("enqueues the memory_v2_reembed follow-up job on success", async () => {
@@ -311,48 +304,46 @@ describe("memoryV2ConsolidateJob — non-empty buffer", () => {
311
304
  expect(existsSync(lockPath())).toBe(false);
312
305
  });
313
306
 
314
- test("returns wake_failed and cleans up the orphan conversation when wake returns invoked: false", async () => {
315
- wakeInvoked = false;
316
- wakeReason = "no_resolver";
307
+ test("returns run_failed and skips follow-ups when the runner reports failure", async () => {
308
+ runnerImpl = async () => ({
309
+ conversationId: "conv-1",
310
+ ok: false,
311
+ error: new Error("simulated runner failure"),
312
+ errorKind: "exception",
313
+ });
317
314
 
318
315
  const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
319
316
 
320
- expect(result.kind).toBe("wake_failed");
321
- if (result.kind === "wake_failed") {
322
- expect(result.reason).toBe("no_resolver");
317
+ expect(result.kind).toBe("run_failed");
318
+ if (result.kind === "run_failed") {
319
+ expect(result.reason).toBe("simulated runner failure");
323
320
  }
324
- expect(deleteCalls).toBe(1);
325
- expect(deletedIds).toEqual(["conv-1"]);
326
- // Critical: do NOT enqueue follow-ups when the wake didn't run — there's
327
- // nothing for them to operate on.
321
+ // No follow-ups: the agent's writes may be partial and re-embedding
322
+ // partial state would be misleading.
328
323
  expect(enqueuedJobs).toHaveLength(0);
329
- });
330
-
331
- test("returns wake_failed without throwing when wake itself rejects", async () => {
332
- wakeShouldThrow = true;
333
-
334
- const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
335
-
336
- expect(result.kind).toBe("wake_failed");
337
- if (result.kind === "wake_failed") {
338
- expect(result.reason).toBe("simulated wake failure");
339
- }
340
- // Lock must still be released on the throw path.
324
+ // Lock must still be released on the failure path so the next
325
+ // scheduled consolidation can re-attempt.
341
326
  expect(existsSync(lockPath())).toBe(false);
342
- expect(deleteCalls).toBe(1);
343
- expect(enqueuedJobs).toHaveLength(0);
344
327
  });
345
328
 
346
- test("does not propagate when deleteConversation throws on the cleanup path", async () => {
347
- wakeInvoked = false;
348
- deleteShouldThrow = true;
329
+ test("does NOT emit a notification signal when the runner fails (suppression honored)", async () => {
330
+ // This is the user-visible payoff of `suppressFailureNotifications: true`:
331
+ // even when the runner stub reports a failure, the consolidation
332
+ // handler must not produce any notification side-effect. The runner
333
+ // itself owns the suppression behavior; this test guards the contract
334
+ // from the consolidation surface — if a future change ever bypasses
335
+ // the runner and emits its own signal on the failure path, this assert
336
+ // will catch it.
337
+ runnerImpl = async () => ({
338
+ conversationId: "conv-1",
339
+ ok: false,
340
+ error: new Error("network blip"),
341
+ errorKind: "model_provider",
342
+ });
349
343
 
350
- await expect(
351
- memoryV2ConsolidateJob(makeJob(), CONFIG),
352
- ).resolves.toMatchObject({ kind: "wake_failed" });
344
+ await memoryV2ConsolidateJob(makeJob(), CONFIG);
353
345
 
354
- expect(deleteCalls).toBe(1);
355
- expect(existsSync(lockPath())).toBe(false);
346
+ expect(emitCalls).toHaveLength(0);
356
347
  });
357
348
  });
358
349
 
@@ -374,8 +365,7 @@ describe("memoryV2ConsolidateJob — concurrent invocations", () => {
374
365
  if (result.kind === "locked") {
375
366
  expect(result.holder).toContain(`${process.pid}`);
376
367
  }
377
- expect(bootstrapCalls).toBe(0);
378
- expect(wakeCalls).toBe(0);
368
+ expect(runnerCalls).toBe(0);
379
369
  expect(enqueuedJobs).toHaveLength(0);
380
370
  // The live holder's lock must NOT be removed by a contender.
381
371
  expect(existsSync(lockPath())).toBe(true);
@@ -392,8 +382,7 @@ describe("memoryV2ConsolidateJob — concurrent invocations", () => {
392
382
  const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
393
383
 
394
384
  expect(result.kind).toBe("invoked");
395
- expect(bootstrapCalls).toBe(1);
396
- expect(wakeCalls).toBe(1);
385
+ expect(runnerCalls).toBe(1);
397
386
  // Lock is released in the finally block after a successful run.
398
387
  expect(existsSync(lockPath())).toBe(false);
399
388
  });
@@ -409,8 +398,7 @@ describe("memoryV2ConsolidateJob — concurrent invocations", () => {
409
398
  const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
410
399
 
411
400
  expect(result.kind).toBe("invoked");
412
- expect(bootstrapCalls).toBe(1);
413
- expect(wakeCalls).toBe(1);
401
+ expect(runnerCalls).toBe(1);
414
402
  expect(existsSync(lockPath())).toBe(false);
415
403
  });
416
404
  });
@@ -36,7 +36,7 @@ afterEach(() => {
36
36
  function makePage(slug: string, edges: string[] = [], body = ""): ConceptPage {
37
37
  return {
38
38
  slug,
39
- frontmatter: { edges, ref_files: [] },
39
+ frontmatter: { edges, ref_files: [], ref_urls: [] },
40
40
  body,
41
41
  };
42
42
  }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Tests for `assistant/src/memory/v2/frontmatter-sweep.ts`.
3
+ *
4
+ * Coverage:
5
+ * - Empty workspace → no warns, no throw.
6
+ * - One bad page (unknown frontmatter key) → exactly one warn carrying
7
+ * `errCode: "unrecognized_keys"` and the offending slug.
8
+ * - Two bad + one good page → two warns; good page produces nothing.
9
+ * - Malformed YAML → a warn surfaces; the sweep does not crash.
10
+ */
11
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
15
+
16
+ const warnCalls: Array<{ data: Record<string, unknown>; msg: string }> = [];
17
+ const recordingLogger = {
18
+ warn: (data: Record<string, unknown>, msg: string) => {
19
+ warnCalls.push({ data, msg });
20
+ },
21
+ info: () => {},
22
+ debug: () => {},
23
+ error: () => {},
24
+ trace: () => {},
25
+ fatal: () => {},
26
+ child: () => recordingLogger,
27
+ };
28
+
29
+ mock.module("../../../util/logger.js", () => ({
30
+ getLogger: () => recordingLogger,
31
+ }));
32
+
33
+ const { sweepConceptPageFrontmatter } = await import("../frontmatter-sweep.js");
34
+
35
+ function makeWorkspace(pages: Record<string, string>): string {
36
+ const dir = mkdtempSync(join(tmpdir(), "frontmatter-sweep-"));
37
+ const conceptsDir = join(dir, "memory", "concepts");
38
+ if (Object.keys(pages).length > 0) {
39
+ mkdirSync(conceptsDir, { recursive: true });
40
+ for (const [slug, content] of Object.entries(pages)) {
41
+ writeFileSync(join(conceptsDir, `${slug}.md`), content, "utf-8");
42
+ }
43
+ }
44
+ return dir;
45
+ }
46
+
47
+ const goodPage = `---\nedges: []\nref_files: []\n---\nbody\n`;
48
+ const badPage = `---\nedges: []\nref_files: []\nbogus_field: 1\n---\nbody\n`;
49
+
50
+ describe("sweepConceptPageFrontmatter", () => {
51
+ beforeEach(() => {
52
+ warnCalls.length = 0;
53
+ });
54
+ afterEach(() => {
55
+ warnCalls.length = 0;
56
+ });
57
+
58
+ test("empty workspace: no warns, no throw", async () => {
59
+ const dir = makeWorkspace({});
60
+ try {
61
+ await sweepConceptPageFrontmatter(dir);
62
+ expect(warnCalls).toHaveLength(0);
63
+ } finally {
64
+ rmSync(dir, { recursive: true, force: true });
65
+ }
66
+ });
67
+
68
+ test("one bad page emits exactly one unrecognized_keys warn", async () => {
69
+ const dir = makeWorkspace({ "bad-one": badPage });
70
+ try {
71
+ await sweepConceptPageFrontmatter(dir);
72
+ expect(warnCalls).toHaveLength(1);
73
+ expect(warnCalls[0].data.slug).toBe("bad-one");
74
+ expect(warnCalls[0].data.errCode).toBe("unrecognized_keys");
75
+ expect(warnCalls[0].data.errKeys).toEqual(["bogus_field"]);
76
+ } finally {
77
+ rmSync(dir, { recursive: true, force: true });
78
+ }
79
+ });
80
+
81
+ test("two bad and one good page: one warn per bad slug, none for the good", async () => {
82
+ const dir = makeWorkspace({
83
+ good: goodPage,
84
+ "bad-a": badPage,
85
+ "bad-b": badPage,
86
+ });
87
+ try {
88
+ await sweepConceptPageFrontmatter(dir);
89
+ const slugs = warnCalls.map((c) => c.data.slug).sort();
90
+ expect(slugs).toEqual(["bad-a", "bad-b"]);
91
+ for (const call of warnCalls) {
92
+ expect(call.data.errCode).toBe("unrecognized_keys");
93
+ }
94
+ } finally {
95
+ rmSync(dir, { recursive: true, force: true });
96
+ }
97
+ });
98
+
99
+ test("malformed YAML: warn surfaces, sweep does not throw", async () => {
100
+ const dir = makeWorkspace({
101
+ mangled: `---\nedges: [unterminated\n---\nbody\n`,
102
+ });
103
+ try {
104
+ await sweepConceptPageFrontmatter(dir);
105
+ expect(warnCalls.length).toBeGreaterThanOrEqual(1);
106
+ expect(warnCalls.some((c) => c.data.slug === "mangled")).toBe(true);
107
+ } finally {
108
+ rmSync(dir, { recursive: true, force: true });
109
+ }
110
+ });
111
+ });