@vellumai/assistant 0.5.1 → 0.5.2

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 (338) hide show
  1. package/ARCHITECTURE.md +54 -54
  2. package/docs/architecture/integrations.md +62 -67
  3. package/docs/credential-execution-service.md +3 -3
  4. package/package.json +1 -1
  5. package/src/__tests__/agent-loop.test.ts +111 -0
  6. package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
  7. package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
  8. package/src/__tests__/app-dir-path-guard.test.ts +78 -0
  9. package/src/__tests__/app-executors.test.ts +1 -291
  10. package/src/__tests__/app-git-history.test.ts +4 -4
  11. package/src/__tests__/app-routes-csp.test.ts +1 -0
  12. package/src/__tests__/app-store-dir-names.test.ts +426 -0
  13. package/src/__tests__/attachments-store.test.ts +169 -21
  14. package/src/__tests__/attachments.test.ts +115 -1
  15. package/src/__tests__/btw-routes.test.ts +1 -0
  16. package/src/__tests__/canonical-guardian-store.test.ts +38 -0
  17. package/src/__tests__/channel-reply-delivery.test.ts +55 -0
  18. package/src/__tests__/checker.test.ts +54 -0
  19. package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
  20. package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
  21. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  22. package/src/__tests__/config-schema-cmd.test.ts +68 -21
  23. package/src/__tests__/config-schema.test.ts +1 -1
  24. package/src/__tests__/conversation-agent-loop-overflow.test.ts +149 -5
  25. package/src/__tests__/conversation-agent-loop.test.ts +290 -2
  26. package/src/__tests__/conversation-attachments.test.ts +17 -19
  27. package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
  28. package/src/__tests__/conversation-disk-view.test.ts +810 -0
  29. package/src/__tests__/conversation-error.test.ts +1 -1
  30. package/src/__tests__/conversation-fork-crud.test.ts +551 -0
  31. package/src/__tests__/conversation-fork-route.test.ts +386 -0
  32. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  33. package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
  34. package/src/__tests__/conversation-media-retry.test.ts +8 -2
  35. package/src/__tests__/conversation-queue.test.ts +36 -1
  36. package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
  37. package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
  38. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
  39. package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
  40. package/src/__tests__/conversation-skill-tools.test.ts +4 -9
  41. package/src/__tests__/conversation-slash-commands.test.ts +149 -0
  42. package/src/__tests__/conversation-store.test.ts +24 -21
  43. package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
  44. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
  45. package/src/__tests__/conversation-title-service.test.ts +137 -0
  46. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
  47. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
  48. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
  49. package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
  50. package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
  51. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  52. package/src/__tests__/credential-vault-unit.test.ts +5 -10
  53. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  54. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
  55. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
  56. package/src/__tests__/diagnostics-export.test.ts +70 -1
  57. package/src/__tests__/first-greeting.test.ts +80 -0
  58. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  59. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
  60. package/src/__tests__/history-repair.test.ts +32 -10
  61. package/src/__tests__/http-conversation-lineage.test.ts +251 -0
  62. package/src/__tests__/image-source-path-reinject.test.ts +136 -0
  63. package/src/__tests__/llm-context-normalization.test.ts +1116 -0
  64. package/src/__tests__/llm-context-route-provider.test.ts +217 -0
  65. package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
  66. package/src/__tests__/media-generate-image.test.ts +47 -94
  67. package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
  68. package/src/__tests__/memory-recall-quality.test.ts +5 -5
  69. package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
  70. package/src/__tests__/migration-export-http.test.ts +3 -1
  71. package/src/__tests__/migration-import-commit-http.test.ts +18 -4
  72. package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
  73. package/src/__tests__/mime-builder.test.ts +3 -2
  74. package/src/__tests__/non-member-access-request.test.ts +12 -1
  75. package/src/__tests__/notification-decision-identity.test.ts +52 -0
  76. package/src/__tests__/oauth-apps-routes.test.ts +103 -0
  77. package/src/__tests__/oauth-store.test.ts +115 -0
  78. package/src/__tests__/provider-error-scenarios.test.ts +1 -3
  79. package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
  80. package/src/__tests__/recording-handler.test.ts +17 -0
  81. package/src/__tests__/registry.test.ts +3 -8
  82. package/src/__tests__/relay-server.test.ts +1 -1
  83. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
  84. package/src/__tests__/schema-transforms.test.ts +165 -5
  85. package/src/__tests__/server-history-render.test.ts +2 -2
  86. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  87. package/src/__tests__/slack-inbound-verification.test.ts +2 -2
  88. package/src/__tests__/starter-task-flow.test.ts +1 -0
  89. package/src/__tests__/suggestion-routes.test.ts +443 -0
  90. package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
  91. package/src/__tests__/swarm-recursion.test.ts +1 -0
  92. package/src/__tests__/swarm-tool.test.ts +1 -0
  93. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
  94. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
  95. package/src/__tests__/top-level-renderer.test.ts +22 -0
  96. package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
  97. package/src/__tests__/web-fetch.test.ts +6 -2
  98. package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
  99. package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
  100. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
  101. package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
  102. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
  103. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
  104. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
  105. package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
  106. package/src/agent/attachments.ts +27 -1
  107. package/src/agent/loop.ts +29 -1
  108. package/src/avatar/traits-png-sync.ts +80 -25
  109. package/src/bundler/app-bundler.ts +4 -4
  110. package/src/calls/call-domain.ts +1 -0
  111. package/src/calls/voice-session-bridge.ts +1 -0
  112. package/src/cli/commands/auth.ts +92 -0
  113. package/src/cli/commands/avatar.ts +7 -6
  114. package/src/cli/commands/config.ts +2 -0
  115. package/src/cli/commands/oauth/providers.ts +29 -0
  116. package/src/cli/program.ts +12 -0
  117. package/src/cli.ts +15 -48
  118. package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
  119. package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
  120. package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
  121. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
  135. package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
  136. package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
  137. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
  138. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
  139. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
  140. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  141. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
  142. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  143. package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
  144. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
  145. package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
  146. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
  147. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
  148. package/src/config/bundled-tool-registry.ts +2 -14
  149. package/src/config/feature-flag-registry.json +8 -0
  150. package/src/config/loader.ts +64 -0
  151. package/src/config/raw-config-utils.ts +30 -0
  152. package/src/config/schema-utils.ts +28 -7
  153. package/src/config/schema.ts +8 -0
  154. package/src/config/schemas/elevenlabs.ts +18 -0
  155. package/src/config/schemas/memory-lifecycle.ts +4 -2
  156. package/src/config/schemas/memory-storage.ts +1 -1
  157. package/src/config/schemas/services.ts +8 -6
  158. package/src/contacts/contact-store.ts +13 -6
  159. package/src/contacts/contacts-write.ts +0 -1
  160. package/src/context/window-manager.ts +13 -2
  161. package/src/daemon/conversation-agent-loop-handlers.ts +48 -7
  162. package/src/daemon/conversation-agent-loop.ts +56 -19
  163. package/src/daemon/conversation-attachments.ts +18 -36
  164. package/src/daemon/conversation-error.ts +2 -1
  165. package/src/daemon/conversation-history.ts +18 -4
  166. package/src/daemon/conversation-lifecycle.ts +39 -15
  167. package/src/daemon/conversation-messaging.ts +70 -26
  168. package/src/daemon/conversation-process.ts +58 -34
  169. package/src/daemon/conversation-runtime-assembly.ts +21 -38
  170. package/src/daemon/conversation-slash.ts +121 -256
  171. package/src/daemon/conversation-surfaces.ts +143 -20
  172. package/src/daemon/conversation-tool-setup.ts +0 -6
  173. package/src/daemon/conversation-workspace.ts +21 -1
  174. package/src/daemon/conversation.ts +51 -29
  175. package/src/daemon/first-greeting.ts +35 -0
  176. package/src/daemon/handlers/config-embeddings.ts +148 -0
  177. package/src/daemon/handlers/config-model.ts +71 -26
  178. package/src/daemon/handlers/conversations.ts +0 -23
  179. package/src/daemon/handlers/recording.ts +26 -21
  180. package/src/daemon/host-cu-proxy.ts +2 -2
  181. package/src/daemon/lifecycle.ts +106 -64
  182. package/src/daemon/message-protocol.ts +3 -0
  183. package/src/daemon/message-types/conversations.ts +19 -0
  184. package/src/daemon/message-types/messages.ts +1 -0
  185. package/src/daemon/message-types/shared.ts +2 -0
  186. package/src/daemon/message-types/surfaces.ts +2 -0
  187. package/src/daemon/message-types/upgrades.ts +23 -0
  188. package/src/daemon/server.ts +83 -12
  189. package/src/daemon/shutdown-handlers.ts +8 -5
  190. package/src/daemon/startup-error.ts +9 -0
  191. package/src/daemon/tool-side-effects.ts +11 -28
  192. package/src/events/tool-permission-telemetry-listener.ts +1 -3
  193. package/src/instrument.ts +0 -4
  194. package/src/media/app-icon-generator.ts +2 -2
  195. package/src/memory/app-git-service.ts +28 -16
  196. package/src/memory/app-store.ts +230 -41
  197. package/src/memory/attachments-store.ts +558 -130
  198. package/src/memory/conversation-attention-store.ts +70 -0
  199. package/src/memory/conversation-crud.ts +442 -3
  200. package/src/memory/conversation-directories.ts +125 -0
  201. package/src/memory/conversation-disk-view.ts +390 -0
  202. package/src/memory/conversation-key-store.ts +17 -5
  203. package/src/memory/conversation-queries.ts +5 -1
  204. package/src/memory/conversation-title-service.ts +21 -49
  205. package/src/memory/db-init.ts +28 -0
  206. package/src/memory/embedding-backend.ts +42 -53
  207. package/src/memory/embedding-gemini.test.ts +4 -4
  208. package/src/memory/embedding-local.ts +1 -3
  209. package/src/memory/embedding-ollama.ts +1 -3
  210. package/src/memory/embedding-openai.ts +1 -3
  211. package/src/memory/indexer.ts +9 -7
  212. package/src/memory/items-extractor.ts +42 -13
  213. package/src/memory/job-handlers/conversation-starters.ts +6 -1
  214. package/src/memory/job-handlers/embedding.test.ts +1 -4
  215. package/src/memory/llm-request-log-store.ts +100 -1
  216. package/src/memory/migrations/102-alter-table-columns.ts +5 -0
  217. package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
  218. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
  219. package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
  220. package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
  221. package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
  222. package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
  223. package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
  224. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
  225. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
  226. package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
  227. package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
  228. package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
  229. package/src/memory/migrations/index.ts +7 -0
  230. package/src/memory/migrations/registry.ts +13 -0
  231. package/src/memory/retriever.test.ts +601 -2
  232. package/src/memory/retriever.ts +85 -9
  233. package/src/memory/schema/conversations.ts +6 -0
  234. package/src/memory/schema/infrastructure.ts +13 -7
  235. package/src/memory/schema/oauth.ts +6 -0
  236. package/src/messaging/providers/gmail/mime-builder.ts +3 -1
  237. package/src/notifications/copy-composer.ts +26 -0
  238. package/src/notifications/decision-engine.ts +14 -1
  239. package/src/notifications/emit-signal.ts +1 -1
  240. package/src/notifications/signal.ts +36 -0
  241. package/src/oauth/byo-connection.test.ts +1 -45
  242. package/src/oauth/byo-connection.ts +2 -8
  243. package/src/oauth/connect-orchestrator.ts +15 -11
  244. package/src/oauth/connection-resolver.test.ts +191 -0
  245. package/src/oauth/connection-resolver.ts +66 -38
  246. package/src/oauth/connection.ts +0 -1
  247. package/src/oauth/oauth-store.ts +97 -47
  248. package/src/oauth/platform-connection.test.ts +0 -1
  249. package/src/oauth/platform-connection.ts +11 -3
  250. package/src/oauth/seed-providers.ts +78 -3
  251. package/src/oauth/token-persistence.ts +16 -10
  252. package/src/permissions/checker.ts +71 -8
  253. package/src/prompts/templates/BOOTSTRAP.md +2 -0
  254. package/src/providers/anthropic/client.ts +8 -1
  255. package/src/providers/failover.ts +4 -1
  256. package/src/providers/gemini/client.ts +50 -0
  257. package/src/providers/model-catalog.ts +92 -0
  258. package/src/providers/model-intents.ts +29 -20
  259. package/src/providers/openai/client.ts +49 -0
  260. package/src/providers/types.ts +2 -0
  261. package/src/runtime/access-request-helper.ts +16 -7
  262. package/src/runtime/auth/credential-service.ts +3 -1
  263. package/src/runtime/auth/route-policy.ts +14 -1
  264. package/src/runtime/btw-sidechain.ts +101 -0
  265. package/src/runtime/channel-reply-delivery.ts +17 -1
  266. package/src/runtime/http-router.ts +3 -1
  267. package/src/runtime/http-server.ts +196 -141
  268. package/src/runtime/http-types.ts +1 -0
  269. package/src/runtime/migrations/vbundle-builder.ts +5 -1
  270. package/src/runtime/routes/access-request-decision.ts +41 -0
  271. package/src/runtime/routes/app-management-routes.ts +6 -3
  272. package/src/runtime/routes/app-routes.ts +7 -3
  273. package/src/runtime/routes/approval-routes.ts +1 -0
  274. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
  275. package/src/runtime/routes/attachment-routes.ts +45 -15
  276. package/src/runtime/routes/btw-routes.ts +21 -61
  277. package/src/runtime/routes/conversation-management-routes.ts +68 -0
  278. package/src/runtime/routes/conversation-query-routes.ts +180 -10
  279. package/src/runtime/routes/conversation-routes.ts +222 -28
  280. package/src/runtime/routes/conversation-starter-routes.ts +9 -11
  281. package/src/runtime/routes/diagnostics-routes.ts +1 -0
  282. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
  283. package/src/runtime/routes/llm-context-normalization.ts +1199 -0
  284. package/src/runtime/routes/log-export-routes.ts +3 -0
  285. package/src/runtime/routes/memory-item-routes.test.ts +34 -0
  286. package/src/runtime/routes/memory-item-routes.ts +4 -0
  287. package/src/runtime/routes/migration-routes.ts +4 -1
  288. package/src/runtime/routes/oauth-apps.ts +291 -0
  289. package/src/runtime/routes/secret-routes.ts +28 -1
  290. package/src/runtime/routes/settings-routes.ts +14 -0
  291. package/src/runtime/routes/trace-event-routes.ts +4 -1
  292. package/src/schedule/schedule-store.ts +9 -21
  293. package/src/security/secure-keys.ts +21 -0
  294. package/src/signals/bash.ts +1 -1
  295. package/src/swarm/backend-claude-code.ts +3 -6
  296. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  297. package/src/telemetry/usage-telemetry-reporter.ts +3 -1
  298. package/src/tools/AGENTS.md +6 -10
  299. package/src/tools/apps/executors.ts +17 -232
  300. package/src/tools/claude-code/claude-code.ts +2 -3
  301. package/src/tools/credentials/vault.ts +7 -12
  302. package/src/tools/host-filesystem/read.ts +13 -10
  303. package/src/tools/network/__tests__/web-search.test.ts +4 -2
  304. package/src/tools/schedule/list.ts +2 -7
  305. package/src/tools/schema-transforms.ts +5 -0
  306. package/src/tools/shared/filesystem/format-diff.ts +2 -7
  307. package/src/tools/skills/execute.ts +1 -1
  308. package/src/tools/tool-manifest.ts +0 -6
  309. package/src/tools/ui-surface/definitions.ts +2 -2
  310. package/src/util/device-id.ts +28 -5
  311. package/src/util/platform.ts +6 -0
  312. package/src/util/pricing.ts +1 -0
  313. package/src/util/retry.ts +1 -3
  314. package/src/workspace/migrations/002-backfill-installation-id.ts +23 -12
  315. package/src/workspace/migrations/003-seed-device-id.ts +3 -4
  316. package/src/workspace/migrations/006-services-config.ts +5 -0
  317. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
  318. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
  319. package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
  320. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
  321. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
  322. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
  323. package/src/workspace/migrations/registry.ts +10 -0
  324. package/src/workspace/top-level-renderer.ts +12 -0
  325. package/src/__tests__/asset-materialize-tool.test.ts +0 -523
  326. package/src/__tests__/asset-search-tool.test.ts +0 -536
  327. package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
  328. package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
  329. package/src/__tests__/media-visibility-policy.test.ts +0 -190
  330. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
  331. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
  332. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
  333. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
  334. package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
  335. package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
  336. package/src/daemon/media-visibility-policy.ts +0 -59
  337. package/src/tools/assets/materialize.ts +0 -248
  338. package/src/tools/assets/search.ts +0 -400
