@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,536 +0,0 @@
1
- import { mkdtempSync, 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-search-test-"));
9
-
10
- mock.module("../util/platform.js", () => ({
11
- getDataDir: () => testDir,
12
- isMacOS: () => process.platform === "darwin",
13
- isLinux: () => process.platform === "linux",
14
- isWindows: () => process.platform === "win32",
15
- getPidPath: () => join(testDir, "test.pid"),
16
- getDbPath: () => join(testDir, "test.db"),
17
- getLogPath: () => join(testDir, "test.log"),
18
- ensureDataDir: () => {},
19
- getRootDir: () => testDir,
20
- }));
21
-
22
- mock.module("../util/logger.js", () => ({
23
- getLogger: () =>
24
- new Proxy({} as Record<string, unknown>, {
25
- get: () => () => {},
26
- }),
27
- }));
28
-
29
- mock.module("../config/loader.js", () => ({
30
- getConfig: () => ({
31
- ui: {},
32
-
33
- model: "test",
34
- provider: "test",
35
- memory: { enabled: false },
36
- rateLimit: { maxRequestsPerMinute: 0 },
37
- }),
38
- }));
39
-
40
- import {
41
- linkAttachmentToMessage,
42
- uploadAttachment,
43
- } from "../memory/attachments-store.js";
44
- import { addMessage, createConversation } from "../memory/conversation-crud.js";
45
- import { getDb, initializeDb, resetDb } from "../memory/db.js";
46
- import { searchAttachments } from "../tools/assets/search.js";
47
- import { assetSearchTool } from "../tools/assets/search.js";
48
- import type { ToolContext } from "../tools/types.js";
49
-
50
- initializeDb();
51
-
52
- afterAll(() => {
53
- resetDb();
54
- try {
55
- rmSync(testDir, { recursive: true });
56
- } catch {
57
- /* best effort */
58
- }
59
- });
60
-
61
- function resetTables() {
62
- const db = getDb();
63
- db.run("DELETE FROM message_attachments");
64
- db.run("DELETE FROM attachments");
65
- db.run("DELETE FROM messages");
66
- db.run("DELETE FROM conversations");
67
- }
68
-
69
- // Seed data helpers
70
- function seedAttachments() {
71
- const now = Date.now();
72
- const oneDayAgo = now - 24 * 60 * 60 * 1000 - 1000;
73
- const tenDaysAgo = now - 10 * 24 * 60 * 60 * 1000;
74
- const sixtyDaysAgo = now - 60 * 24 * 60 * 60 * 1000;
75
-
76
- // Force createdAt by uploading then manipulating the DB
77
- const db = getDb();
78
-
79
- const png1 = uploadAttachment("selfie.png", "image/png", "AAAA");
80
- const jpg1 = uploadAttachment("photo.jpg", "image/jpeg", "BBBB");
81
- const pdf1 = uploadAttachment("report.pdf", "application/pdf", "CCCC");
82
- const png2 = uploadAttachment("screenshot.png", "image/png", "DDDD");
83
-
84
- // Backdate some attachments for recency testing
85
- db.run(
86
- `UPDATE attachments SET created_at = ${oneDayAgo} WHERE id = '${jpg1.id}'`,
87
- );
88
- db.run(
89
- `UPDATE attachments SET created_at = ${tenDaysAgo} WHERE id = '${pdf1.id}'`,
90
- );
91
- db.run(
92
- `UPDATE attachments SET created_at = ${sixtyDaysAgo} WHERE id = '${png2.id}'`,
93
- );
94
-
95
- return { png1, jpg1, pdf1, png2, now, oneDayAgo, tenDaysAgo, sixtyDaysAgo };
96
- }
97
-
98
- const dummyContext: ToolContext = {
99
- workingDir: "/tmp",
100
- conversationId: "conv-test",
101
- trustClass: "guardian",
102
- };
103
-
104
- // ---------------------------------------------------------------------------
105
- // searchAttachments (unit tests on the query function)
106
- // ---------------------------------------------------------------------------
107
-
108
- describe("searchAttachments", () => {
109
- beforeEach(resetTables);
110
-
111
- test("returns all attachments when no filters provided", () => {
112
- seedAttachments();
113
- const results = searchAttachments({});
114
- expect(results.length).toBe(4);
115
- });
116
-
117
- test("filters by exact MIME type", () => {
118
- seedAttachments();
119
- const results = searchAttachments({ mime_type: "application/pdf" });
120
- expect(results.length).toBe(1);
121
- expect(results[0].mimeType).toBe("application/pdf");
122
- });
123
-
124
- test("filters by MIME type wildcard (image/*)", () => {
125
- seedAttachments();
126
- const results = searchAttachments({ mime_type: "image/*" });
127
- expect(results.length).toBe(3);
128
- for (const r of results) {
129
- expect(r.mimeType.startsWith("image/")).toBe(true);
130
- }
131
- });
132
-
133
- test("filters by filename substring", () => {
134
- seedAttachments();
135
- const results = searchAttachments({ filename: "selfie" });
136
- expect(results.length).toBe(1);
137
- expect(results[0].originalFilename).toBe("selfie.png");
138
- });
139
-
140
- test("filename search is case-insensitive via LIKE", () => {
141
- seedAttachments();
142
- // SQLite LIKE is case-insensitive for ASCII by default
143
- const results = searchAttachments({ filename: "SELFIE" });
144
- expect(results.length).toBe(1);
145
- });
146
-
147
- test("filters by recency: last_24_hours", () => {
148
- seedAttachments();
149
- const results = searchAttachments({ recency: "last_24_hours" });
150
- // Only selfie.png was uploaded "now" (not backdated past 24h)
151
- expect(results.length).toBe(1);
152
- expect(results[0].originalFilename).toBe("selfie.png");
153
- });
154
-
155
- test("filters by recency: last_7_days", () => {
156
- seedAttachments();
157
- const results = searchAttachments({ recency: "last_7_days" });
158
- // selfie.png (now) and photo.jpg (1 day ago)
159
- expect(results.length).toBe(2);
160
- });
161
-
162
- test("filters by recency: last_30_days", () => {
163
- seedAttachments();
164
- const results = searchAttachments({ recency: "last_30_days" });
165
- // selfie.png (now), photo.jpg (1 day ago), report.pdf (10 days ago)
166
- expect(results.length).toBe(3);
167
- });
168
-
169
- test("filters by recency: last_90_days", () => {
170
- seedAttachments();
171
- const results = searchAttachments({ recency: "last_90_days" });
172
- // All 4 attachments are within 90 days
173
- expect(results.length).toBe(4);
174
- });
175
-
176
- test("combines mime_type and filename filters", () => {
177
- seedAttachments();
178
- const results = searchAttachments({
179
- mime_type: "image/*",
180
- filename: "selfie",
181
- });
182
- expect(results.length).toBe(1);
183
- expect(results[0].originalFilename).toBe("selfie.png");
184
- });
185
-
186
- test("combines mime_type and recency filters", () => {
187
- seedAttachments();
188
- const results = searchAttachments({
189
- mime_type: "image/*",
190
- recency: "last_24_hours",
191
- });
192
- expect(results.length).toBe(1);
193
- expect(results[0].originalFilename).toBe("selfie.png");
194
- });
195
-
196
- test("respects limit parameter", () => {
197
- seedAttachments();
198
- const results = searchAttachments({ limit: 2 });
199
- expect(results.length).toBe(2);
200
- });
201
-
202
- test("caps limit at MAX_RESULTS (100)", () => {
203
- seedAttachments();
204
- const results = searchAttachments({ limit: 500 });
205
- // We only have 4 attachments so we just verify it doesn't error
206
- expect(results.length).toBe(4);
207
- });
208
-
209
- test("returns results ordered by createdAt desc (most recent first)", () => {
210
- seedAttachments();
211
- const results = searchAttachments({});
212
- // selfie.png is most recent (now), then photo.jpg (1 day ago), etc.
213
- expect(results[0].originalFilename).toBe("selfie.png");
214
- for (let i = 1; i < results.length; i++) {
215
- expect(results[i - 1].createdAt).toBeGreaterThanOrEqual(
216
- results[i].createdAt,
217
- );
218
- }
219
- });
220
-
221
- test("returns empty array when no matches", () => {
222
- seedAttachments();
223
- const results = searchAttachments({ filename: "nonexistent" });
224
- expect(results.length).toBe(0);
225
- });
226
-
227
- test("does not return base64 data in results", () => {
228
- seedAttachments();
229
- const results = searchAttachments({}) as unknown as Array<
230
- Record<string, unknown>
231
- >;
232
- for (const r of results) {
233
- expect(r.dataBase64).toBeUndefined();
234
- }
235
- });
236
- });
237
-
238
- // ---------------------------------------------------------------------------
239
- // searchAttachments with conversation_id
240
- // ---------------------------------------------------------------------------
241
-
242
- describe("searchAttachments with conversation_id", () => {
243
- beforeEach(resetTables);
244
-
245
- test("returns only attachments linked to the specified conversation", async () => {
246
- const png1 = uploadAttachment("in-conv.png", "image/png", "AAAA");
247
- const png2 = uploadAttachment("other-conv.png", "image/png", "BBBB");
248
-
249
- const conv1 = createConversation();
250
- const conv2 = createConversation();
251
- const msg1 = await addMessage(conv1.id, "user", "First conv");
252
- const msg2 = await addMessage(conv2.id, "user", "Second conv");
253
-
254
- linkAttachmentToMessage(msg1.id, png1.id, 0);
255
- linkAttachmentToMessage(msg2.id, png2.id, 0);
256
-
257
- const results = searchAttachments({ conversation_id: conv1.id });
258
- expect(results.length).toBe(1);
259
- expect(results[0].id).toBe(png1.id);
260
- });
261
-
262
- test("returns empty when conversation has no attachments", async () => {
263
- uploadAttachment("orphan.png", "image/png", "AAAA");
264
- const conv = createConversation();
265
- await addMessage(conv.id, "user", "No attachments here");
266
-
267
- const results = searchAttachments({ conversation_id: conv.id });
268
- expect(results.length).toBe(0);
269
- });
270
-
271
- test("returns empty for nonexistent conversation_id", () => {
272
- uploadAttachment("file.png", "image/png", "AAAA");
273
- const results = searchAttachments({ conversation_id: "conv-nonexistent" });
274
- expect(results.length).toBe(0);
275
- });
276
-
277
- test("combines conversation_id with mime_type filter", async () => {
278
- const png = uploadAttachment("image.png", "image/png", "AAAA");
279
- const pdf = uploadAttachment("doc.pdf", "application/pdf", "BBBB");
280
-
281
- const conv = createConversation();
282
- const msg = await addMessage(conv.id, "user", "Both types");
283
-
284
- linkAttachmentToMessage(msg.id, png.id, 0);
285
- linkAttachmentToMessage(msg.id, pdf.id, 1);
286
-
287
- const results = searchAttachments({
288
- conversation_id: conv.id,
289
- mime_type: "image/*",
290
- });
291
- expect(results.length).toBe(1);
292
- expect(results[0].mimeType).toBe("image/png");
293
- });
294
-
295
- test("combines conversation_id with filename filter", async () => {
296
- const a = uploadAttachment("target.png", "image/png", "AAAA");
297
- const b = uploadAttachment("other.png", "image/png", "BBBB");
298
-
299
- const conv = createConversation();
300
- const msg = await addMessage(conv.id, "user", "Both");
301
-
302
- linkAttachmentToMessage(msg.id, a.id, 0);
303
- linkAttachmentToMessage(msg.id, b.id, 1);
304
-
305
- const results = searchAttachments({
306
- conversation_id: conv.id,
307
- filename: "target",
308
- });
309
- expect(results.length).toBe(1);
310
- expect(results[0].originalFilename).toBe("target.png");
311
- });
312
- });
313
-
314
- // ---------------------------------------------------------------------------
315
- // AssetSearchTool.execute (integration test via tool interface)
316
- // ---------------------------------------------------------------------------
317
-
318
- describe("AssetSearchTool.execute", () => {
319
- beforeEach(resetTables);
320
-
321
- // Import the tool instance
322
- let tool: import("../tools/types.js").Tool;
323
- beforeEach(async () => {
324
- const mod = await import("../tools/assets/search.js");
325
- tool = mod.assetSearchTool;
326
- });
327
-
328
- test("returns formatted results for matching assets", async () => {
329
- uploadAttachment("selfie.png", "image/png", "AAAA");
330
- const result = await tool.execute({}, dummyContext);
331
- expect(result.isError).toBe(false);
332
- expect(result.content).toContain("selfie.png");
333
- expect(result.content).toContain("Found 1 asset(s)");
334
- });
335
-
336
- test("returns no-match message when nothing found", async () => {
337
- const result = await tool.execute(
338
- { filename: "nonexistent" },
339
- dummyContext,
340
- );
341
- expect(result.isError).toBe(false);
342
- expect(result.content).toContain("No assets found");
343
- });
344
-
345
- test("returns error for invalid recency value", async () => {
346
- const result = await tool.execute({ recency: "last_year" }, dummyContext);
347
- expect(result.isError).toBe(true);
348
- expect(result.content).toContain("Invalid recency value");
349
- });
350
-
351
- test("returns error for invalid limit", async () => {
352
- const result = await tool.execute({ limit: -1 }, dummyContext);
353
- expect(result.isError).toBe(true);
354
- expect(result.content).toContain("limit must be a positive number");
355
- });
356
-
357
- test("includes attachment ID in output", async () => {
358
- const stored = uploadAttachment("chart.png", "image/png", "AAAA");
359
- const result = await tool.execute({}, dummyContext);
360
- expect(result.isError).toBe(false);
361
- expect(result.content).toContain(stored.id);
362
- });
363
-
364
- test("includes MIME type and kind in output", async () => {
365
- uploadAttachment("chart.png", "image/png", "AAAA");
366
- const result = await tool.execute({}, dummyContext);
367
- expect(result.isError).toBe(false);
368
- expect(result.content).toContain("image/png");
369
- expect(result.content).toContain("image");
370
- });
371
-
372
- test("tool definition has correct name and schema", () => {
373
- const def = tool.getDefinition();
374
- expect(def.name).toBe("asset_search");
375
- expect(
376
- (def.input_schema as Record<string, unknown>).properties,
377
- ).toHaveProperty("mime_type");
378
- expect(
379
- (def.input_schema as Record<string, unknown>).properties,
380
- ).toHaveProperty("filename");
381
- expect(
382
- (def.input_schema as Record<string, unknown>).properties,
383
- ).toHaveProperty("recency");
384
- expect(
385
- (def.input_schema as Record<string, unknown>).properties,
386
- ).toHaveProperty("conversation_id");
387
- expect(
388
- (def.input_schema as Record<string, unknown>).properties,
389
- ).toHaveProperty("limit");
390
- expect((def.input_schema as Record<string, unknown>).required).toEqual([]);
391
- });
392
-
393
- test("tool has LOW risk level", () => {
394
- expect(tool.defaultRiskLevel).toBe(RiskLevel.Low);
395
- });
396
-
397
- test("tool category is assets", () => {
398
- expect(tool.category).toBe("assets");
399
- });
400
- });
401
-
402
- // ---------------------------------------------------------------------------
403
- // Visibility policy enforcement
404
- // ---------------------------------------------------------------------------
405
-
406
- describe("AssetSearchTool visibility policy", () => {
407
- beforeEach(resetTables);
408
-
409
- test("attachments from standard threads are visible from any context", async () => {
410
- const standardConv = createConversation({ title: "standard-conv" });
411
- const attachment = uploadAttachment("public.png", "image/png", "AAAA");
412
- const msg = await addMessage(standardConv.id, "user", "standard message");
413
- linkAttachmentToMessage(msg.id, attachment.id, 0);
414
-
415
- // Search from a different standard conversation
416
- const otherConv = createConversation({ title: "other-conv" });
417
- const context: ToolContext = {
418
- workingDir: "/tmp",
419
- conversationId: otherConv.id,
420
- trustClass: "guardian",
421
- };
422
-
423
- const result = await assetSearchTool.execute({}, context);
424
- expect(result.isError).toBe(false);
425
- expect(result.content).toContain("public.png");
426
- });
427
-
428
- test("attachments from private threads are visible within the same private thread", async () => {
429
- const privateConv = createConversation({
430
- title: "private-conv",
431
- conversationType: "private",
432
- });
433
- const attachment = uploadAttachment("secret.png", "image/png", "AAAA");
434
- const msg = await addMessage(privateConv.id, "user", "private message");
435
- linkAttachmentToMessage(msg.id, attachment.id, 0);
436
-
437
- // Search from the same private conversation
438
- const context: ToolContext = {
439
- workingDir: "/tmp",
440
- conversationId: privateConv.id,
441
- trustClass: "guardian",
442
- };
443
-
444
- const result = await assetSearchTool.execute({}, context);
445
- expect(result.isError).toBe(false);
446
- expect(result.content).toContain("secret.png");
447
- });
448
-
449
- test("attachments from private threads are NOT visible from a different conversation", async () => {
450
- const privateConv = createConversation({
451
- title: "private-conv",
452
- conversationType: "private",
453
- });
454
- const attachment = uploadAttachment("secret.png", "image/png", "AAAA");
455
- const msg = await addMessage(privateConv.id, "user", "private message");
456
- linkAttachmentToMessage(msg.id, attachment.id, 0);
457
-
458
- // Search from a different private conversation
459
- const otherPrivateConv = createConversation({
460
- title: "other-private",
461
- conversationType: "private",
462
- });
463
- const context: ToolContext = {
464
- workingDir: "/tmp",
465
- conversationId: otherPrivateConv.id,
466
- trustClass: "guardian",
467
- };
468
-
469
- const result = await assetSearchTool.execute({}, context);
470
- expect(result.isError).toBe(false);
471
- expect(result.content).toContain("No assets found");
472
- });
473
-
474
- test("attachments from private threads are NOT visible from standard threads", async () => {
475
- const privateConv = createConversation({
476
- title: "private-conv",
477
- conversationType: "private",
478
- });
479
- const attachment = uploadAttachment("secret.png", "image/png", "AAAA");
480
- const msg = await addMessage(privateConv.id, "user", "private message");
481
- linkAttachmentToMessage(msg.id, attachment.id, 0);
482
-
483
- // Search from a standard conversation
484
- const standardConv = createConversation({ title: "standard-conv" });
485
- const context: ToolContext = {
486
- workingDir: "/tmp",
487
- conversationId: standardConv.id,
488
- trustClass: "guardian",
489
- };
490
-
491
- const result = await assetSearchTool.execute({}, context);
492
- expect(result.isError).toBe(false);
493
- expect(result.content).toContain("No assets found");
494
- });
495
-
496
- test("attachment linked to both private and standard threads is visible everywhere", async () => {
497
- const privateConv = createConversation({
498
- title: "private-conv",
499
- conversationType: "private",
500
- });
501
- const standardConv = createConversation({ title: "standard-conv" });
502
- const attachment = uploadAttachment("shared.png", "image/png", "AAAA");
503
-
504
- const msg1 = await addMessage(privateConv.id, "user", "private message");
505
- const msg2 = await addMessage(standardConv.id, "user", "standard message");
506
- linkAttachmentToMessage(msg1.id, attachment.id, 0);
507
- linkAttachmentToMessage(msg2.id, attachment.id, 0);
508
-
509
- // Should be visible from a third, unrelated standard conversation
510
- const otherConv = createConversation({ title: "other-conv" });
511
- const context: ToolContext = {
512
- workingDir: "/tmp",
513
- conversationId: otherConv.id,
514
- trustClass: "guardian",
515
- };
516
-
517
- const result = await assetSearchTool.execute({}, context);
518
- expect(result.isError).toBe(false);
519
- expect(result.content).toContain("shared.png");
520
- });
521
-
522
- test("orphan attachments (no message linkage) remain visible", async () => {
523
- uploadAttachment("orphan.png", "image/png", "AAAA");
524
-
525
- const conv = createConversation({ title: "any-conv" });
526
- const context: ToolContext = {
527
- workingDir: "/tmp",
528
- conversationId: conv.id,
529
- trustClass: "guardian",
530
- };
531
-
532
- const result = await assetSearchTool.execute({}, context);
533
- expect(result.isError).toBe(false);
534
- expect(result.content).toContain("orphan.png");
535
- });
536
- });
@@ -1,56 +0,0 @@
1
- /**
2
- * Shared fixtures for media-reuse testing.
3
- *
4
- * Provides deterministic attachment blobs and approval response helpers
5
- * used by the proxy and asset tool test suites.
6
- */
7
-
8
- import type { StoredAttachment } from "../../memory/attachments-store.js";
9
- import type { UserDecision } from "../../permissions/types.js";
10
-
11
- // ---------------------------------------------------------------------------
12
- // Fake attachment data
13
- // ---------------------------------------------------------------------------
14
-
15
- /** A tiny 1x1 red PNG pixel, base64-encoded. */
16
- export const TINY_PNG_BASE64 =
17
- "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
18
-
19
- // ---------------------------------------------------------------------------
20
- // Deterministic attachment records
21
- // ---------------------------------------------------------------------------
22
-
23
- const NOW = 1700000000000;
24
-
25
- /** A fake selfie image attachment with deterministic IDs. */
26
- export const FAKE_SELFIE_ATTACHMENT: StoredAttachment = {
27
- id: "att-selfie-001",
28
- originalFilename: "selfie.png",
29
- mimeType: "image/png",
30
- sizeBytes: Buffer.from(TINY_PNG_BASE64, "base64").length,
31
- kind: "image",
32
- thumbnailBase64: null,
33
- createdAt: NOW,
34
- };
35
-
36
- // ---------------------------------------------------------------------------
37
- // Approval response helpers
38
- // ---------------------------------------------------------------------------
39
-
40
- interface FakeApprovalResponse {
41
- decision: UserDecision;
42
- /** Pattern for "always allow" decisions (undefined for one-shot allow/deny). */
43
- pattern?: string;
44
- /** Scope prefix for trust rule creation. */
45
- scope?: string;
46
- }
47
-
48
- /** Returns a one-shot allow decision. */
49
- export function fakeAllowOnce(): FakeApprovalResponse {
50
- return { decision: "allow" };
51
- }
52
-
53
- /** Returns a deny decision. */
54
- export function fakeDeny(): FakeApprovalResponse {
55
- return { decision: "deny" };
56
- }