@vellumai/assistant 0.5.1 → 0.5.3

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 (405) hide show
  1. package/ARCHITECTURE.md +163 -54
  2. package/docs/architecture/integrations.md +62 -67
  3. package/docs/credential-execution-service.md +3 -3
  4. package/docs/skills.md +100 -0
  5. package/package.json +1 -1
  6. package/src/__tests__/agent-loop.test.ts +111 -0
  7. package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
  8. package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
  9. package/src/__tests__/app-dir-path-guard.test.ts +78 -0
  10. package/src/__tests__/app-executors.test.ts +1 -291
  11. package/src/__tests__/app-git-history.test.ts +4 -4
  12. package/src/__tests__/app-routes-csp.test.ts +1 -0
  13. package/src/__tests__/app-store-dir-names.test.ts +426 -0
  14. package/src/__tests__/attachments-store.test.ts +169 -21
  15. package/src/__tests__/attachments.test.ts +115 -1
  16. package/src/__tests__/btw-routes.test.ts +1 -0
  17. package/src/__tests__/canonical-guardian-store.test.ts +38 -0
  18. package/src/__tests__/channel-reply-delivery.test.ts +55 -0
  19. package/src/__tests__/checker.test.ts +54 -0
  20. package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
  21. package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
  22. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  23. package/src/__tests__/config-schema-cmd.test.ts +68 -21
  24. package/src/__tests__/config-schema.test.ts +1 -1
  25. package/src/__tests__/conversation-agent-loop-overflow.test.ts +156 -5
  26. package/src/__tests__/conversation-agent-loop.test.ts +297 -2
  27. package/src/__tests__/conversation-attachments.test.ts +17 -19
  28. package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
  29. package/src/__tests__/conversation-disk-view.test.ts +810 -0
  30. package/src/__tests__/conversation-error.test.ts +1 -1
  31. package/src/__tests__/conversation-fork-crud.test.ts +551 -0
  32. package/src/__tests__/conversation-fork-route.test.ts +386 -0
  33. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  34. package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
  35. package/src/__tests__/conversation-media-retry.test.ts +8 -2
  36. package/src/__tests__/conversation-memory-dirty-tail.test.ts +150 -0
  37. package/src/__tests__/conversation-provider-retry-repair.test.ts +7 -0
  38. package/src/__tests__/conversation-queue.test.ts +36 -1
  39. package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
  40. package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
  41. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
  42. package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
  43. package/src/__tests__/conversation-skill-tools.test.ts +4 -9
  44. package/src/__tests__/conversation-slash-commands.test.ts +149 -0
  45. package/src/__tests__/conversation-store.test.ts +24 -21
  46. package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
  47. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
  48. package/src/__tests__/conversation-title-service.test.ts +137 -0
  49. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
  50. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
  51. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
  52. package/src/__tests__/conversation-wipe.test.ts +226 -0
  53. package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
  54. package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
  55. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  56. package/src/__tests__/credential-vault-unit.test.ts +5 -10
  57. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  58. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
  59. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
  60. package/src/__tests__/db-memory-archive-migration.test.ts +372 -0
  61. package/src/__tests__/db-memory-brief-state-migration.test.ts +213 -0
  62. package/src/__tests__/db-memory-reducer-checkpoints.test.ts +273 -0
  63. package/src/__tests__/diagnostics-export.test.ts +70 -1
  64. package/src/__tests__/first-greeting.test.ts +80 -0
  65. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  66. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
  67. package/src/__tests__/history-repair.test.ts +32 -10
  68. package/src/__tests__/http-conversation-lineage.test.ts +251 -0
  69. package/src/__tests__/image-source-path-reinject.test.ts +136 -0
  70. package/src/__tests__/inline-command-runner.test.ts +311 -0
  71. package/src/__tests__/inline-skill-authoring-guard.test.ts +220 -0
  72. package/src/__tests__/inline-skill-load-permissions.test.ts +435 -0
  73. package/src/__tests__/list-messages-attachments.test.ts +96 -0
  74. package/src/__tests__/llm-context-normalization.test.ts +1116 -0
  75. package/src/__tests__/llm-context-route-provider.test.ts +217 -0
  76. package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
  77. package/src/__tests__/media-generate-image.test.ts +47 -94
  78. package/src/__tests__/memory-brief-open-loops.test.ts +530 -0
  79. package/src/__tests__/memory-brief-time.test.ts +285 -0
  80. package/src/__tests__/memory-brief-wrapper.test.ts +311 -0
  81. package/src/__tests__/memory-chunk-archive.test.ts +400 -0
  82. package/src/__tests__/memory-chunk-dual-write.test.ts +453 -0
  83. package/src/__tests__/memory-episode-archive.test.ts +370 -0
  84. package/src/__tests__/memory-episode-dual-write.test.ts +626 -0
  85. package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
  86. package/src/__tests__/memory-observation-archive.test.ts +375 -0
  87. package/src/__tests__/memory-observation-dual-write.test.ts +318 -0
  88. package/src/__tests__/memory-recall-quality.test.ts +7 -7
  89. package/src/__tests__/memory-reducer-store.test.ts +728 -0
  90. package/src/__tests__/memory-reducer-types.test.ts +699 -0
  91. package/src/__tests__/memory-reducer.test.ts +698 -0
  92. package/src/__tests__/memory-regressions.test.ts +6 -4
  93. package/src/__tests__/memory-simplified-config.test.ts +281 -0
  94. package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
  95. package/src/__tests__/migration-export-http.test.ts +3 -1
  96. package/src/__tests__/migration-import-commit-http.test.ts +18 -4
  97. package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
  98. package/src/__tests__/mime-builder.test.ts +3 -2
  99. package/src/__tests__/non-member-access-request.test.ts +12 -1
  100. package/src/__tests__/notification-decision-identity.test.ts +52 -0
  101. package/src/__tests__/oauth-apps-routes.test.ts +103 -0
  102. package/src/__tests__/oauth-store.test.ts +115 -0
  103. package/src/__tests__/parse-identity-fields.test.ts +129 -0
  104. package/src/__tests__/provider-error-scenarios.test.ts +1 -3
  105. package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
  106. package/src/__tests__/recording-handler.test.ts +17 -0
  107. package/src/__tests__/registry.test.ts +3 -8
  108. package/src/__tests__/relay-server.test.ts +1 -1
  109. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
  110. package/src/__tests__/schema-transforms.test.ts +165 -5
  111. package/src/__tests__/server-history-render.test.ts +2 -2
  112. package/src/__tests__/skill-load-inline-command.test.ts +598 -0
  113. package/src/__tests__/skill-load-inline-includes.test.ts +644 -0
  114. package/src/__tests__/skills-inline-command-expansions.test.ts +301 -0
  115. package/src/__tests__/skills-transitive-hash.test.ts +333 -0
  116. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  117. package/src/__tests__/slack-inbound-verification.test.ts +2 -2
  118. package/src/__tests__/starter-task-flow.test.ts +1 -0
  119. package/src/__tests__/suggestion-routes.test.ts +443 -0
  120. package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
  121. package/src/__tests__/swarm-recursion.test.ts +1 -0
  122. package/src/__tests__/swarm-tool.test.ts +1 -0
  123. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
  124. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
  125. package/src/__tests__/top-level-renderer.test.ts +22 -0
  126. package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
  127. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +320 -0
  128. package/src/__tests__/web-fetch.test.ts +6 -2
  129. package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
  130. package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
  131. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
  132. package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
  133. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
  134. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
  135. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
  136. package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
  137. package/src/agent/attachments.ts +27 -1
  138. package/src/agent/loop.ts +29 -1
  139. package/src/avatar/traits-png-sync.ts +80 -25
  140. package/src/bundler/app-bundler.ts +4 -4
  141. package/src/calls/call-domain.ts +1 -0
  142. package/src/calls/voice-session-bridge.ts +1 -0
  143. package/src/cli/commands/auth.ts +92 -0
  144. package/src/cli/commands/avatar.ts +7 -6
  145. package/src/cli/commands/config.ts +2 -0
  146. package/src/cli/commands/oauth/providers.ts +29 -0
  147. package/src/cli/program.ts +12 -0
  148. package/src/cli.ts +15 -48
  149. package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
  150. package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
  151. package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
  152. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
  153. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
  154. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
  155. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
  156. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
  157. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
  158. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
  159. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
  160. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
  161. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
  162. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
  163. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
  164. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
  165. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
  166. package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
  167. package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
  168. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
  169. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
  170. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
  171. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  172. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
  173. package/src/config/bundled-skills/skill-management/SKILL.md +1 -1
  174. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  175. package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
  176. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
  177. package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
  178. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
  179. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
  180. package/src/config/bundled-tool-registry.ts +2 -14
  181. package/src/config/feature-flag-registry.json +24 -0
  182. package/src/config/loader.ts +65 -0
  183. package/src/config/raw-config-utils.ts +58 -0
  184. package/src/config/schema-utils.ts +28 -7
  185. package/src/config/schema.ts +20 -0
  186. package/src/config/schemas/elevenlabs.ts +18 -0
  187. package/src/config/schemas/memory-lifecycle.ts +4 -2
  188. package/src/config/schemas/memory-simplified.ts +101 -0
  189. package/src/config/schemas/memory-storage.ts +1 -1
  190. package/src/config/schemas/memory.ts +4 -0
  191. package/src/config/schemas/services.ts +8 -6
  192. package/src/config/skills.ts +50 -4
  193. package/src/contacts/contact-store.ts +13 -6
  194. package/src/contacts/contacts-write.ts +0 -1
  195. package/src/context/window-manager.ts +13 -2
  196. package/src/daemon/conversation-agent-loop-handlers.ts +54 -8
  197. package/src/daemon/conversation-agent-loop.ts +127 -20
  198. package/src/daemon/conversation-attachments.ts +18 -36
  199. package/src/daemon/conversation-error.ts +2 -1
  200. package/src/daemon/conversation-history.ts +18 -4
  201. package/src/daemon/conversation-lifecycle.ts +50 -16
  202. package/src/daemon/conversation-messaging.ts +70 -26
  203. package/src/daemon/conversation-process.ts +58 -34
  204. package/src/daemon/conversation-runtime-assembly.ts +22 -38
  205. package/src/daemon/conversation-slash.ts +121 -256
  206. package/src/daemon/conversation-surfaces.ts +170 -24
  207. package/src/daemon/conversation-tool-setup.ts +0 -6
  208. package/src/daemon/conversation-workspace.ts +21 -1
  209. package/src/daemon/conversation.ts +69 -30
  210. package/src/daemon/first-greeting.ts +35 -0
  211. package/src/daemon/handlers/config-embeddings.ts +156 -0
  212. package/src/daemon/handlers/config-model.ts +62 -26
  213. package/src/daemon/handlers/conversations.ts +0 -23
  214. package/src/daemon/handlers/identity.ts +12 -1
  215. package/src/daemon/handlers/recording.ts +26 -21
  216. package/src/daemon/host-cu-proxy.ts +2 -2
  217. package/src/daemon/lifecycle.ts +115 -65
  218. package/src/daemon/message-protocol.ts +3 -0
  219. package/src/daemon/message-types/conversations.ts +18 -0
  220. package/src/daemon/message-types/messages.ts +1 -0
  221. package/src/daemon/message-types/shared.ts +2 -0
  222. package/src/daemon/message-types/surfaces.ts +2 -0
  223. package/src/daemon/message-types/upgrades.ts +23 -0
  224. package/src/daemon/server.ts +83 -12
  225. package/src/daemon/shutdown-handlers.ts +8 -5
  226. package/src/daemon/startup-error.ts +9 -0
  227. package/src/daemon/tool-side-effects.ts +11 -28
  228. package/src/events/tool-permission-telemetry-listener.ts +1 -3
  229. package/src/followups/followup-store.ts +47 -1
  230. package/src/instrument.ts +0 -4
  231. package/src/media/app-icon-generator.ts +2 -2
  232. package/src/memory/app-git-service.ts +28 -16
  233. package/src/memory/app-store.ts +230 -41
  234. package/src/memory/archive-store.ts +400 -0
  235. package/src/memory/attachments-store.ts +558 -130
  236. package/src/memory/brief-formatting.ts +33 -0
  237. package/src/memory/brief-open-loops.ts +266 -0
  238. package/src/memory/brief-time.ts +161 -0
  239. package/src/memory/brief.ts +75 -0
  240. package/src/memory/conversation-attention-store.ts +70 -0
  241. package/src/memory/conversation-crud.ts +591 -8
  242. package/src/memory/conversation-directories.ts +125 -0
  243. package/src/memory/conversation-disk-view.ts +390 -0
  244. package/src/memory/conversation-key-store.ts +17 -5
  245. package/src/memory/conversation-queries.ts +5 -1
  246. package/src/memory/conversation-title-service.ts +21 -49
  247. package/src/memory/db-init.ts +40 -0
  248. package/src/memory/embedding-backend.ts +42 -53
  249. package/src/memory/embedding-gemini.test.ts +4 -4
  250. package/src/memory/embedding-local.ts +1 -3
  251. package/src/memory/embedding-ollama.ts +1 -3
  252. package/src/memory/embedding-openai.ts +1 -3
  253. package/src/memory/indexer.ts +114 -21
  254. package/src/memory/items-extractor.ts +42 -13
  255. package/src/memory/job-handlers/conversation-starters.ts +6 -1
  256. package/src/memory/job-handlers/embedding.test.ts +2 -4
  257. package/src/memory/job-handlers/embedding.ts +83 -0
  258. package/src/memory/job-utils.ts +1 -1
  259. package/src/memory/jobs-store.ts +6 -0
  260. package/src/memory/jobs-worker.ts +12 -0
  261. package/src/memory/llm-request-log-store.ts +100 -1
  262. package/src/memory/migrations/102-alter-table-columns.ts +5 -0
  263. package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
  264. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
  265. package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
  266. package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
  267. package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
  268. package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
  269. package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
  270. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
  271. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
  272. package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
  273. package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
  274. package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
  275. package/src/memory/migrations/185-memory-brief-state.ts +52 -0
  276. package/src/memory/migrations/186-memory-archive.ts +109 -0
  277. package/src/memory/migrations/187-memory-reducer-checkpoints.ts +19 -0
  278. package/src/memory/migrations/index.ts +10 -0
  279. package/src/memory/migrations/registry.ts +13 -0
  280. package/src/memory/qdrant-client.ts +23 -4
  281. package/src/memory/reducer-store.ts +271 -0
  282. package/src/memory/reducer-types.ts +99 -0
  283. package/src/memory/reducer.ts +453 -0
  284. package/src/memory/retriever.test.ts +601 -2
  285. package/src/memory/retriever.ts +85 -9
  286. package/src/memory/schema/conversations.ts +9 -0
  287. package/src/memory/schema/index.ts +2 -0
  288. package/src/memory/schema/infrastructure.ts +13 -7
  289. package/src/memory/schema/memory-archive.ts +121 -0
  290. package/src/memory/schema/memory-brief.ts +55 -0
  291. package/src/memory/schema/oauth.ts +6 -0
  292. package/src/memory/search/semantic.ts +17 -4
  293. package/src/messaging/providers/gmail/mime-builder.ts +3 -1
  294. package/src/notifications/copy-composer.ts +26 -0
  295. package/src/notifications/decision-engine.ts +14 -1
  296. package/src/notifications/emit-signal.ts +1 -1
  297. package/src/notifications/signal.ts +36 -0
  298. package/src/oauth/byo-connection.test.ts +1 -45
  299. package/src/oauth/byo-connection.ts +2 -8
  300. package/src/oauth/connect-orchestrator.ts +15 -11
  301. package/src/oauth/connection-resolver.test.ts +191 -0
  302. package/src/oauth/connection-resolver.ts +66 -38
  303. package/src/oauth/connection.ts +0 -1
  304. package/src/oauth/oauth-store.ts +99 -47
  305. package/src/oauth/platform-connection.test.ts +0 -1
  306. package/src/oauth/platform-connection.ts +11 -3
  307. package/src/oauth/seed-providers.ts +78 -3
  308. package/src/oauth/token-persistence.ts +16 -10
  309. package/src/permissions/checker.ts +160 -14
  310. package/src/permissions/defaults.ts +14 -0
  311. package/src/prompts/templates/BOOTSTRAP.md +2 -0
  312. package/src/providers/anthropic/client.ts +8 -1
  313. package/src/providers/failover.ts +4 -1
  314. package/src/providers/gemini/client.ts +50 -0
  315. package/src/providers/model-catalog.ts +92 -0
  316. package/src/providers/model-intents.ts +29 -20
  317. package/src/providers/openai/client.ts +49 -0
  318. package/src/providers/types.ts +2 -0
  319. package/src/runtime/access-request-helper.ts +16 -7
  320. package/src/runtime/auth/credential-service.ts +3 -1
  321. package/src/runtime/auth/route-policy.ts +14 -1
  322. package/src/runtime/btw-sidechain.ts +101 -0
  323. package/src/runtime/channel-reply-delivery.ts +17 -1
  324. package/src/runtime/http-router.ts +3 -1
  325. package/src/runtime/http-server.ts +196 -141
  326. package/src/runtime/http-types.ts +1 -0
  327. package/src/runtime/migrations/vbundle-builder.ts +5 -1
  328. package/src/runtime/routes/access-request-decision.ts +41 -0
  329. package/src/runtime/routes/app-management-routes.ts +6 -3
  330. package/src/runtime/routes/app-routes.ts +7 -3
  331. package/src/runtime/routes/approval-routes.ts +1 -0
  332. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
  333. package/src/runtime/routes/attachment-routes.ts +45 -15
  334. package/src/runtime/routes/btw-routes.ts +21 -61
  335. package/src/runtime/routes/conversation-management-routes.ts +74 -0
  336. package/src/runtime/routes/conversation-query-routes.ts +187 -10
  337. package/src/runtime/routes/conversation-routes.ts +269 -28
  338. package/src/runtime/routes/conversation-starter-routes.ts +9 -11
  339. package/src/runtime/routes/diagnostics-routes.ts +1 -0
  340. package/src/runtime/routes/identity-routes.ts +2 -35
  341. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
  342. package/src/runtime/routes/llm-context-normalization.ts +1212 -0
  343. package/src/runtime/routes/log-export-routes.ts +3 -0
  344. package/src/runtime/routes/memory-item-routes.test.ts +34 -0
  345. package/src/runtime/routes/memory-item-routes.ts +94 -5
  346. package/src/runtime/routes/migration-routes.ts +4 -1
  347. package/src/runtime/routes/oauth-apps.ts +291 -0
  348. package/src/runtime/routes/secret-routes.ts +30 -1
  349. package/src/runtime/routes/settings-routes.ts +14 -0
  350. package/src/runtime/routes/surface-action-routes.ts +68 -1
  351. package/src/runtime/routes/trace-event-routes.ts +4 -1
  352. package/src/schedule/schedule-store.ts +30 -21
  353. package/src/security/secure-keys.ts +21 -0
  354. package/src/signals/bash.ts +1 -1
  355. package/src/skills/inline-command-expansions.ts +204 -0
  356. package/src/skills/inline-command-render.ts +127 -0
  357. package/src/skills/inline-command-runner.ts +242 -0
  358. package/src/skills/transitive-version-hash.ts +88 -0
  359. package/src/swarm/backend-claude-code.ts +3 -6
  360. package/src/tasks/task-store.ts +43 -1
  361. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  362. package/src/telemetry/usage-telemetry-reporter.ts +3 -1
  363. package/src/tools/AGENTS.md +6 -10
  364. package/src/tools/apps/executors.ts +17 -232
  365. package/src/tools/claude-code/claude-code.ts +2 -3
  366. package/src/tools/credentials/vault.ts +7 -12
  367. package/src/tools/host-filesystem/read.ts +13 -10
  368. package/src/tools/network/__tests__/web-search.test.ts +4 -2
  369. package/src/tools/permission-checker.ts +8 -1
  370. package/src/tools/schedule/list.ts +2 -7
  371. package/src/tools/schema-transforms.ts +5 -0
  372. package/src/tools/shared/filesystem/format-diff.ts +2 -7
  373. package/src/tools/skills/execute.ts +1 -1
  374. package/src/tools/skills/load.ts +140 -6
  375. package/src/tools/tool-manifest.ts +0 -6
  376. package/src/tools/ui-surface/definitions.ts +2 -2
  377. package/src/util/device-id.ts +28 -5
  378. package/src/util/platform.ts +24 -0
  379. package/src/util/pricing.ts +1 -0
  380. package/src/util/retry.ts +1 -3
  381. package/src/workspace/migrations/003-seed-device-id.ts +3 -4
  382. package/src/workspace/migrations/006-services-config.ts +5 -0
  383. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
  384. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
  385. package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
  386. package/src/workspace/migrations/{002-backfill-installation-id.ts → 011-backfill-installation-id.ts} +24 -13
  387. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
  388. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
  389. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
  390. package/src/workspace/migrations/registry.ts +11 -1
  391. package/src/workspace/top-level-renderer.ts +12 -0
  392. package/src/__tests__/asset-materialize-tool.test.ts +0 -523
  393. package/src/__tests__/asset-search-tool.test.ts +0 -536
  394. package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
  395. package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
  396. package/src/__tests__/media-visibility-policy.test.ts +0 -190
  397. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
  398. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
  399. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
  400. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
  401. package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
  402. package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
  403. package/src/daemon/media-visibility-policy.ts +0 -59
  404. package/src/tools/assets/materialize.ts +0 -248
  405. package/src/tools/assets/search.ts +0 -400