@@ -70,21 +70,53 @@ describe("injectActivityField", () => {
70
70
  expect("activity" in props0).toBe(false);
71
71
  });
72
72
 
73
- test("skips tools that already have activity in properties", () => {
73
+ test("returns unchanged when activity is in top-level properties but not required", () => {
74
74
  const defs = [
75
75
  makeDef("my_tool", {
76
76
  type: "object",
77
77
  properties: { activity: { type: "number" } },
78
- required: [],
78
+ required: ["foo"],
79
79
  }),
80
80
  ];
81
81
  const result = injectActivityField(defs);
82
- // Should be the exact same object reference (no clone needed)
82
+ // Should be the exact same object reference (no modification)
83
83
  expect(Object.is(result[0], defs[0])).toBe(true);
84
84
  const schema = result[0].input_schema as Record<string, unknown>;
85
85
  const props = schema.properties as Record<string, unknown>;
86
86
  // Original activity type preserved
87
87
  expect(props.activity).toEqual({ type: "number" });
88
+ // required NOT modified — don't promote server-defined optional activity
89
+ expect(schema.required).toEqual(["foo"]);
90
+ });
91
+
92
+ test("returns unchanged when activity is in both top-level properties AND required", () => {
93
+ const defs = [
94
+ makeDef("my_tool", {
95
+ type: "object",
96
+ properties: { activity: { type: "string" } },
97
+ required: ["activity"],
98
+ }),
99
+ ];
100
+ const result = injectActivityField(defs);
101
+ const schema = result[0].input_schema as Record<string, unknown>;
102
+ const props = schema.properties as Record<string, unknown>;
103
+ // Original activity type preserved
104
+ expect(props.activity).toEqual({ type: "string" });
105
+ // activity must be in required even though it was already in properties
106
+ expect(schema.required).toEqual(["activity"]);
107
+ });
108
+
109
+ test("skips tools that already have activity in both properties and required", () => {
110
+ const defs = [
111
+ makeDef("my_tool", {
112
+ type: "object",
113
+ properties: { activity: { type: "number" } },
114
+ required: ["activity"],
115
+ }),
116
+ ];
117
+ const result = injectActivityField(defs);
118
+ // Should be the exact same object reference (no clone needed)
119
+ expect(Object.is(result[0], defs[0])).toBe(true);
88
120
  });
89
121
 
90
122
  test("does NOT mutate original definition objects", () => {
@@ -125,6 +157,60 @@ describe("injectActivityField", () => {
125
157
  expect(Object.is(result[0], defs[0])).toBe(true);
126
158
  });
127
159
 
160
+ test("does NOT add activity to top-level required when only in oneOf branch", () => {
161
+ const defs = [
162
+ makeDef("my_tool", {
163
+ type: "object",
164
+ properties: { shared: { type: "string" } },
165
+ oneOf: [
166
+ {
167
+ properties: {
168
+ activity: { type: "string" },
169
+ branch_a: { type: "number" },
170
+ },
171
+ },
172
+ {
173
+ properties: { branch_b: { type: "boolean" } },
174
+ },
175
+ ],
176
+ required: ["shared"],
177
+ }),
178
+ ];
179
+ const result = injectActivityField(defs);
180
+ // Should be the exact same object reference (no modification)
181
+ expect(Object.is(result[0], defs[0])).toBe(true);
182
+ const schema = result[0].input_schema as Record<string, unknown>;
183
+ // Top-level required should NOT include activity
184
+ expect(schema.required).toEqual(["shared"]);
185
+ // Top-level properties should NOT have activity injected
186
+ const props = schema.properties as Record<string, unknown>;
187
+ expect("activity" in props).toBe(false);
188
+ });
189
+
190
+ test("does NOT add activity to top-level required when only in allOf sub-schema with additionalProperties: false", () => {
191
+ const defs = [
192
+ makeDef("my_tool", {
193
+ type: "object",
194
+ properties: { foo: { type: "string" } },
195
+ additionalProperties: false,
196
+ allOf: [
197
+ {
198
+ properties: { activity: { type: "string" } },
199
+ },
200
+ ],
201
+ required: ["foo"],
202
+ }),
203
+ ];
204
+ const result = injectActivityField(defs);
205
+ // Should be the exact same object reference (no modification)
206
+ expect(Object.is(result[0], defs[0])).toBe(true);
207
+ const schema = result[0].input_schema as Record<string, unknown>;
208
+ // Top-level required should NOT include activity
209
+ expect(schema.required).toEqual(["foo"]);
210
+ const props = schema.properties as Record<string, unknown>;
211
+ expect("activity" in props).toBe(false);
212
+ });
213
+
128
214
  test("skips tools with activity defined inside allOf member (composite schema)", () => {
129
215
  const defs = [
130
216
  makeDef("my_tool", {
@@ -139,18 +225,92 @@ describe("injectActivityField", () => {
139
225
  }),
140
226
  ];
141
227
  const result = injectActivityField(defs);
142
- // Should be the exact same object reference (no injection)
228
+ // Should be the exact same object reference (no modification)
143
229
  expect(Object.is(result[0], defs[0])).toBe(true);
144
230
  const schema = result[0].input_schema as Record<string, unknown>;
145
231
  const props = schema.properties as Record<string, unknown>;
146
- // Top-level properties should NOT have activity injected
232
+ // Top-level properties should NOT have activity injected (it's in allOf)
147
233
  expect("activity" in props).toBe(false);
234
+ // Top-level required should NOT include activity (it's only in composite sub-schemas)
235
+ expect(schema.required).toEqual([]);
236
+ });
237
+
238
+ test("skips allOf composite schema where activity is already required", () => {
239
+ const defs = [
240
+ makeDef("my_tool", {
241
+ type: "object",
242
+ properties: { foo: { type: "string" } },
243
+ allOf: [
244
+ {
245
+ properties: { activity: { type: "string" } },
246
+ },
247
+ ],
248
+ required: ["activity"],
249
+ }),
250
+ ];
251
+ const result = injectActivityField(defs);
252
+ // Should be the exact same object reference (no change needed)
253
+ expect(Object.is(result[0], defs[0])).toBe(true);
148
254
  });
149
255
 
150
256
  test("handles empty definitions array", () => {
151
257
  const result = injectActivityField([]);
152
258
  expect(result).toEqual([]);
153
259
  });
260
+
261
+ test("injects activity only on tools that don't define it at all", () => {
262
+ const defs = [
263
+ // Normal tool without activity — should get it injected
264
+ makeDef("tool_a", {
265
+ type: "object",
266
+ properties: { foo: { type: "string" } },
267
+ required: ["foo"],
268
+ }),
269
+ // Tool defines activity in properties but NOT in required — left unchanged
270
+ makeDef("tool_b", {
271
+ type: "object",
272
+ properties: {
273
+ bar: { type: "string" },
274
+ activity: { type: "string", description: "custom activity" },
275
+ },
276
+ required: ["bar"],
277
+ }),
278
+ // Tool that defines activity in both properties AND required — left unchanged
279
+ makeDef("tool_c", {
280
+ type: "object",
281
+ properties: {
282
+ baz: { type: "number" },
283
+ activity: { type: "string", description: "custom activity" },
284
+ },
285
+ required: ["baz", "activity"],
286
+ }),
287
+ // Non-object schema — should be left alone
288
+ makeDef("tool_d", { type: "string" }),
289
+ // Object schema without properties — should be left alone
290
+ makeDef("tool_e", { type: "object" }),
291
+ ];
292
+
293
+ const result = injectActivityField(defs);
294
+
295
+ // tool_a: activity injected and required
296
+ const schemaA = result[0].input_schema as Record<string, unknown>;
297
+ expect(
298
+ (schemaA.properties as Record<string, unknown>).activity,
299
+ ).toBeDefined();
300
+ expect(schemaA.required).toEqual(["foo", "activity"]);
301
+
302
+ // tool_b: unchanged (activity optional, not promoted)
303
+ expect(Object.is(result[1], defs[1])).toBe(true);
304
+ const schemaB = result[1].input_schema as Record<string, unknown>;
305
+ expect(schemaB.required).toEqual(["bar"]);
306
+
307
+ // tool_c: unchanged (activity already present and required)
308
+ expect(Object.is(result[2], defs[2])).toBe(true);
309
+
310
+ // tool_d, tool_e: unchanged
311
+ expect(Object.is(result[3], defs[3])).toBe(true);
312
+ expect(Object.is(result[4], defs[4])).toBe(true);
313
+ });
154
314
  });
155
315
 
156
316
  describe("schemaDefinesProperty", () => {
@@ -330,7 +330,7 @@ describe("getAttachmentsForMessage", () => {
330
330
 
331
331
  test("returns attachments linked to a message", async () => {
332
332
  const msgId = await createMessage("assistant", "Here is a chart");
333
- const stored = uploadAttachment("chart.png", "image/png", "iVBOR");
333
+ const stored = uploadAttachment("chart.png", "image/png", "iVBORw==");
334
334
  linkAttachmentToMessage(msgId, stored.id, 0);
335
335
 
336
336
  const result = getAttachmentsForMessage(msgId);
@@ -338,7 +338,7 @@ describe("getAttachmentsForMessage", () => {
338
338
  expect(result[0].id).toBe(stored.id);
339
339
  expect(result[0].originalFilename).toBe("chart.png");
340
340
  expect(result[0].mimeType).toBe("image/png");
341
- expect(result[0].dataBase64).toBe("iVBOR");
341
+ expect(result[0].dataBase64).toBe("iVBORw==");
342
342
  });
343
343
 
344
344
  test("returns empty array when no attachments are linked", () => {
@@ -9,7 +9,9 @@ const skillContent = readFileSync(SKILL_PATH, "utf-8");
9
9
 
10
10
  describe("slack-app-setup skill regression", () => {
11
11
  test("keeps Slack token collection on the secure credential prompt path", () => {
12
- expect(skillContent).toContain('`credential_store` with `action: "prompt"`');
12
+ expect(skillContent).toContain(
13
+ '`credential_store` with `action: "prompt"`',
14
+ );
13
15
  expect(skillContent).toContain(
14
16
  "same Slack settings handler used by Settings",
15
17
  );
@@ -163,11 +163,11 @@ describe("Slack inbound trusted contact verification", () => {
163
163
  // Verification code is NOT sent to the requester — only the guardian
164
164
  // receives it via the access request notification flow
165
165
 
166
- // Channel reply tells user the owner has been notified
166
+ // Channel reply tells user they're not recognized yet
167
167
  expect(deliverReplyCalls.length).toBe(1);
168
168
  expect(
169
169
  (deliverReplyCalls[0].payload as Record<string, unknown>).text,
170
- ).toContain("notified the owner");
170
+ ).toContain("I don't recognize you yet");
171
171
  });
172
172
 
173
173
  test("verification session is identity-bound to the Slack user", async () => {
@@ -39,6 +39,7 @@ function makeContext(): SurfaceConversationContext {
39
39
  >(),
40
40
  surfaceState: new Map(),
41
41
  surfaceUndoStacks: new Map(),
42
+ accumulatedSurfaceState: new Map(),
42
43
  surfaceActionRequestIds: new Set<string>(),
43
44
  currentTurnSurfaces: [],
44
45
  isProcessing: () => false,