@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
@@ -1,523 +0,0 @@
1
- import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
5
-
6
- import { RiskLevel } from "../permissions/types.js";
7
-
8
- const testDir = mkdtempSync(join(tmpdir(), "asset-materialize-test-"));
9
- const sandboxDir = join(testDir, "sandbox");
10
-
11
- mock.module("../util/platform.js", () => ({
12
- getDataDir: () => testDir,
13
- isMacOS: () => process.platform === "darwin",
14
- isLinux: () => process.platform === "linux",
15
- isWindows: () => process.platform === "win32",
16
- getPidPath: () => join(testDir, "test.pid"),
17
- getDbPath: () => join(testDir, "test.db"),
18
- getLogPath: () => join(testDir, "test.log"),
19
- ensureDataDir: () => {},
20
- getRootDir: () => testDir,
21
- }));
22
-
23
- mock.module("../util/logger.js", () => ({
24
- getLogger: () =>
25
- new Proxy({} as Record<string, unknown>, {
26
- get: () => () => {},
27
- }),
28
- }));
29
-
30
- mock.module("../config/loader.js", () => ({
31
- getConfig: () => ({
32
- ui: {},
33
-
34
- model: "test",
35
- provider: "test",
36
- memory: { enabled: false },
37
- rateLimit: { maxRequestsPerMinute: 0 },
38
- }),
39
- }));
40
-
41
- import {
42
- linkAttachmentToMessage,
43
- uploadAttachment,
44
- } from "../memory/attachments-store.js";
45
- import { addMessage, createConversation } from "../memory/conversation-crud.js";
46
- import { getDb, initializeDb, resetDb } from "../memory/db.js";
47
- import { assetMaterializeTool } from "../tools/assets/materialize.js";
48
- import type { ToolContext } from "../tools/types.js";
49
-
50
- initializeDb();
51
-
52
- // Ensure the sandbox directory exists
53
- import { mkdirSync } from "node:fs";
54
- mkdirSync(sandboxDir, { recursive: true });
55
-
56
- afterAll(() => {
57
- resetDb();
58
- try {
59
- rmSync(testDir, { recursive: true });
60
- } catch {
61
- /* best effort */
62
- }
63
- });
64
-
65
- function resetTables() {
66
- const db = getDb();
67
- db.run("DELETE FROM message_attachments");
68
- db.run("DELETE FROM attachments");
69
- db.run("DELETE FROM messages");
70
- db.run("DELETE FROM conversations");
71
- }
72
-
73
- const dummyContext: ToolContext = {
74
- workingDir: sandboxDir,
75
- conversationId: "conv-test",
76
- trustClass: "guardian",
77
- };
78
-
79
- // ---------------------------------------------------------------------------
80
- // Input validation
81
- // ---------------------------------------------------------------------------
82
-
83
- describe("AssetMaterializeTool input validation", () => {
84
- test("returns error when attachment_id is missing", async () => {
85
- const result = await assetMaterializeTool.execute(
86
- { destination_path: "output.png" },
87
- dummyContext,
88
- );
89
- expect(result.isError).toBe(true);
90
- expect(result.content).toContain("attachment_id is required");
91
- });
92
-
93
- test("returns error when destination_path is missing", async () => {
94
- const result = await assetMaterializeTool.execute(
95
- { attachment_id: "some-id" },
96
- dummyContext,
97
- );
98
- expect(result.isError).toBe(true);
99
- expect(result.content).toContain("destination_path is required");
100
- });
101
-
102
- test("returns error when both params are missing", async () => {
103
- const result = await assetMaterializeTool.execute({}, dummyContext);
104
- expect(result.isError).toBe(true);
105
- });
106
- });
107
-
108
- // ---------------------------------------------------------------------------
109
- // Sandbox path enforcement
110
- // ---------------------------------------------------------------------------
111
-
112
- describe("AssetMaterializeTool sandbox path enforcement", () => {
113
- beforeEach(resetTables);
114
-
115
- test("rejects path that escapes sandbox via ../", async () => {
116
- const stored = uploadAttachment("test.png", "image/png", "AAAA");
117
- const result = await assetMaterializeTool.execute(
118
- { attachment_id: stored.id, destination_path: "../../etc/evil.png" },
119
- dummyContext,
120
- );
121
- expect(result.isError).toBe(true);
122
- expect(result.content).toContain("outside");
123
- });
124
-
125
- test("rejects absolute path outside sandbox", async () => {
126
- const stored = uploadAttachment("test.png", "image/png", "AAAA");
127
- const result = await assetMaterializeTool.execute(
128
- {
129
- attachment_id: stored.id,
130
- destination_path: "/tmp/outside-sandbox/evil.png",
131
- },
132
- dummyContext,
133
- );
134
- expect(result.isError).toBe(true);
135
- expect(result.content).toContain("outside");
136
- });
137
-
138
- test("accepts relative path inside sandbox", async () => {
139
- const stored = uploadAttachment("test.png", "image/png", "AAAA");
140
- const result = await assetMaterializeTool.execute(
141
- { attachment_id: stored.id, destination_path: "output.png" },
142
- dummyContext,
143
- );
144
- expect(result.isError).toBe(false);
145
- expect(result.content).toContain("Materialized");
146
- });
147
-
148
- test("accepts nested path inside sandbox with auto-created subdirs", async () => {
149
- const stored = uploadAttachment("test.png", "image/png", "AAAA");
150
- const result = await assetMaterializeTool.execute(
151
- { attachment_id: stored.id, destination_path: "subdir/deep/output.png" },
152
- dummyContext,
153
- );
154
- expect(result.isError).toBe(false);
155
- expect(existsSync(join(sandboxDir, "subdir", "deep", "output.png"))).toBe(
156
- true,
157
- );
158
- });
159
- });
160
-
161
- // ---------------------------------------------------------------------------
162
- // Attachment lookup
163
- // ---------------------------------------------------------------------------
164
-
165
- describe("AssetMaterializeTool attachment lookup", () => {
166
- beforeEach(resetTables);
167
-
168
- test("returns error for non-existent attachment ID", async () => {
169
- const result = await assetMaterializeTool.execute(
170
- { attachment_id: "nonexistent-id", destination_path: "out.png" },
171
- dummyContext,
172
- );
173
- expect(result.isError).toBe(true);
174
- expect(result.content).toContain("not found");
175
- });
176
- });
177
-
178
- // ---------------------------------------------------------------------------
179
- // Successful materialization
180
- // ---------------------------------------------------------------------------
181
-
182
- describe("AssetMaterializeTool materialization", () => {
183
- beforeEach(resetTables);
184
-
185
- test("writes correct binary content to disk", async () => {
186
- // Create known content: "Hello, World!" in base64
187
- const originalContent = "Hello, World!";
188
- const base64Content = Buffer.from(originalContent).toString("base64");
189
-
190
- const stored = uploadAttachment("hello.txt", "text/plain", base64Content);
191
-
192
- const destPath = "materialized-hello.txt";
193
- const result = await assetMaterializeTool.execute(
194
- { attachment_id: stored.id, destination_path: destPath },
195
- dummyContext,
196
- );
197
-
198
- expect(result.isError).toBe(false);
199
- expect(result.content).toContain("Materialized");
200
- expect(result.content).toContain("hello.txt");
201
- expect(result.content).toContain("text/plain");
202
-
203
- const writtenContent = readFileSync(join(sandboxDir, destPath), "utf-8");
204
- expect(writtenContent).toBe(originalContent);
205
- });
206
-
207
- test("writes binary (image) content correctly", async () => {
208
- // Small valid PNG-like bytes encoded as base64
209
- const binaryBytes = Buffer.from([
210
- 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
211
- ]);
212
- const base64Content = binaryBytes.toString("base64");
213
-
214
- const stored = uploadAttachment("tiny.png", "image/png", base64Content);
215
-
216
- const result = await assetMaterializeTool.execute(
217
- { attachment_id: stored.id, destination_path: "images/tiny.png" },
218
- dummyContext,
219
- );
220
-
221
- expect(result.isError).toBe(false);
222
-
223
- const writtenBytes = readFileSync(join(sandboxDir, "images", "tiny.png"));
224
- expect(Buffer.compare(writtenBytes, binaryBytes)).toBe(0);
225
- });
226
-
227
- test("result includes resolved path", async () => {
228
- const base64Content = Buffer.from("test").toString("base64");
229
- const stored = uploadAttachment("doc.txt", "text/plain", base64Content);
230
-
231
- const result = await assetMaterializeTool.execute(
232
- { attachment_id: stored.id, destination_path: "output/doc.txt" },
233
- dummyContext,
234
- );
235
-
236
- expect(result.isError).toBe(false);
237
- expect(result.content).toContain(join(sandboxDir, "output", "doc.txt"));
238
- });
239
-
240
- test("result includes filename, MIME type and size info", async () => {
241
- const base64Content = Buffer.from("some data here").toString("base64");
242
- const stored = uploadAttachment(
243
- "report.pdf",
244
- "application/pdf",
245
- base64Content,
246
- );
247
-
248
- const result = await assetMaterializeTool.execute(
249
- { attachment_id: stored.id, destination_path: "report.pdf" },
250
- dummyContext,
251
- );
252
-
253
- expect(result.isError).toBe(false);
254
- expect(result.content).toContain("report.pdf");
255
- expect(result.content).toContain("application/pdf");
256
- });
257
- });
258
-
259
- // ---------------------------------------------------------------------------
260
- // Size limit enforcement
261
- // ---------------------------------------------------------------------------
262
-
263
- describe("AssetMaterializeTool size limit", () => {
264
- beforeEach(resetTables);
265
-
266
- test("rejects attachment exceeding 100MB limit", async () => {
267
- // Simulate a large attachment by inserting directly into the DB
268
- // with a sizeBytes value over the limit
269
- const db = getDb();
270
- const fakeId = "oversized-attachment";
271
- db.run(
272
- `INSERT INTO attachments (id, original_filename, mime_type, size_bytes, kind, data_base64, created_at)
273
- VALUES ('${fakeId}', 'huge.bin', 'application/octet-stream', ${
274
- 101 * 1024 * 1024
275
- }, 'document', 'AAAA', ${Date.now()})`,
276
- );
277
-
278
- const result = await assetMaterializeTool.execute(
279
- { attachment_id: fakeId, destination_path: "huge.bin" },
280
- dummyContext,
281
- );
282
-
283
- expect(result.isError).toBe(true);
284
- expect(result.content).toContain("exceeds");
285
- expect(result.content).toContain("materialization limit");
286
- });
287
- });
288
-
289
- // ---------------------------------------------------------------------------
290
- // Tool metadata
291
- // ---------------------------------------------------------------------------
292
-
293
- describe("AssetMaterializeTool metadata", () => {
294
- test("tool definition has correct name", () => {
295
- const def = assetMaterializeTool.getDefinition();
296
- expect(def.name).toBe("asset_materialize");
297
- });
298
-
299
- test("tool definition has required params", () => {
300
- const def = assetMaterializeTool.getDefinition();
301
- expect((def.input_schema as Record<string, unknown>).required).toEqual([
302
- "attachment_id",
303
- "destination_path",
304
- ]);
305
- });
306
-
307
- test("tool definition has attachment_id and destination_path properties", () => {
308
- const def = assetMaterializeTool.getDefinition();
309
- expect(
310
- (def.input_schema as Record<string, unknown>).properties,
311
- ).toHaveProperty("attachment_id");
312
- expect(
313
- (def.input_schema as Record<string, unknown>).properties,
314
- ).toHaveProperty("destination_path");
315
- });
316
-
317
- test("tool has LOW risk level", () => {
318
- expect(assetMaterializeTool.defaultRiskLevel).toBe(RiskLevel.Low);
319
- });
320
-
321
- test("tool category is assets", () => {
322
- expect(assetMaterializeTool.category).toBe("assets");
323
- });
324
-
325
- test("tool name is asset_materialize", () => {
326
- expect(assetMaterializeTool.name).toBe("asset_materialize");
327
- });
328
- });
329
-
330
- // ---------------------------------------------------------------------------
331
- // Visibility policy enforcement
332
- // ---------------------------------------------------------------------------
333
-
334
- describe("AssetMaterializeTool visibility policy", () => {
335
- beforeEach(resetTables);
336
-
337
- test("materializing from a standard thread works from any context", async () => {
338
- const standardConv = createConversation({ title: "standard-conv" });
339
- const base64Content = Buffer.from("standard content").toString("base64");
340
- const attachment = uploadAttachment(
341
- "public.txt",
342
- "text/plain",
343
- base64Content,
344
- );
345
- const msg = await addMessage(standardConv.id, "user", "standard message");
346
- linkAttachmentToMessage(msg.id, attachment.id, 0);
347
-
348
- // Materialize from a different standard conversation
349
- const otherConv = createConversation({ title: "other-conv" });
350
- const context: ToolContext = {
351
- workingDir: sandboxDir,
352
- conversationId: otherConv.id,
353
- trustClass: "guardian",
354
- };
355
-
356
- const result = await assetMaterializeTool.execute(
357
- { attachment_id: attachment.id, destination_path: "public-output.txt" },
358
- context,
359
- );
360
- expect(result.isError).toBe(false);
361
- expect(result.content).toContain("Materialized");
362
- });
363
-
364
- test("materializing from a private thread works within the same private thread", async () => {
365
- const privateConv = createConversation({
366
- title: "private-conv",
367
- conversationType: "private",
368
- });
369
- const base64Content = Buffer.from("private content").toString("base64");
370
- const attachment = uploadAttachment(
371
- "secret.txt",
372
- "text/plain",
373
- base64Content,
374
- );
375
- const msg = await addMessage(privateConv.id, "user", "private message");
376
- linkAttachmentToMessage(msg.id, attachment.id, 0);
377
-
378
- // Materialize from the same private conversation
379
- const context: ToolContext = {
380
- workingDir: sandboxDir,
381
- conversationId: privateConv.id,
382
- trustClass: "guardian",
383
- };
384
-
385
- const result = await assetMaterializeTool.execute(
386
- { attachment_id: attachment.id, destination_path: "private-output.txt" },
387
- context,
388
- );
389
- expect(result.isError).toBe(false);
390
- expect(result.content).toContain("Materialized");
391
- });
392
-
393
- test("materializing from a private thread is REJECTED from a different conversation", async () => {
394
- const privateConv = createConversation({
395
- title: "private-conv",
396
- conversationType: "private",
397
- });
398
- const base64Content = Buffer.from("private content").toString("base64");
399
- const attachment = uploadAttachment(
400
- "secret.txt",
401
- "text/plain",
402
- base64Content,
403
- );
404
- const msg = await addMessage(privateConv.id, "user", "private message");
405
- linkAttachmentToMessage(msg.id, attachment.id, 0);
406
-
407
- // Attempt to materialize from a different conversation
408
- const otherConv = createConversation({ title: "other-conv" });
409
- const context: ToolContext = {
410
- workingDir: sandboxDir,
411
- conversationId: otherConv.id,
412
- trustClass: "guardian",
413
- };
414
-
415
- const result = await assetMaterializeTool.execute(
416
- { attachment_id: attachment.id, destination_path: "stolen.txt" },
417
- context,
418
- );
419
- expect(result.isError).toBe(true);
420
- expect(result.content).toContain("private conversation");
421
- expect(result.content).toContain("cannot be accessed");
422
- });
423
-
424
- test("error message is user-actionable", async () => {
425
- const privateConv = createConversation({
426
- title: "private-conv",
427
- conversationType: "private",
428
- });
429
- const base64Content = Buffer.from("private content").toString("base64");
430
- const attachment = uploadAttachment(
431
- "confidential.pdf",
432
- "application/pdf",
433
- base64Content,
434
- );
435
- const msg = await addMessage(privateConv.id, "user", "private message");
436
- linkAttachmentToMessage(msg.id, attachment.id, 0);
437
-
438
- // From a standard conversation
439
- const standardConv = createConversation({ title: "standard-conv" });
440
- const context: ToolContext = {
441
- workingDir: sandboxDir,
442
- conversationId: standardConv.id,
443
- trustClass: "guardian",
444
- };
445
-
446
- const result = await assetMaterializeTool.execute(
447
- { attachment_id: attachment.id, destination_path: "stolen.pdf" },
448
- context,
449
- );
450
- expect(result.isError).toBe(true);
451
- // Should mention the filename so the user knows which file
452
- expect(result.content).toContain("confidential.pdf");
453
- // Should explain how to access it
454
- expect(result.content).toContain("from within the private conversation");
455
- });
456
-
457
- test("materializing from a different private thread is REJECTED", async () => {
458
- const privateConv1 = createConversation({
459
- title: "private-conv-1",
460
- conversationType: "private",
461
- });
462
- const base64Content = Buffer.from("private content").toString("base64");
463
- const attachment = uploadAttachment(
464
- "secret.txt",
465
- "text/plain",
466
- base64Content,
467
- );
468
- const msg = await addMessage(privateConv1.id, "user", "private message");
469
- linkAttachmentToMessage(msg.id, attachment.id, 0);
470
-
471
- // Attempt from a different private conversation
472
- const privateConv2 = createConversation({
473
- title: "private-conv-2",
474
- conversationType: "private",
475
- });
476
- const context: ToolContext = {
477
- workingDir: sandboxDir,
478
- conversationId: privateConv2.id,
479
- trustClass: "guardian",
480
- };
481
-
482
- const result = await assetMaterializeTool.execute(
483
- { attachment_id: attachment.id, destination_path: "cross-thread.txt" },
484
- context,
485
- );
486
- expect(result.isError).toBe(true);
487
- expect(result.content).toContain("private conversation");
488
- });
489
-
490
- test("attachment linked to both private and standard threads can be materialized from anywhere", async () => {
491
- const privateConv = createConversation({
492
- title: "private-conv",
493
- conversationType: "private",
494
- });
495
- const standardConv = createConversation({ title: "standard-conv" });
496
- const base64Content = Buffer.from("shared content").toString("base64");
497
- const attachment = uploadAttachment(
498
- "shared.txt",
499
- "text/plain",
500
- base64Content,
501
- );
502
-
503
- const msg1 = await addMessage(privateConv.id, "user", "private message");
504
- const msg2 = await addMessage(standardConv.id, "user", "standard message");
505
- linkAttachmentToMessage(msg1.id, attachment.id, 0);
506
- linkAttachmentToMessage(msg2.id, attachment.id, 0);
507
-
508
- // Should be materializable from a third, unrelated standard conversation
509
- const otherConv = createConversation({ title: "other-conv" });
510
- const context: ToolContext = {
511
- workingDir: sandboxDir,
512
- conversationId: otherConv.id,
513
- trustClass: "guardian",
514
- };
515
-
516
- const result = await assetMaterializeTool.execute(
517
- { attachment_id: attachment.id, destination_path: "shared-output.txt" },
518
- context,
519
- );
520
- expect(result.isError).toBe(false);
521
- expect(result.content).toContain("Materialized");
522
- });
523
- });