@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,243 @@
1
+ import { mkdtempSync, realpathSync, 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
+ const testDir = realpathSync(
7
+ mkdtempSync(join(tmpdir(), "turn-boundary-resolution-test-")),
8
+ );
9
+ const workspaceDir = join(testDir, ".vellum", "workspace");
10
+ const conversationsDir = join(workspaceDir, "conversations");
11
+
12
+ mock.module("../util/platform.js", () => ({
13
+ getRootDir: () => join(testDir, ".vellum"),
14
+ getDataDir: () => join(workspaceDir, "data"),
15
+ getWorkspaceDir: () => workspaceDir,
16
+ getConversationsDir: () => conversationsDir,
17
+ isMacOS: () => process.platform === "darwin",
18
+ isLinux: () => process.platform === "linux",
19
+ isWindows: () => process.platform === "win32",
20
+ getPidPath: () => join(testDir, "test.pid"),
21
+ getDbPath: () => join(testDir, "test.db"),
22
+ getLogPath: () => join(testDir, "test.log"),
23
+ ensureDataDir: () => {},
24
+ }));
25
+
26
+ mock.module("../util/logger.js", () => ({
27
+ getLogger: () =>
28
+ new Proxy({} as Record<string, unknown>, {
29
+ get: () => () => {},
30
+ }),
31
+ }));
32
+
33
+ mock.module("../config/loader.js", () => ({
34
+ getConfig: () => ({
35
+ ui: {},
36
+ model: "test",
37
+ provider: "test",
38
+ memory: { enabled: false },
39
+ rateLimit: { maxRequestsPerMinute: 0 },
40
+ secretDetection: { enabled: false },
41
+ }),
42
+ }));
43
+
44
+ import {
45
+ addMessage,
46
+ createConversation,
47
+ getAssistantMessageIdsInTurn,
48
+ } from "../memory/conversation-crud.js";
49
+ import { getDb, initializeDb, resetDb } from "../memory/db.js";
50
+ import { llmRequestLogs, toolInvocations } from "../memory/schema.js";
51
+
52
+ initializeDb();
53
+
54
+ function resetTables(): void {
55
+ const db = getDb();
56
+ db.delete(llmRequestLogs).run();
57
+ db.delete(toolInvocations).run();
58
+ db.run("DELETE FROM message_attachments");
59
+ db.run("DELETE FROM attachments");
60
+ db.run("DELETE FROM messages");
61
+ db.run("DELETE FROM conversations");
62
+ }
63
+
64
+ function toolResultContent(toolUseIds: string[]): string {
65
+ return JSON.stringify(
66
+ toolUseIds.map((id) => ({
67
+ type: "tool_result",
68
+ tool_use_id: id,
69
+ content: "ok",
70
+ is_error: false,
71
+ })),
72
+ );
73
+ }
74
+
75
+ afterAll(() => {
76
+ resetDb();
77
+ try {
78
+ rmSync(testDir, { recursive: true, force: true });
79
+ } catch {
80
+ /* best effort */
81
+ }
82
+ });
83
+
84
+ describe("getAssistantMessageIdsInTurn", () => {
85
+ beforeEach(() => {
86
+ resetTables();
87
+ });
88
+
89
+ test("single-step turn: returns only the one assistant message", async () => {
90
+ const conv = createConversation("single-step");
91
+ await addMessage(conv.id, "user", "Hello", undefined, {
92
+ skipIndexing: true,
93
+ });
94
+ const a1 = await addMessage(conv.id, "assistant", "Hi there!", undefined, {
95
+ skipIndexing: true,
96
+ });
97
+
98
+ const result = getAssistantMessageIdsInTurn(a1.id);
99
+ expect(result).toEqual([a1.id]);
100
+ });
101
+
102
+ test("multi-step turn: user → A1 → tool_result → A2 → query A2 → returns [A1, A2]", async () => {
103
+ const conv = createConversation("multi-step");
104
+ await addMessage(conv.id, "user", "Do the thing", undefined, {
105
+ skipIndexing: true,
106
+ });
107
+ const a1 = await addMessage(
108
+ conv.id,
109
+ "assistant",
110
+ "Using tool...",
111
+ undefined,
112
+ { skipIndexing: true },
113
+ );
114
+ await addMessage(
115
+ conv.id,
116
+ "user",
117
+ toolResultContent(["tool-1"]),
118
+ undefined,
119
+ { skipIndexing: true },
120
+ );
121
+ const a2 = await addMessage(conv.id, "assistant", "Done!", undefined, {
122
+ skipIndexing: true,
123
+ });
124
+
125
+ const result = getAssistantMessageIdsInTurn(a2.id);
126
+ expect(result).toEqual([a1.id, a2.id]);
127
+ });
128
+
129
+ test("3-step turn: user → A1 → tool_result → A2 → tool_result → A3 → query A3 → returns [A1, A2, A3]", async () => {
130
+ const conv = createConversation("three-step");
131
+ await addMessage(conv.id, "user", "Complex task", undefined, {
132
+ skipIndexing: true,
133
+ });
134
+ const a1 = await addMessage(conv.id, "assistant", "Step 1...", undefined, {
135
+ skipIndexing: true,
136
+ });
137
+ await addMessage(
138
+ conv.id,
139
+ "user",
140
+ toolResultContent(["tool-1"]),
141
+ undefined,
142
+ { skipIndexing: true },
143
+ );
144
+ const a2 = await addMessage(conv.id, "assistant", "Step 2...", undefined, {
145
+ skipIndexing: true,
146
+ });
147
+ await addMessage(
148
+ conv.id,
149
+ "user",
150
+ toolResultContent(["tool-2"]),
151
+ undefined,
152
+ { skipIndexing: true },
153
+ );
154
+ const a3 = await addMessage(conv.id, "assistant", "All done!", undefined, {
155
+ skipIndexing: true,
156
+ });
157
+
158
+ const result = getAssistantMessageIdsInTurn(a3.id);
159
+ expect(result).toEqual([a1.id, a2.id, a3.id]);
160
+ });
161
+
162
+ test("query intermediate message: query A1 in a 2-step turn → returns [A1, A2]", async () => {
163
+ const conv = createConversation("intermediate");
164
+ await addMessage(conv.id, "user", "Start task", undefined, {
165
+ skipIndexing: true,
166
+ });
167
+ const a1 = await addMessage(
168
+ conv.id,
169
+ "assistant",
170
+ "Using tool...",
171
+ undefined,
172
+ { skipIndexing: true },
173
+ );
174
+ await addMessage(
175
+ conv.id,
176
+ "user",
177
+ toolResultContent(["tool-1"]),
178
+ undefined,
179
+ { skipIndexing: true },
180
+ );
181
+ const a2 = await addMessage(conv.id, "assistant", "Done!", undefined, {
182
+ skipIndexing: true,
183
+ });
184
+
185
+ const result = getAssistantMessageIdsInTurn(a1.id);
186
+ expect(result).toEqual([a1.id, a2.id]);
187
+ });
188
+
189
+ test("message not found: returns [messageId]", () => {
190
+ const result = getAssistantMessageIdsInTurn("nonexistent-id");
191
+ expect(result).toEqual(["nonexistent-id"]);
192
+ });
193
+
194
+ test("consecutive turns: query message in second turn → returns only that turn's messages", async () => {
195
+ const conv = createConversation("consecutive");
196
+
197
+ // First turn
198
+ await addMessage(conv.id, "user", "First question", undefined, {
199
+ skipIndexing: true,
200
+ });
201
+ const a1 = await addMessage(
202
+ conv.id,
203
+ "assistant",
204
+ "First answer",
205
+ undefined,
206
+ { skipIndexing: true },
207
+ );
208
+
209
+ // Second turn
210
+ await addMessage(conv.id, "user", "Second question", undefined, {
211
+ skipIndexing: true,
212
+ });
213
+ const a2 = await addMessage(
214
+ conv.id,
215
+ "assistant",
216
+ "Using tool...",
217
+ undefined,
218
+ { skipIndexing: true },
219
+ );
220
+ await addMessage(
221
+ conv.id,
222
+ "user",
223
+ toolResultContent(["tool-1"]),
224
+ undefined,
225
+ { skipIndexing: true },
226
+ );
227
+ const a3 = await addMessage(
228
+ conv.id,
229
+ "assistant",
230
+ "Done with second",
231
+ undefined,
232
+ { skipIndexing: true },
233
+ );
234
+
235
+ // Query second turn → should NOT include a1
236
+ const result = getAssistantMessageIdsInTurn(a3.id);
237
+ expect(result).toEqual([a2.id, a3.id]);
238
+
239
+ // Query first turn → should only include a1
240
+ const firstTurnResult = getAssistantMessageIdsInTurn(a1.id);
241
+ expect(firstTurnResult).toEqual([a1.id]);
242
+ });
243
+ });
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Tests that vellum-self-knowledge uses inline command expansion to inject
3
+ * the current assistant info at skill_load time.
4
+ *
5
+ * Validates that:
6
+ * - The `!\`bun run .../self-info.ts\`` token in SKILL.md is replaced by an
7
+ * `<inline_skill_command>` block containing the runner's output.
8
+ * - The rest of the skill body (architecture, config, references, critical rule)
9
+ * remains unchanged.
10
+ * - The inline command token does NOT appear verbatim in the loaded output
11
+ * (i.e. the model is never told to shell out manually).
12
+ */
13
+
14
+ import {
15
+ copyFileSync,
16
+ existsSync,
17
+ mkdirSync,
18
+ mkdtempSync,
19
+ rmSync,
20
+ } from "node:fs";
21
+ import { tmpdir } from "node:os";
22
+ import { join } from "node:path";
23
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
24
+
25
+ // ── Paths ──────────────────────────────────────────────────────────────────
26
+
27
+ const TEST_DIR = mkdtempSync(
28
+ join(tmpdir(), "vellum-self-knowledge-inline-test-"),
29
+ );
30
+
31
+ /** Resolve the real skill directory so we can copy SKILL.md into the test. */
32
+ const SKILL_SRC_DIR = join(
33
+ import.meta.dirname ?? __dirname,
34
+ "..",
35
+ "..",
36
+ "..",
37
+ "skills",
38
+ "vellum-self-knowledge",
39
+ );
40
+
41
+ // ── Mocks (must be declared before any imports from the project) ──────────
42
+
43
+ const platformOverrides: Record<string, (...args: unknown[]) => unknown> = {
44
+ getRootDir: () => TEST_DIR,
45
+ getDataDir: () => join(TEST_DIR, "data"),
46
+ ensureDataDir: () => {},
47
+ getPidPath: () => join(TEST_DIR, "vellum.pid"),
48
+ getDbPath: () => join(TEST_DIR, "data", "assistant.db"),
49
+ getLogPath: () => join(TEST_DIR, "logs", "vellum.log"),
50
+ getWorkspaceDir: () => join(TEST_DIR, "workspace"),
51
+ getWorkspaceSkillsDir: () => join(TEST_DIR, "skills"),
52
+ getWorkspaceConfigPath: () => join(TEST_DIR, "workspace", "config.json"),
53
+ getWorkspaceHooksDir: () => join(TEST_DIR, "workspace", "hooks"),
54
+ getWorkspacePromptPath: (f: unknown) =>
55
+ join(TEST_DIR, "workspace", String(f)),
56
+ getInterfacesDir: () => join(TEST_DIR, "interfaces"),
57
+ getHooksDir: () => join(TEST_DIR, "hooks"),
58
+ getSandboxRootDir: () => join(TEST_DIR, "sandbox"),
59
+ getSandboxWorkingDir: () => join(TEST_DIR, "sandbox", "work"),
60
+ getHistoryPath: () => join(TEST_DIR, "history"),
61
+ getSessionTokenPath: () => join(TEST_DIR, "session-token"),
62
+ readSessionToken: () => null,
63
+ getClipboardCommand: () => null,
64
+ readLockfile: () => null,
65
+ normalizeAssistantId: (id: unknown) => String(id),
66
+ writeLockfile: () => {},
67
+ getEmbeddingModelsDir: () => join(TEST_DIR, "embedding-models"),
68
+ getTCPPort: () => 8765,
69
+ isTCPEnabled: () => false,
70
+ getTCPHost: () => "127.0.0.1",
71
+ isIOSPairingEnabled: () => false,
72
+ getPlatformTokenPath: () => join(TEST_DIR, "platform-token"),
73
+ readPlatformToken: () => null,
74
+ isMacOS: () => process.platform === "darwin",
75
+ isLinux: () => process.platform === "linux",
76
+ isWindows: () => process.platform === "win32",
77
+ getPlatformName: () => process.platform,
78
+ getWorkspaceDirDisplay: () => "~/.vellum/workspace",
79
+ getConversationsDir: () => join(TEST_DIR, "conversations"),
80
+ };
81
+ mock.module("../util/platform.js", () => platformOverrides);
82
+
83
+ mock.module("../util/logger.js", () => ({
84
+ getLogger: () =>
85
+ new Proxy({} as Record<string, unknown>, {
86
+ get: () => () => {},
87
+ }),
88
+ truncateForLog: (s: unknown) => String(s),
89
+ }));
90
+
91
+ // Track inline command runner calls
92
+ interface RunInlineCommandCall {
93
+ command: string;
94
+ workingDir: string;
95
+ }
96
+ const runInlineCommandCalls: RunInlineCommandCall[] = [];
97
+
98
+ /** Return type matching InlineCommandResult from the runner module. */
99
+ interface MockInlineCommandResult {
100
+ output: string;
101
+ ok: boolean;
102
+ failureReason?:
103
+ | "timeout"
104
+ | "non_zero_exit"
105
+ | "binary_output"
106
+ | "spawn_failure";
107
+ }
108
+
109
+ type MockRunFn = (
110
+ command: string,
111
+ workingDir: string,
112
+ ) => Promise<MockInlineCommandResult>;
113
+
114
+ // Default: commands succeed, returning a realistic self-info summary
115
+ const MOCK_SELF_INFO_OUTPUT =
116
+ "You are running as Claude Opus 4.6 via Anthropic (your-own API key).";
117
+
118
+ let mockRunInlineCommand = mock<MockRunFn>(
119
+ (command: string, workingDir: string) => {
120
+ runInlineCommandCalls.push({ command, workingDir });
121
+ return Promise.resolve({
122
+ output: MOCK_SELF_INFO_OUTPUT,
123
+ ok: true,
124
+ });
125
+ },
126
+ );
127
+
128
+ mock.module("../skills/inline-command-runner.js", () => ({
129
+ runInlineCommand: (command: string, workingDir: string, _options?: unknown) =>
130
+ mockRunInlineCommand(command, workingDir),
131
+ }));
132
+
133
+ // Mock autoInstallFromCatalog
134
+ const mockAutoInstall = mock((_skillId: string) => Promise.resolve(false));
135
+ mock.module("../skills/catalog-install.js", () => ({
136
+ autoInstallFromCatalog: (skillId: string) => mockAutoInstall(skillId),
137
+ resolveCatalog: (_skillId?: string) => Promise.resolve([]),
138
+ }));
139
+
140
+ interface TestConfig {
141
+ permissions: { mode: "strict" | "workspace" };
142
+ skills: { load: { extraDirs: string[] } };
143
+ sandbox: { enabled: boolean };
144
+ assistantFeatureFlagValues?: Record<string, boolean>;
145
+ [key: string]: unknown;
146
+ }
147
+
148
+ const testConfig: TestConfig = {
149
+ permissions: { mode: "workspace" },
150
+ skills: { load: { extraDirs: [] } },
151
+ sandbox: { enabled: true },
152
+ assistantFeatureFlagValues: {
153
+ "feature_flags.inline-skill-commands.enabled": true,
154
+ },
155
+ };
156
+
157
+ mock.module("../config/loader.js", () => ({
158
+ getConfig: () => testConfig,
159
+ loadConfig: () => testConfig,
160
+ invalidateConfigCache: () => {},
161
+ saveConfig: () => {},
162
+ loadRawConfig: () => ({}),
163
+ saveRawConfig: () => {},
164
+ getNestedValue: () => undefined,
165
+ setNestedValue: () => {},
166
+ }));
167
+
168
+ // ── Imports (after mocks) ────────────────────────────────────────────────
169
+
170
+ await import("../tools/skills/load.js");
171
+ const { getTool } = await import("../tools/registry.js");
172
+
173
+ // ── Helpers ──────────────────────────────────────────────────────────────
174
+
175
+ /** Copy the real vellum-self-knowledge SKILL.md into the test skills dir. */
176
+ function installSelfKnowledgeSkill(): void {
177
+ const destDir = join(TEST_DIR, "skills", "vellum-self-knowledge");
178
+ mkdirSync(destDir, { recursive: true });
179
+ copyFileSync(join(SKILL_SRC_DIR, "SKILL.md"), join(destDir, "SKILL.md"));
180
+ // Also copy references/ so that the reference listing still works
181
+ const refsSrc = join(SKILL_SRC_DIR, "references");
182
+ if (existsSync(refsSrc)) {
183
+ const refsDir = join(destDir, "references");
184
+ mkdirSync(refsDir, { recursive: true });
185
+ copyFileSync(join(refsSrc, "inference.md"), join(refsDir, "inference.md"));
186
+ }
187
+ }
188
+
189
+ async function executeSkillLoad(
190
+ input: Record<string, unknown>,
191
+ workingDir = "/tmp",
192
+ ): Promise<{ content: string; isError: boolean }> {
193
+ const tool = getTool("skill_load");
194
+ if (!tool) throw new Error("skill_load tool was not registered");
195
+
196
+ const result = await tool.execute(input, {
197
+ workingDir,
198
+ conversationId: "conversation-1",
199
+ trustClass: "guardian",
200
+ });
201
+ return { content: result.content, isError: result.isError };
202
+ }
203
+
204
+ // ── Tests ────────────────────────────────────────────────────────────────
205
+
206
+ describe("vellum-self-knowledge inline command expansion", () => {
207
+ beforeEach(() => {
208
+ mkdirSync(join(TEST_DIR, "skills"), { recursive: true });
209
+ runInlineCommandCalls.length = 0;
210
+ mockAutoInstall.mockReset();
211
+ mockAutoInstall.mockImplementation(() => Promise.resolve(false));
212
+
213
+ // Reset to default: commands succeed with self-info output
214
+ mockRunInlineCommand = mock<MockRunFn>(
215
+ (command: string, workingDir: string) => {
216
+ runInlineCommandCalls.push({ command, workingDir });
217
+ return Promise.resolve({
218
+ output: MOCK_SELF_INFO_OUTPUT,
219
+ ok: true,
220
+ });
221
+ },
222
+ );
223
+ mock.module("../skills/inline-command-runner.js", () => ({
224
+ runInlineCommand: (
225
+ command: string,
226
+ workingDir: string,
227
+ _options?: unknown,
228
+ ) => mockRunInlineCommand(command, workingDir),
229
+ }));
230
+
231
+ // Enable the feature flag
232
+ testConfig.assistantFeatureFlagValues = {
233
+ "feature_flags.inline-skill-commands.enabled": true,
234
+ };
235
+ testConfig.skills = { load: { extraDirs: [] } };
236
+
237
+ installSelfKnowledgeSkill();
238
+ });
239
+
240
+ afterEach(() => {
241
+ if (existsSync(TEST_DIR)) {
242
+ rmSync(TEST_DIR, { recursive: true, force: true });
243
+ }
244
+ });
245
+
246
+ // ── Inline token replacement ─────────────────────────────────────────
247
+
248
+ test("inline token is replaced by an <inline_skill_command> block", async () => {
249
+ const result = await executeSkillLoad({ skill: "vellum-self-knowledge" });
250
+ expect(result.isError).toBe(false);
251
+ expect(result.content).toContain(
252
+ `<inline_skill_command index="0">${MOCK_SELF_INFO_OUTPUT}</inline_skill_command>`,
253
+ );
254
+ });
255
+
256
+ test("the raw inline token does not appear in the loaded output", async () => {
257
+ const result = await executeSkillLoad({ skill: "vellum-self-knowledge" });
258
+ expect(result.isError).toBe(false);
259
+ // The original `!\`...\`` token must be fully replaced
260
+ expect(result.content).not.toContain("!`bun run");
261
+ expect(result.content).not.toContain("scripts/self-info.ts`");
262
+ });
263
+
264
+ test("the model is not told to shell out manually", async () => {
265
+ const result = await executeSkillLoad({ skill: "vellum-self-knowledge" });
266
+ expect(result.isError).toBe(false);
267
+ // The old instruction "Always run this script" should be gone
268
+ expect(result.content).not.toContain("Always run this script");
269
+ // No code block instructing manual execution
270
+ expect(result.content).not.toContain("```bash\nbun run");
271
+ });
272
+
273
+ // ── Runner invocation ────────────────────────────────────────────────
274
+
275
+ test("invokes the inline command runner with the self-info script command", async () => {
276
+ await executeSkillLoad({ skill: "vellum-self-knowledge" });
277
+ expect(runInlineCommandCalls).toHaveLength(1);
278
+ expect(runInlineCommandCalls[0].command).toContain("bun run");
279
+ expect(runInlineCommandCalls[0].command).toContain("scripts/self-info.ts");
280
+ });
281
+
282
+ // ── Rest of skill body preserved ─────────────────────────────────────
283
+
284
+ test("architecture section is preserved", async () => {
285
+ const result = await executeSkillLoad({ skill: "vellum-self-knowledge" });
286
+ expect(result.isError).toBe(false);
287
+ expect(result.content).toContain("## Architecture at a Glance");
288
+ expect(result.content).toContain("AgentLoop");
289
+ });
290
+
291
+ test("configuration section is preserved", async () => {
292
+ const result = await executeSkillLoad({ skill: "vellum-self-knowledge" });
293
+ expect(result.isError).toBe(false);
294
+ expect(result.content).toContain("## Configuration System");
295
+ expect(result.content).toContain("assistant config get");
296
+ });
297
+
298
+ test("references section is preserved", async () => {
299
+ const result = await executeSkillLoad({ skill: "vellum-self-knowledge" });
300
+ expect(result.isError).toBe(false);
301
+ expect(result.content).toContain("## When to Consult References");
302
+ expect(result.content).toContain("references/inference.md");
303
+ });
304
+
305
+ test("critical rule section is preserved", async () => {
306
+ const result = await executeSkillLoad({ skill: "vellum-self-knowledge" });
307
+ expect(result.isError).toBe(false);
308
+ expect(result.content).toContain("## Critical Rule");
309
+ expect(result.content).toContain(
310
+ "populated at skill-load time and reflects the live configuration",
311
+ );
312
+ });
313
+
314
+ test("what is vellum section is preserved", async () => {
315
+ const result = await executeSkillLoad({ skill: "vellum-self-knowledge" });
316
+ expect(result.isError).toBe(false);
317
+ expect(result.content).toContain("## What is Vellum");
318
+ expect(result.content).toContain("personal AI assistant platform");
319
+ });
320
+ });
@@ -1641,7 +1641,9 @@ describe("web_fetch tool", () => {
1641
1641
  );
1642
1642
 
1643
1643
  expect(result.isError).toBe(false);
1644
- expect(result.content).not.toContain("Extracted text content is very short");
1644
+ expect(result.content).not.toContain(
1645
+ "Extracted text content is very short",
1646
+ );
1645
1647
  });
1646
1648
 
1647
1649
  test("does not suggest JS rendering notice in raw mode even for sparse HTML", async () => {
@@ -1660,6 +1662,8 @@ describe("web_fetch tool", () => {
1660
1662
  );
1661
1663
 
1662
1664
  expect(result.isError).toBe(false);
1663
- expect(result.content).not.toContain("Extracted text content is very short");
1665
+ expect(result.content).not.toContain(
1666
+ "Extracted text content is very short",
1667
+ );
1664
1668
  });
1665
1669
  });