@@ -0,0 +1,156 @@
1
+ import {
2
+ getConfig,
3
+ loadRawConfig,
4
+ saveRawConfig,
5
+ } from "../../config/loader.js";
6
+ import {
7
+ deleteMemoryEmbeddingField,
8
+ setMemoryEmbeddingField,
9
+ } from "../../config/raw-config-utils.js";
10
+ import { VALID_MEMORY_EMBEDDING_PROVIDERS } from "../../config/schemas/memory-storage.js";
11
+ import {
12
+ clearEmbeddingBackendCache,
13
+ getMemoryBackendStatus,
14
+ } from "../../memory/embedding-backend.js";
15
+ import type { ModelSetContext } from "./config-model.js";
16
+ import { CONFIG_RELOAD_DEBOUNCE_MS, log } from "./shared.js";
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Embedding provider catalog
20
+ // ---------------------------------------------------------------------------
21
+
22
+ const EMBEDDING_PROVIDER_CATALOG = [
23
+ {
24
+ id: "auto",
25
+ displayName: "Auto (Best Available)",
26
+ defaultModel: "",
27
+ requiresKey: false,
28
+ },
29
+ {
30
+ id: "local",
31
+ displayName: "Local (In-Process)",
32
+ defaultModel: "Xenova/bge-small-en-v1.5",
33
+ requiresKey: false,
34
+ },
35
+ {
36
+ id: "openai",
37
+ displayName: "OpenAI",
38
+ defaultModel: "text-embedding-3-small",
39
+ requiresKey: true,
40
+ },
41
+ {
42
+ id: "gemini",
43
+ displayName: "Gemini",
44
+ defaultModel: "gemini-embedding-2-preview",
45
+ requiresKey: true,
46
+ },
47
+ {
48
+ id: "ollama",
49
+ displayName: "Ollama",
50
+ defaultModel: "nomic-embed-text",
51
+ requiresKey: false,
52
+ },
53
+ ];
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Provider-specific model field names
57
+ // ---------------------------------------------------------------------------
58
+
59
+ const PROVIDER_MODEL_FIELD: Record<string, string> = {
60
+ local: "localModel",
61
+ openai: "openaiModel",
62
+ gemini: "geminiModel",
63
+ ollama: "ollamaModel",
64
+ };
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // GET — return current embedding config + resolved status
68
+ // ---------------------------------------------------------------------------
69
+
70
+ export async function getEmbeddingConfigInfo(): Promise<{
71
+ provider: string;
72
+ model: string | null;
73
+ activeProvider: string | null;
74
+ activeModel: string | null;
75
+ availableProviders: typeof EMBEDDING_PROVIDER_CATALOG;
76
+ status: { enabled: boolean; degraded: boolean; reason: string | null };
77
+ }> {
78
+ const config = getConfig();
79
+ const embeddingConfig = config.memory.embeddings;
80
+ const backendStatus = await getMemoryBackendStatus(config);
81
+
82
+ // Derive the provider-specific model from config
83
+ const fieldName = PROVIDER_MODEL_FIELD[embeddingConfig.provider];
84
+ const model = fieldName
85
+ ? (embeddingConfig as Record<string, unknown>)[fieldName]
86
+ : null;
87
+
88
+ return {
89
+ provider: embeddingConfig.provider,
90
+ model: typeof model === "string" ? model : null,
91
+ activeProvider: backendStatus.provider,
92
+ activeModel: backendStatus.model,
93
+ availableProviders: EMBEDDING_PROVIDER_CATALOG,
94
+ status: {
95
+ enabled: backendStatus.enabled,
96
+ degraded: backendStatus.degraded,
97
+ reason: backendStatus.reason,
98
+ },
99
+ };
100
+ }
101
+
102
+ // ---------------------------------------------------------------------------
103
+ // PUT — persist embedding provider/model to config
104
+ // ---------------------------------------------------------------------------
105
+
106
+ export async function setEmbeddingConfig(
107
+ provider: string,
108
+ model: string | undefined,
109
+ ctx: ModelSetContext,
110
+ ): Promise<ReturnType<typeof getEmbeddingConfigInfo>> {
111
+ const validProviders = new Set<string>(VALID_MEMORY_EMBEDDING_PROVIDERS);
112
+ if (!validProviders.has(provider)) {
113
+ throw new Error(
114
+ `Invalid embedding provider "${provider}". Valid providers: ${[...validProviders].join(", ")}`,
115
+ );
116
+ }
117
+
118
+ const raw = loadRawConfig();
119
+ setMemoryEmbeddingField(raw, "provider", provider);
120
+
121
+ if (model !== undefined) {
122
+ const fieldName = PROVIDER_MODEL_FIELD[provider];
123
+ if (fieldName) {
124
+ if (model === "") {
125
+ // Empty string means "clear override — use schema default"
126
+ deleteMemoryEmbeddingField(raw, fieldName);
127
+ } else {
128
+ setMemoryEmbeddingField(raw, fieldName, model);
129
+ }
130
+ }
131
+ }
132
+
133
+ // Suppress the file watcher callback — we handle the reload ourselves.
134
+ const wasSuppressed = ctx.suppressConfigReload;
135
+ ctx.setSuppressConfigReload(true);
136
+ try {
137
+ saveRawConfig(raw);
138
+ } catch (err) {
139
+ ctx.setSuppressConfigReload(wasSuppressed);
140
+ throw err;
141
+ }
142
+ ctx.debounceTimers.schedule(
143
+ "__suppress_reset__",
144
+ () => {
145
+ ctx.setSuppressConfigReload(false);
146
+ },
147
+ CONFIG_RELOAD_DEBOUNCE_MS,
148
+ );
149
+
150
+ clearEmbeddingBackendCache();
151
+ ctx.updateConfigFingerprint();
152
+
153
+ log.info({ provider, model }, "Embedding config updated");
154
+
155
+ return getEmbeddingConfigInfo();
156
+ }
@@ -4,12 +4,18 @@ import {
4
4
  saveRawConfig,
5
5
  } from "../../config/loader.js";
6
6
  import { setServiceField } from "../../config/raw-config-utils.js";
7
+ import { VALID_INFERENCE_PROVIDERS } from "../../config/schemas/services.js";
8
+ import type { ProviderCatalogEntry } from "../../providers/model-catalog.js";
9
+ import {
10
+ isModelInCatalog,
11
+ PROVIDER_CATALOG,
12
+ } from "../../providers/model-catalog.js";
13
+ import { getProviderDefaultModel } from "../../providers/model-intents.js";
7
14
  import {
8
15
  getConfiguredProviders,
9
16
  isProviderAvailable,
10
17
  } from "../../providers/provider-availability.js";
11
18
  import { initializeProviders } from "../../providers/registry.js";
12
- import { MODEL_TO_PROVIDER } from "../conversation-slash.js";
13
19
  import type {
14
20
  ImageGenModelSetRequest,
15
21
  ModelSetRequest,
@@ -20,6 +26,13 @@ import {
20
26
  log,
21
27
  } from "./shared.js";
22
28
 
29
+ /** Reverse lookup: model ID → provider, derived from PROVIDER_CATALOG. */
30
+ export const MODEL_TO_PROVIDER: Record<string, string> = Object.fromEntries(
31
+ PROVIDER_CATALOG.flatMap((provider) =>
32
+ provider.models.map(({ id }) => [id, provider.id]),
33
+ ),
34
+ );
35
+
23
36
  // ---------------------------------------------------------------------------
24
37
  // Shared business logic (transport-agnostic)
25
38
  // ---------------------------------------------------------------------------
@@ -28,15 +41,21 @@ export interface ModelInfo {
28
41
  model: string;
29
42
  provider: string;
30
43
  configuredProviders?: string[];
44
+ availableModels?: Array<{ id: string; displayName: string }>;
45
+ allProviders?: ProviderCatalogEntry[];
31
46
  }
32
47
 
33
48
  /** Return current model configuration. */
34
49
  export async function getModelInfo(): Promise<ModelInfo> {
35
50
  const config = getConfig();
51
+ const provider = config.services.inference.provider;
52
+
36
53
  return {
37
54
  model: config.services.inference.model,
38
- provider: config.services.inference.provider,
55
+ provider,
39
56
  configuredProviders: await getConfiguredProviders(),
57
+ availableModels: PROVIDER_CATALOG.find((p) => p.id === provider)?.models,
58
+ allProviders: PROVIDER_CATALOG,
40
59
  };
41
60
  }
42
61
 
@@ -58,28 +77,52 @@ export interface ModelSetContext {
58
77
  /**
59
78
  * Set the active model. Returns the resulting ModelInfo, or throws on failure.
60
79
  * The caller is responsible for sending the response to the client.
80
+ *
81
+ * When `explicitProvider` is supplied, it takes precedence over automatic
82
+ * provider inference from the model ID. If the provider changes and the
83
+ * current model doesn't belong to the new provider's catalog, the model
84
+ * is auto-reset to the provider's default.
61
85
  */
62
86
  export async function setModel(
63
87
  modelId: string,
64
88
  ctx: ModelSetContext,
89
+ explicitProvider?: string,
65
90
  ): Promise<ModelInfo> {
66
- // If the requested model is already the current model AND the provider
67
- // is already aligned with what MODEL_TO_PROVIDER expects, skip expensive
68
- // reinitialization but still return model_info so the client confirms.
69
- {
70
- const current = getConfig();
71
- const expectedProvider = MODEL_TO_PROVIDER[modelId];
72
- const providerAligned =
73
- !expectedProvider ||
74
- current.services.inference.provider === expectedProvider;
75
- if (modelId === current.services.inference.model && providerAligned) {
76
- return await getModelInfo();
77
- }
91
+ const validProviders = new Set<string>(VALID_INFERENCE_PROVIDERS);
92
+
93
+ // Validate explicit provider against allowlist
94
+ if (explicitProvider && !validProviders.has(explicitProvider)) {
95
+ throw new Error(
96
+ `Invalid provider "${explicitProvider}". Valid providers: ${[...validProviders].join(", ")}`,
97
+ );
98
+ }
99
+
100
+ // Resolve provider: explicit > MODEL_TO_PROVIDER lookup > current
101
+ const current = getConfig();
102
+ const resolvedProvider =
103
+ explicitProvider ??
104
+ MODEL_TO_PROVIDER[modelId] ??
105
+ current.services.inference.provider;
106
+
107
+ // Auto-reset model when provider changes and current modelId doesn't
108
+ // belong to the new provider's catalog.
109
+ if (
110
+ resolvedProvider !== current.services.inference.provider &&
111
+ !isModelInCatalog(resolvedProvider, modelId)
112
+ ) {
113
+ modelId = getProviderDefaultModel(resolvedProvider);
114
+ }
115
+
116
+ // No-op guard: skip expensive reinitialization when nothing changed
117
+ if (
118
+ modelId === current.services.inference.model &&
119
+ resolvedProvider === current.services.inference.provider
120
+ ) {
121
+ return await getModelInfo();
78
122
  }
79
123
 
80
124
  // Validate provider availability (secure key, env var, or managed proxy) before switching
81
- const provider = MODEL_TO_PROVIDER[modelId];
82
- if (provider && !(await isProviderAvailable(provider))) {
125
+ if (!(await isProviderAvailable(resolvedProvider))) {
83
126
  // Return current model_info so the client resyncs its optimistic state
84
127
  return await getModelInfo();
85
128
  }
@@ -87,10 +130,7 @@ export async function setModel(
87
130
  // Use raw config to avoid persisting env-var API keys to disk
88
131
  const raw = loadRawConfig();
89
132
  setServiceField(raw, "inference", "model", modelId);
90
- // Infer provider from model ID to keep provider and model in sync
91
- if (provider) {
92
- setServiceField(raw, "inference", "provider", provider);
93
- }
133
+ setServiceField(raw, "inference", "provider", resolvedProvider);
94
134
 
95
135
  // Suppress the file watcher callback — setModel already does
96
136
  // the full reload sequence; a redundant watcher-triggered reload
@@ -128,11 +168,7 @@ export async function setModel(
128
168
 
129
169
  ctx.updateConfigFingerprint();
130
170
 
131
- return {
132
- model: config.services.inference.model,
133
- provider: config.services.inference.provider,
134
- configuredProviders: await getConfiguredProviders(),
135
- };
171
+ return await getModelInfo();
136
172
  }
137
173
 
138
174
  /**
@@ -179,7 +215,7 @@ export async function handleModelSet(
179
215
  ctx: HandlerContext,
180
216
  ): Promise<void> {
181
217
  try {
182
- const info = await setModel(msg.model, ctx);
218
+ const info = await setModel(msg.model, ctx, msg.provider);
183
219
  ctx.send({ type: "model_info", ...info });
184
220
  } catch (err) {
185
221
  const message = err instanceof Error ? err.message : String(err);
@@ -9,7 +9,6 @@ import { getConfig } from "../../config/loader.js";
9
9
  import {
10
10
  createCanonicalGuardianRequest,
11
11
  generateCanonicalRequestCode,
12
- resolveCanonicalGuardianRequest,
13
12
  } from "../../memory/canonical-guardian-store.js";
14
13
  import {
15
14
  batchSetDisplayOrders,
@@ -50,27 +49,6 @@ import {
50
49
  pendingStandaloneSecrets,
51
50
  } from "./shared.js";
52
51
 
53
- export function syncCanonicalStatusFromConfirmationDecision(
54
- requestId: string,
55
- decision: ConfirmationResponse["decision"],
56
- ): void {
57
- const targetStatus =
58
- decision === "deny" || decision === "always_deny"
59
- ? ("denied" as const)
60
- : ("approved" as const);
61
-
62
- try {
63
- resolveCanonicalGuardianRequest(requestId, "pending", {
64
- status: targetStatus,
65
- });
66
- } catch (err) {
67
- log.debug(
68
- { err, requestId, targetStatus },
69
- "Failed to resolve canonical request from local confirmation response",
70
- );
71
- }
72
- }
73
-
74
52
  export function makeEventSender(params: {
75
53
  ctx: HandlerContext;
76
54
  conversation: Conversation;
@@ -165,7 +143,6 @@ export function handleConfirmationResponse(
165
143
  undefined,
166
144
  { source: "button" },
167
145
  );
168
- syncCanonicalStatusFromConfirmationDecision(msg.requestId, msg.decision);
169
146
  pendingInteractions.resolve(msg.requestId);
170
147
  return;
171
148
  }
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Returns true when the value is a template placeholder that should be treated
3
+ * as empty/unset. Placeholders follow the pattern `_(…)_`, e.g.
4
+ * `_(not yet chosen)_` or `_(not yet established)_`.
5
+ */
6
+ export function isTemplatePlaceholder(value: string): boolean {
7
+ return value.startsWith("_(") && value.endsWith(")_");
8
+ }
9
+
1
10
  export interface IdentityFields {
2
11
  name: string;
3
12
  role: string;
@@ -14,7 +23,9 @@ export function parseIdentityFields(content: string): IdentityFields {
14
23
  const lower = trimmed.toLowerCase();
15
24
  const extract = (prefix: string): string | null => {
16
25
  if (!lower.startsWith(prefix)) return null;
17
- return trimmed.split(":**").pop()?.trim() ?? null;
26
+ const value = trimmed.split(":**").pop()?.trim() ?? null;
27
+ if (value && isTemplatePlaceholder(value)) return null;
28
+ return value;
18
29
  };
19
30
 
20
31
  const name = extract("- **name:**");
@@ -4,10 +4,10 @@ import * as path from "node:path";
4
4
  import { v4 as uuid } from "uuid";
5
5
 
6
6
  import {
7
- linkAttachmentToMessage,
8
- uploadFileBackedAttachment,
7
+ attachFileBackedAttachmentToMessage,
9
8
  } from "../../memory/attachments-store.js";
10
- import { addMessage } from "../../memory/conversation-crud.js";
9
+ import { addMessage, getConversation } from "../../memory/conversation-crud.js";
10
+ import { syncMessageToDisk } from "../../memory/conversation-disk-view.js";
11
11
  import type { RecordingOptions, RecordingStatus } from "../message-protocol.js";
12
12
  import { type HandlerContext, log } from "./shared.js";
13
13
 
@@ -616,23 +616,6 @@ export async function finalizeAndPublishRecording(params: {
616
616
  const ext = filename.split(".").pop()?.toLowerCase();
617
617
  const mimeType = (ext && RECORDING_MIME_TYPES.get(ext)) || "video/mp4";
618
618
 
619
- // Store as file-backed attachment (avoids reading large files into memory)
620
- const attachment = uploadFileBackedAttachment(
621
- filename,
622
- mimeType,
623
- resolvedPath,
624
- sizeBytes,
625
- );
626
- log.info(
627
- {
628
- recordingId,
629
- attachmentId: attachment.id,
630
- sizeBytes,
631
- filePath: resolvedPath,
632
- },
633
- "Created attachment for standalone recording",
634
- );
635
-
636
619
  // Always create a new assistant message for the recording attachment.
637
620
  // Reusing the last assistant message would attach the recording to an
638
621
  // unrelated older message after reload.
@@ -648,12 +631,34 @@ export async function finalizeAndPublishRecording(params: {
648
631
  "Created assistant message for recording attachment",
649
632
  );
650
633
 
651
- linkAttachmentToMessage(messageId, attachment.id, 0);
634
+ const attachment = attachFileBackedAttachmentToMessage(
635
+ messageId,
636
+ 0,
637
+ filename,
638
+ mimeType,
639
+ resolvedPath,
640
+ sizeBytes,
641
+ );
642
+ log.info(
643
+ {
644
+ recordingId,
645
+ attachmentId: attachment.id,
646
+ sizeBytes,
647
+ filePath: resolvedPath,
648
+ },
649
+ "Created attachment for standalone recording",
650
+ );
652
651
  log.info(
653
652
  { recordingId, messageId, attachmentId: attachment.id },
654
653
  "Linked recording attachment to assistant message",
655
654
  );
656
655
 
656
+ // Sync the recording message (with attachment) to the disk view
657
+ const convForDisk = getConversation(conversationId);
658
+ if (convForDisk) {
659
+ syncMessageToDisk(conversationId, messageId, convForDisk.createdAt);
660
+ }
661
+
657
662
  // Skip server-side thumbnail generation for recordings — the client
658
663
  // generates thumbnails natively from the local file path using
659
664
  // AVAssetImageGenerator, which is faster and doesn't depend on ffmpeg.
@@ -10,6 +10,7 @@
10
10
  import { v4 as uuid } from "uuid";
11
11
 
12
12
  import { escapeAxTreeContent } from "../agent/loop.js";
13
+ import { loadConfig } from "../config/loader.js";
13
14
  import type { ContentBlock } from "../providers/types.js";
14
15
  import type { ToolExecutionResult } from "../tools/types.js";
15
16
  import { AssistantError, ErrorCode } from "../util/errors.js";
@@ -23,7 +24,6 @@ const log = getLogger("host-cu-proxy");
23
24
  // ---------------------------------------------------------------------------
24
25
 
25
26
  const REQUEST_TIMEOUT_SEC = 60;
26
- const MAX_STEPS = 50;
27
27
  const MAX_HISTORY_ENTRIES = 10;
28
28
  const LOOP_DETECTION_WINDOW = 3;
29
29
  const CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD = 2;
@@ -79,7 +79,7 @@ export class HostCuProxy {
79
79
  constructor(
80
80
  sendToClient: (msg: ServerMessage) => void,
81
81
  onInternalResolve?: (requestId: string) => void,
82
- maxSteps = MAX_STEPS,
82
+ maxSteps = loadConfig().maxStepsPerSession,
83
83
  ) {
84
84
  this.sendToClient = sendToClient;
85
85
  this.onInternalResolve = onInternalResolve;