@vellumai/assistant 0.4.56 → 0.5.0

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 (457) hide show
  1. package/ARCHITECTURE.md +10 -10
  2. package/Dockerfile +3 -0
  3. package/README.md +11 -11
  4. package/docs/architecture/integrations.md +2 -2
  5. package/docs/architecture/memory.md +3 -4
  6. package/docs/credential-execution-service.md +13 -20
  7. package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
  8. package/package.json +1 -1
  9. package/src/__tests__/actor-token-service.test.ts +7 -7
  10. package/src/__tests__/anthropic-provider.test.ts +172 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
  12. package/src/__tests__/approval-cascade.test.ts +2 -2
  13. package/src/__tests__/approval-routes-http.test.ts +3 -4
  14. package/src/__tests__/asset-materialize-tool.test.ts +5 -5
  15. package/src/__tests__/asset-search-tool.test.ts +1 -1
  16. package/src/__tests__/assistant-attachments.test.ts +5 -5
  17. package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
  19. package/src/__tests__/attachments-store.test.ts +2 -2
  20. package/src/__tests__/avatar-e2e.test.ts +5 -3
  21. package/src/__tests__/browser-skill-endstate.test.ts +0 -1
  22. package/src/__tests__/call-routes-http.test.ts +2 -2
  23. package/src/__tests__/callback-handoff-copy.test.ts +1 -1
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
  25. package/src/__tests__/channel-readiness-routes.test.ts +0 -1
  26. package/src/__tests__/channel-readiness-service.test.ts +0 -1
  27. package/src/__tests__/checker.test.ts +31 -32
  28. package/src/__tests__/chrome-cdp.test.ts +47 -18
  29. package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
  30. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  31. package/src/__tests__/config-schema.test.ts +9 -18
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
  34. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
  35. package/src/__tests__/conversation-agent-loop.test.ts +11 -4
  36. package/src/__tests__/conversation-attachments.test.ts +1 -1
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
  38. package/src/__tests__/conversation-error.test.ts +33 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
  40. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  41. package/src/__tests__/conversation-pairing.test.ts +1 -1
  42. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
  44. package/src/__tests__/conversation-queue.test.ts +23 -14
  45. package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +204 -185
  47. package/src/__tests__/conversation-seed-composer.test.ts +1 -1
  48. package/src/__tests__/conversation-slash-queue.test.ts +4 -4
  49. package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
  50. package/src/__tests__/conversation-starter-routes.test.ts +291 -0
  51. package/src/__tests__/conversation-wipe.test.ts +438 -0
  52. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
  53. package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
  54. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
  55. package/src/__tests__/credential-security-e2e.test.ts +20 -0
  56. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  57. package/src/__tests__/credential-vault-unit.test.ts +227 -0
  58. package/src/__tests__/credentials-cli.test.ts +3 -0
  59. package/src/__tests__/date-context.test.ts +59 -377
  60. package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
  61. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
  62. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
  63. package/src/__tests__/encrypted-store.test.ts +249 -15
  64. package/src/__tests__/ephemeral-permissions.test.ts +4 -5
  65. package/src/__tests__/event-bus.test.ts +3 -3
  66. package/src/__tests__/file-read-tool.test.ts +40 -0
  67. package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
  68. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  69. package/src/__tests__/gemini-image-service.test.ts +4 -4
  70. package/src/__tests__/gemini-provider.test.ts +6 -9
  71. package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
  72. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  73. package/src/__tests__/host-file-read-tool.test.ts +87 -0
  74. package/src/__tests__/host-shell-tool.test.ts +6 -6
  75. package/src/__tests__/http-user-message-parity.test.ts +2 -2
  76. package/src/__tests__/identity-intro-cache.test.ts +209 -0
  77. package/src/__tests__/intent-routing.test.ts +51 -99
  78. package/src/__tests__/invite-routes-http.test.ts +5 -0
  79. package/src/__tests__/list-messages-attachments.test.ts +1 -1
  80. package/src/__tests__/managed-proxy-context.test.ts +2 -5
  81. package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
  82. package/src/__tests__/media-generate-image.test.ts +32 -15
  83. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
  84. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
  85. package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
  86. package/src/__tests__/memory-recall-quality.test.ts +4 -3
  87. package/src/__tests__/memory-regressions.test.ts +86 -90
  88. package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
  89. package/src/__tests__/migration-export-http.test.ts +26 -27
  90. package/src/__tests__/migration-import-commit-http.test.ts +165 -37
  91. package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
  92. package/src/__tests__/migration-validate-http.test.ts +16 -16
  93. package/src/__tests__/model-intents.test.ts +2 -2
  94. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
  95. package/src/__tests__/non-member-access-request.test.ts +3 -3
  96. package/src/__tests__/notification-broadcaster.test.ts +1 -1
  97. package/src/__tests__/notification-decision-fallback.test.ts +2 -2
  98. package/src/__tests__/notification-decision-identity.test.ts +8 -9
  99. package/src/__tests__/notification-decision-strategy.test.ts +1 -1
  100. package/src/__tests__/notification-deep-link.test.ts +1 -1
  101. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  102. package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
  103. package/src/__tests__/oauth-store.test.ts +1 -3
  104. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
  105. package/src/__tests__/onboarding-template-contract.test.ts +23 -59
  106. package/src/__tests__/provider-error-scenarios.test.ts +154 -0
  107. package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
  108. package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
  109. package/src/__tests__/provider-registry-ollama.test.ts +5 -2
  110. package/src/__tests__/qdrant-manager.test.ts +7 -7
  111. package/src/__tests__/ratelimit.test.ts +0 -74
  112. package/src/__tests__/recording-handler.test.ts +0 -1
  113. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  114. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  115. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  116. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  117. package/src/__tests__/scheduler-recurrence.test.ts +46 -2
  118. package/src/__tests__/schema-transforms.test.ts +114 -54
  119. package/src/__tests__/secret-onetime-send.test.ts +20 -0
  120. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
  121. package/src/__tests__/secret-scanner-executor.test.ts +1 -2
  122. package/src/__tests__/send-endpoint-busy.test.ts +63 -4
  123. package/src/__tests__/send-notification-tool.test.ts +2 -2
  124. package/src/__tests__/shell-credential-ref.test.ts +0 -1
  125. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
  126. package/src/__tests__/skill-memory.test.ts +549 -0
  127. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
  128. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
  129. package/src/__tests__/slack-channel-config.test.ts +109 -94
  130. package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
  131. package/src/__tests__/swarm-recursion.test.ts +2 -2
  132. package/src/__tests__/swarm-tool.test.ts +2 -2
  133. package/src/__tests__/system-prompt.test.ts +19 -66
  134. package/src/__tests__/telegram-config.test.ts +121 -0
  135. package/src/__tests__/terminal-tools.test.ts +1 -1
  136. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  138. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  139. package/src/__tests__/tool-executor.test.ts +1 -1
  140. package/src/__tests__/trace-emitter.test.ts +8 -1
  141. package/src/__tests__/trust-store.test.ts +7 -8
  142. package/src/__tests__/twilio-routes.test.ts +1 -18
  143. package/src/__tests__/user-reference.test.ts +82 -2
  144. package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
  145. package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
  146. package/src/approvals/guardian-request-resolvers.ts +3 -3
  147. package/src/avatar/ascii-renderer.ts +2 -2
  148. package/src/avatar/png-renderer.ts +2 -2
  149. package/src/avatar/resvg-lazy.ts +21 -0
  150. package/src/calls/guardian-dispatch.ts +1 -1
  151. package/src/calls/relay-access-wait.ts +2 -2
  152. package/src/calls/twilio-rest.ts +0 -248
  153. package/src/cli/AGENTS.md +5 -8
  154. package/src/cli/__tests__/notifications.test.ts +5 -5
  155. package/src/cli/commands/avatar.ts +64 -2
  156. package/src/cli/commands/conversations.ts +131 -1
  157. package/src/cli/commands/credentials.ts +2 -0
  158. package/src/cli/commands/notifications.ts +3 -3
  159. package/src/cli.ts +10 -0
  160. package/src/config/bundled-skills/acp/SKILL.md +5 -5
  161. package/src/config/bundled-skills/acp/TOOLS.json +6 -6
  162. package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
  163. package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
  164. package/src/config/bundled-skills/browser/SKILL.md +15 -15
  165. package/src/config/bundled-skills/browser/TOOLS.json +14 -14
  166. package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
  167. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
  168. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  169. package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
  170. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  171. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
  172. package/src/config/bundled-skills/contacts/SKILL.md +3 -3
  173. package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
  174. package/src/config/bundled-skills/document/SKILL.md +4 -4
  175. package/src/config/bundled-skills/document/TOOLS.json +2 -2
  176. package/src/config/bundled-skills/followups/TOOLS.json +3 -3
  177. package/src/config/bundled-skills/gmail/SKILL.md +32 -32
  178. package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
  179. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
  180. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  181. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
  182. package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
  183. package/src/config/bundled-skills/google-calendar/types.ts +1 -1
  184. package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
  185. package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
  186. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
  187. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
  188. package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
  189. package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
  190. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
  191. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
  192. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
  193. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
  194. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
  195. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
  196. package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
  197. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  198. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
  199. package/src/config/bundled-skills/messaging/SKILL.md +29 -25
  200. package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
  201. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  202. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  203. package/src/config/bundled-skills/notifications/SKILL.md +3 -3
  204. package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
  205. package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
  206. package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
  207. package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
  208. package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
  209. package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
  210. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
  211. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
  212. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
  213. package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
  214. package/src/config/bundled-skills/schedule/SKILL.md +26 -26
  215. package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
  216. package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
  217. package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
  218. package/src/config/bundled-skills/sequences/SKILL.md +2 -2
  219. package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
  220. package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
  221. package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
  222. package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
  223. package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
  224. package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
  225. package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
  226. package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
  227. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  228. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
  229. package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
  230. package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
  231. package/src/config/bundled-skills/slack/SKILL.md +2 -2
  232. package/src/config/bundled-skills/slack/TOOLS.json +8 -8
  233. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
  234. package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
  235. package/src/config/bundled-skills/tasks/SKILL.md +1 -1
  236. package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
  237. package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
  238. package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
  240. package/src/config/bundled-skills/watcher/SKILL.md +4 -4
  241. package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
  242. package/src/config/feature-flag-registry.json +33 -17
  243. package/src/config/schemas/sandbox.ts +1 -1
  244. package/src/config/schemas/services.ts +13 -3
  245. package/src/config/schemas/timeouts.ts +0 -10
  246. package/src/contacts/contact-store.ts +63 -0
  247. package/src/contacts/contacts-write.ts +1 -1
  248. package/src/daemon/assistant-attachments.ts +2 -2
  249. package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
  250. package/src/daemon/conversation-agent-loop.ts +7 -30
  251. package/src/daemon/conversation-error.ts +24 -0
  252. package/src/daemon/conversation-memory.ts +8 -7
  253. package/src/daemon/conversation-runtime-assembly.ts +141 -275
  254. package/src/daemon/conversation-slash.ts +7 -26
  255. package/src/daemon/conversation-surfaces.ts +14 -0
  256. package/src/daemon/conversation-tool-setup.ts +9 -8
  257. package/src/daemon/conversation.ts +2 -0
  258. package/src/daemon/daemon-control.ts +1 -1
  259. package/src/daemon/date-context.ts +10 -83
  260. package/src/daemon/handlers/config-channels.ts +12 -2
  261. package/src/daemon/handlers/config-slack-channel.ts +7 -1
  262. package/src/daemon/handlers/config-telegram.ts +6 -1
  263. package/src/daemon/handlers/conversations.ts +2 -2
  264. package/src/daemon/handlers/skills.ts +4 -0
  265. package/src/daemon/lifecycle.ts +28 -4
  266. package/src/daemon/providers-setup.ts +1 -1
  267. package/src/daemon/server.ts +1 -5
  268. package/src/daemon/shutdown-handlers.ts +9 -3
  269. package/src/daemon/tool-side-effects.ts +40 -0
  270. package/src/daemon/trace-emitter.ts +26 -2
  271. package/src/events/domain-events.ts +1 -1
  272. package/src/events/tool-permission-telemetry-listener.ts +46 -0
  273. package/src/inbound/platform-callback-registration.ts +0 -18
  274. package/src/media/app-icon-generator.ts +15 -8
  275. package/src/media/avatar-router.ts +15 -8
  276. package/src/media/gemini-image-service.ts +125 -21
  277. package/src/memory/attachments-store.ts +3 -3
  278. package/src/memory/channel-verification-sessions.ts +6 -6
  279. package/src/memory/conversation-crud.ts +196 -1
  280. package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
  281. package/src/memory/conversation-title-service.ts +2 -3
  282. package/src/memory/db-init.ts +25 -1
  283. package/src/memory/invite-store.ts +4 -4
  284. package/src/memory/items-extractor.ts +4 -4
  285. package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
  286. package/src/memory/jobs-store.ts +3 -2
  287. package/src/memory/jobs-worker.ts +7 -5
  288. package/src/memory/lifecycle-events-store.ts +63 -0
  289. package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
  290. package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
  291. package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
  292. package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
  293. package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
  294. package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
  295. package/src/memory/migrations/index.ts +6 -0
  296. package/src/memory/migrations/registry.ts +13 -0
  297. package/src/memory/retriever.test.ts +223 -96
  298. package/src/memory/retriever.ts +115 -138
  299. package/src/memory/schema/calls.ts +1 -1
  300. package/src/memory/schema/contacts.ts +1 -1
  301. package/src/memory/schema/infrastructure.ts +29 -0
  302. package/src/memory/schema/memory-core.ts +7 -17
  303. package/src/memory/schema/notifications.ts +1 -1
  304. package/src/memory/search/formatting.ts +23 -6
  305. package/src/memory/search/lexical.ts +2 -0
  306. package/src/memory/search/semantic.ts +2 -0
  307. package/src/memory/search/staleness.ts +5 -1
  308. package/src/memory/search/types.ts +4 -0
  309. package/src/memory/task-memory-cleanup.ts +96 -6
  310. package/src/memory/trace-event-store.ts +148 -0
  311. package/src/notifications/README.md +1 -1
  312. package/src/notifications/decision-engine.ts +45 -4
  313. package/src/notifications/emit-signal.ts +5 -4
  314. package/src/notifications/events-store.ts +4 -4
  315. package/src/notifications/signal.ts +1 -1
  316. package/src/oauth/manual-token-connection.ts +49 -25
  317. package/src/permissions/checker.ts +6 -5
  318. package/src/permissions/defaults.ts +4 -4
  319. package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
  320. package/src/prompts/cache-boundary.ts +8 -0
  321. package/src/prompts/system-prompt.ts +105 -634
  322. package/src/prompts/templates/BOOTSTRAP.md +172 -33
  323. package/src/prompts/templates/IDENTITY.md +8 -24
  324. package/src/prompts/templates/SOUL.md +20 -41
  325. package/src/prompts/templates/USER.md +3 -19
  326. package/src/prompts/user-reference.ts +14 -16
  327. package/src/providers/anthropic/client.ts +51 -19
  328. package/src/providers/gemini/client.ts +6 -9
  329. package/src/providers/managed-proxy/constants.ts +1 -7
  330. package/src/providers/managed-proxy/context.ts +0 -1
  331. package/src/providers/model-intents.ts +5 -5
  332. package/src/providers/openai/client.ts +10 -1
  333. package/src/providers/openrouter/client.ts +1 -0
  334. package/src/providers/ratelimit.ts +0 -35
  335. package/src/providers/registry.ts +3 -5
  336. package/src/providers/retry.ts +18 -1
  337. package/src/runtime/access-request-helper.ts +16 -2
  338. package/src/runtime/auth/route-policy.ts +7 -0
  339. package/src/runtime/channel-verification-service.ts +1 -1
  340. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  341. package/src/runtime/guardian-vellum-migration.ts +61 -1
  342. package/src/runtime/http-server.ts +8 -4
  343. package/src/runtime/migrations/vbundle-builder.ts +212 -32
  344. package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
  345. package/src/runtime/migrations/vbundle-importer.ts +66 -1
  346. package/src/runtime/migrations/vbundle-validator.ts +17 -3
  347. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
  348. package/src/runtime/routes/attachment-routes.ts +2 -2
  349. package/src/runtime/routes/btw-routes.ts +93 -0
  350. package/src/runtime/routes/channel-verification-routes.ts +19 -2
  351. package/src/runtime/routes/conversation-management-routes.ts +55 -1
  352. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  353. package/src/runtime/routes/conversation-routes.ts +49 -5
  354. package/src/runtime/routes/conversation-starter-routes.ts +207 -0
  355. package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
  356. package/src/runtime/routes/identity-intro-cache.ts +105 -0
  357. package/src/runtime/routes/identity-routes.ts +51 -0
  358. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
  359. package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
  360. package/src/runtime/routes/migration-routes.ts +25 -13
  361. package/src/runtime/routes/secret-routes.ts +18 -0
  362. package/src/runtime/routes/settings-routes.ts +9 -9
  363. package/src/runtime/routes/telemetry-routes.ts +53 -0
  364. package/src/runtime/routes/trace-event-routes.ts +62 -0
  365. package/src/runtime/tool-grant-request-helper.ts +1 -1
  366. package/src/runtime/verification-outbound-actions.ts +47 -31
  367. package/src/security/encrypted-store.ts +262 -78
  368. package/src/skills/catalog-install.ts +10 -0
  369. package/src/skills/managed-store.ts +2 -0
  370. package/src/skills/skill-memory.ts +222 -0
  371. package/src/subagent/manager.ts +1 -4
  372. package/src/telemetry/types.ts +10 -1
  373. package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
  374. package/src/telemetry/usage-telemetry-reporter.ts +53 -4
  375. package/src/tools/AGENTS.md +11 -11
  376. package/src/tools/acp/spawn.ts +1 -1
  377. package/src/tools/apps/executors.ts +8 -8
  378. package/src/tools/apps/registry.ts +1 -1
  379. package/src/tools/assets/materialize.ts +6 -6
  380. package/src/tools/assets/search.ts +10 -10
  381. package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
  382. package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
  383. package/src/tools/browser/auth-detector.ts +6 -6
  384. package/src/tools/browser/browser-execution.ts +13 -13
  385. package/src/tools/browser/browser-manager.ts +3 -3
  386. package/src/tools/browser/chrome-cdp.ts +5 -5
  387. package/src/tools/browser/jit-auth.ts +2 -2
  388. package/src/tools/browser/network-recorder.test.ts +2 -2
  389. package/src/tools/browser/network-recorder.ts +3 -3
  390. package/src/tools/browser/runtime-check.ts +3 -3
  391. package/src/tools/claude-code/claude-code.ts +2 -2
  392. package/src/tools/computer-use/definitions.ts +18 -18
  393. package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
  394. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
  395. package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
  396. package/src/tools/credentials/broker-types.ts +5 -5
  397. package/src/tools/credentials/broker.ts +15 -15
  398. package/src/tools/credentials/metadata-store.ts +2 -2
  399. package/src/tools/credentials/resolve.ts +1 -1
  400. package/src/tools/credentials/selection.ts +1 -1
  401. package/src/tools/credentials/tool-policy.ts +1 -1
  402. package/src/tools/credentials/vault.ts +115 -25
  403. package/src/tools/execution-target.ts +2 -2
  404. package/src/tools/executor.ts +7 -7
  405. package/src/tools/filesystem/edit.ts +2 -2
  406. package/src/tools/filesystem/read.ts +15 -4
  407. package/src/tools/filesystem/write.ts +1 -1
  408. package/src/tools/host-filesystem/edit.ts +2 -1
  409. package/src/tools/host-filesystem/read.ts +18 -1
  410. package/src/tools/host-filesystem/write.ts +1 -1
  411. package/src/tools/host-terminal/host-shell.ts +9 -8
  412. package/src/tools/mcp/mcp-tool-factory.ts +7 -6
  413. package/src/tools/memory/definitions.ts +6 -5
  414. package/src/tools/memory/handlers.test.ts +1 -1
  415. package/src/tools/network/__tests__/web-search.test.ts +3 -3
  416. package/src/tools/network/domain-normalize.ts +2 -2
  417. package/src/tools/network/script-proxy/session-manager.ts +10 -10
  418. package/src/tools/network/web-fetch.ts +1 -1
  419. package/src/tools/network/web-search.ts +3 -3
  420. package/src/tools/permission-checker.ts +8 -8
  421. package/src/tools/registry.ts +7 -7
  422. package/src/tools/schedule/list.ts +2 -2
  423. package/src/tools/schema-transforms.ts +31 -21
  424. package/src/tools/secret-detection-handler.ts +1 -1
  425. package/src/tools/sensitive-output-placeholders.ts +1 -1
  426. package/src/tools/shared/filesystem/edit-engine.ts +1 -1
  427. package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
  428. package/src/tools/shared/filesystem/image-read.ts +25 -5
  429. package/src/tools/shared/filesystem/path-policy.ts +2 -2
  430. package/src/tools/shared/shell-output.ts +1 -1
  431. package/src/tools/side-effects.ts +1 -1
  432. package/src/tools/skills/execute.ts +1 -1
  433. package/src/tools/skills/load.ts +3 -3
  434. package/src/tools/skills/sandbox-runner.ts +3 -3
  435. package/src/tools/subagent/read.ts +1 -1
  436. package/src/tools/subagent/spawn.ts +2 -2
  437. package/src/tools/swarm/delegate.ts +3 -3
  438. package/src/tools/system/request-permission.ts +5 -4
  439. package/src/tools/terminal/backends/native.ts +4 -4
  440. package/src/tools/terminal/parser.ts +6 -6
  441. package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
  442. package/src/tools/terminal/shell.ts +16 -16
  443. package/src/tools/tool-approval-handler.ts +21 -12
  444. package/src/tools/tool-manifest.ts +4 -4
  445. package/src/tools/types.ts +3 -3
  446. package/src/tools/ui-surface/definitions.ts +9 -37
  447. package/src/tools/watcher/list.ts +1 -1
  448. package/src/util/logger.ts +7 -2
  449. package/src/util/pricing.ts +4 -0
  450. package/src/util/retry.ts +29 -1
  451. package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
  452. package/src/workspace/migrations/registry.ts +2 -0
  453. package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
  454. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
  455. package/src/cli/reference.ts +0 -38
  456. package/src/memory/job-handlers/capability-cards.ts +0 -420
  457. package/src/runtime/routes/thread-starter-routes.ts +0 -294
@@ -0,0 +1,37 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { describe, expect, test } from "bun:test";
4
+
5
+ const REPO_ROOT = resolve(import.meta.dirname ?? __dirname, "..", "..", "..");
6
+ const SKILL_PATH = resolve(REPO_ROOT, "skills", "slack-app-setup", "SKILL.md");
7
+
8
+ const skillContent = readFileSync(SKILL_PATH, "utf-8");
9
+
10
+ describe("slack-app-setup skill regression", () => {
11
+ test("keeps Slack token collection on the secure credential prompt path", () => {
12
+ expect(skillContent).toContain('`credential_store` with `action: "prompt"`');
13
+ expect(skillContent).toContain(
14
+ "same Slack settings handler used by Settings",
15
+ );
16
+ });
17
+
18
+ test("forbids plaintext forms and chat-pasted secrets", () => {
19
+ expect(skillContent).toContain("Do NOT use `ui_show`");
20
+ expect(skillContent).toContain("Do NOT ask the user to paste them in chat");
21
+ });
22
+
23
+ test("does not instruct the agent to reimplement Slack validation in shell", () => {
24
+ expect(skillContent).not.toContain(
25
+ "assistant credentials reveal --service slack_channel",
26
+ );
27
+ expect(skillContent).not.toContain(
28
+ 'curl -sf -X POST "https://slack.com/api/auth.test"',
29
+ );
30
+ expect(skillContent).not.toContain("assistant config set slack.teamId");
31
+ expect(skillContent).not.toContain("assistant config set slack.teamName");
32
+ expect(skillContent).not.toContain("assistant config set slack.botUserId");
33
+ expect(skillContent).not.toContain(
34
+ "assistant config set slack.botUsername",
35
+ );
36
+ });
37
+ });
@@ -4,6 +4,11 @@ import { join } from "node:path";
4
4
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
5
5
 
6
6
  const testDir = mkdtempSync(join(tmpdir(), "slack-channel-cfg-test-"));
7
+ const secureStorePath = join(testDir, "keys.enc");
8
+ const metadataPath = join(testDir, "metadata.json");
9
+ const originalVellumDev = process.env.VELLUM_DEV;
10
+
11
+ process.env.VELLUM_DEV = "1";
7
12
 
8
13
  // In-memory config store for tests
9
14
  let configStore: Record<string, unknown> = {};
@@ -84,32 +89,6 @@ mock.module("../util/logger.js", () => ({
84
89
  }),
85
90
  }));
86
91
 
87
- // Mock secure key storage
88
- let secureKeyStore: Record<string, string> = {};
89
-
90
- mock.module("../security/secure-keys.js", () => {
91
- const syncSet = (account: string, value: string) => {
92
- secureKeyStore[account] = value;
93
- return true;
94
- };
95
- const syncDelete = (account: string) => {
96
- if (account in secureKeyStore) {
97
- delete secureKeyStore[account];
98
- return "deleted" as const;
99
- }
100
- return "not-found" as const;
101
- };
102
- return {
103
- getSecureKeyAsync: async (account: string) =>
104
- secureKeyStore[account] ?? undefined,
105
- setSecureKeyAsync: async (account: string, value: string) =>
106
- syncSet(account, value),
107
- deleteSecureKeyAsync: async (account: string) => syncDelete(account),
108
- listSecureKeysAsync: async () => Object.keys(secureKeyStore),
109
- _resetBackend: () => {},
110
- };
111
- });
112
-
113
92
  // Mock oauth-store (getConnectionByProvider)
114
93
  let oauthConnectionStore: Record<
115
94
  string,
@@ -148,54 +127,28 @@ mock.module("../oauth/manual-token-connection.js", () => ({
148
127
  removeManualTokenConnection: (providerKey: string) => {
149
128
  delete oauthConnectionStore[providerKey];
150
129
  },
151
- }));
152
-
153
- // Mock credential metadata store
154
- let credentialMetadataStore: Array<{
155
- service: string;
156
- field: string;
157
- accountInfo?: string;
158
- }> = [];
159
-
160
- mock.module("../tools/credentials/metadata-store.js", () => ({
161
- getCredentialMetadata: (service: string, field: string) =>
162
- credentialMetadataStore.find(
163
- (m) => m.service === service && m.field === field,
164
- ) ?? undefined,
165
- upsertCredentialMetadata: (
166
- service: string,
167
- field: string,
168
- policy?: Record<string, unknown>,
130
+ syncManualTokenConnection: async (
131
+ providerKey: string,
132
+ accountInfo?: string,
169
133
  ) => {
170
- const existing = credentialMetadataStore.find(
171
- (m) => m.service === service && m.field === field,
172
- );
173
- if (existing) {
174
- if (policy?.accountInfo !== undefined)
175
- existing.accountInfo = policy.accountInfo as string;
176
- return existing;
134
+ const { getSecureKeyAsync } = await import("../security/secure-keys.js");
135
+ if (providerKey !== "slack_channel") return;
136
+ const hasBotToken = !!(await getSecureKeyAsync(
137
+ credentialKey("slack_channel", "bot_token"),
138
+ ));
139
+ const hasAppToken = !!(await getSecureKeyAsync(
140
+ credentialKey("slack_channel", "app_token"),
141
+ ));
142
+ if (hasBotToken && hasAppToken) {
143
+ oauthConnectionStore[providerKey] = {
144
+ id: `conn-${providerKey}`,
145
+ status: "active",
146
+ accountInfo: accountInfo ?? null,
147
+ };
148
+ return;
177
149
  }
178
- const record = {
179
- service,
180
- field,
181
- accountInfo: policy?.accountInfo as string | undefined,
182
- };
183
- credentialMetadataStore.push(record);
184
- return record;
185
- },
186
- deleteCredentialMetadata: (service: string, field: string) => {
187
- const idx = credentialMetadataStore.findIndex(
188
- (m) => m.service === service && m.field === field,
189
- );
190
- if (idx !== -1) {
191
- credentialMetadataStore.splice(idx, 1);
192
- return true;
193
- }
194
- return false;
150
+ delete oauthConnectionStore[providerKey];
195
151
  },
196
- listCredentialMetadata: () => credentialMetadataStore,
197
- assertMetadataWritable: () => {},
198
- _setMetadataPath: () => {},
199
152
  }));
200
153
 
201
154
  // Mock fetch for Slack API validation
@@ -207,9 +160,28 @@ import {
207
160
  setSlackChannelConfig,
208
161
  } from "../daemon/handlers/config-slack-channel.js";
209
162
  import { credentialKey } from "../security/credential-key.js";
163
+ import { _setStorePath } from "../security/encrypted-store.js";
164
+ import {
165
+ _resetBackend,
166
+ getSecureKeyAsync,
167
+ setSecureKeyAsync,
168
+ } from "../security/secure-keys.js";
169
+ import {
170
+ _setMetadataPath,
171
+ listCredentialMetadata,
172
+ upsertCredentialMetadata,
173
+ } from "../tools/credentials/metadata-store.js";
210
174
 
211
175
  afterAll(() => {
212
176
  globalThis.fetch = originalFetch;
177
+ _setMetadataPath(null);
178
+ _setStorePath(null);
179
+ _resetBackend();
180
+ if (originalVellumDev === undefined) {
181
+ delete process.env.VELLUM_DEV;
182
+ } else {
183
+ process.env.VELLUM_DEV = originalVellumDev;
184
+ }
213
185
  try {
214
186
  rmSync(testDir, { recursive: true });
215
187
  } catch {
@@ -219,11 +191,14 @@ afterAll(() => {
219
191
 
220
192
  describe("Slack channel config handler", () => {
221
193
  beforeEach(() => {
222
- secureKeyStore = {};
223
- credentialMetadataStore = [];
224
194
  oauthConnectionStore = {};
225
195
  configStore = {};
226
196
  globalThis.fetch = originalFetch;
197
+ rmSync(secureStorePath, { force: true });
198
+ rmSync(metadataPath, { force: true });
199
+ _setStorePath(secureStorePath);
200
+ _resetBackend();
201
+ _setMetadataPath(metadataPath);
227
202
  });
228
203
 
229
204
  test("GET returns correct shape when not configured", async () => {
@@ -239,8 +214,16 @@ describe("Slack channel config handler", () => {
239
214
  id: "conn-slack",
240
215
  status: "active",
241
216
  };
242
- secureKeyStore[credentialKey("slack_channel", "bot_token")] = "xoxb-test";
243
- secureKeyStore[credentialKey("slack_channel", "app_token")] = "xapp-test";
217
+ await Promise.all([
218
+ setSecureKeyAsync(
219
+ credentialKey("slack_channel", "bot_token"),
220
+ "xoxb-test",
221
+ ),
222
+ setSecureKeyAsync(
223
+ credentialKey("slack_channel", "app_token"),
224
+ "xapp-test",
225
+ ),
226
+ ]);
244
227
 
245
228
  const result = await getSlackChannelConfig();
246
229
  expect(result.success).toBe(true);
@@ -249,13 +232,35 @@ describe("Slack channel config handler", () => {
249
232
  expect(result.connected).toBe(true);
250
233
  });
251
234
 
235
+ test("GET backfills the slack_channel connection row when chat setup stored both credentials", async () => {
236
+ await Promise.all([
237
+ setSecureKeyAsync(
238
+ credentialKey("slack_channel", "bot_token"),
239
+ "xoxb-test",
240
+ ),
241
+ setSecureKeyAsync(
242
+ credentialKey("slack_channel", "app_token"),
243
+ "xapp-test",
244
+ ),
245
+ ]);
246
+
247
+ const result = await getSlackChannelConfig();
248
+
249
+ expect(result.success).toBe(true);
250
+ expect(result.connected).toBe(true);
251
+ expect(oauthConnectionStore["slack_channel"]).toBeDefined();
252
+ });
253
+
252
254
  test("GET reports per-field token presence independently of connection row", async () => {
253
255
  // Only bot_token in keychain, no app_token, but connection row exists
254
256
  oauthConnectionStore["slack_channel"] = {
255
257
  id: "conn-slack",
256
258
  status: "active",
257
259
  };
258
- secureKeyStore[credentialKey("slack_channel", "bot_token")] = "xoxb-test";
260
+ await setSecureKeyAsync(
261
+ credentialKey("slack_channel", "bot_token"),
262
+ "xoxb-test",
263
+ );
259
264
 
260
265
  const result = await getSlackChannelConfig();
261
266
  expect(result.success).toBe(true);
@@ -270,8 +275,16 @@ describe("Slack channel config handler", () => {
270
275
  id: "conn-slack",
271
276
  status: "active",
272
277
  };
273
- secureKeyStore[credentialKey("slack_channel", "bot_token")] = "xoxb-test";
274
- secureKeyStore[credentialKey("slack_channel", "app_token")] = "xapp-test";
278
+ await Promise.all([
279
+ setSecureKeyAsync(
280
+ credentialKey("slack_channel", "bot_token"),
281
+ "xoxb-test",
282
+ ),
283
+ setSecureKeyAsync(
284
+ credentialKey("slack_channel", "app_token"),
285
+ "xapp-test",
286
+ ),
287
+ ]);
275
288
  configStore = {
276
289
  slack: {
277
290
  teamId: "T123",
@@ -301,9 +314,9 @@ describe("Slack channel config handler", () => {
301
314
  );
302
315
  expect(result.success).toBe(true);
303
316
  expect(result.hasAppToken).toBe(true);
304
- expect(secureKeyStore[credentialKey("slack_channel", "app_token")]).toBe(
305
- "xapp-valid-token-123",
306
- );
317
+ expect(
318
+ await getSecureKeyAsync(credentialKey("slack_channel", "app_token")),
319
+ ).toBe("xapp-valid-token-123");
307
320
  });
308
321
 
309
322
  test("POST validates bot token via Slack auth.test API and writes config", async () => {
@@ -357,16 +370,18 @@ describe("Slack channel config handler", () => {
357
370
  });
358
371
 
359
372
  test("DELETE clears credentials and config", async () => {
360
- secureKeyStore[credentialKey("slack_channel", "bot_token")] = "xoxb-test";
361
- secureKeyStore[credentialKey("slack_channel", "app_token")] = "xapp-test";
362
- credentialMetadataStore.push({
363
- service: "slack_channel",
364
- field: "bot_token",
365
- });
366
- credentialMetadataStore.push({
367
- service: "slack_channel",
368
- field: "app_token",
369
- });
373
+ await Promise.all([
374
+ setSecureKeyAsync(
375
+ credentialKey("slack_channel", "bot_token"),
376
+ "xoxb-test",
377
+ ),
378
+ setSecureKeyAsync(
379
+ credentialKey("slack_channel", "app_token"),
380
+ "xapp-test",
381
+ ),
382
+ ]);
383
+ upsertCredentialMetadata("slack_channel", "bot_token", {});
384
+ upsertCredentialMetadata("slack_channel", "app_token", {});
370
385
  configStore = {
371
386
  slack: {
372
387
  teamId: "T123",
@@ -383,12 +398,12 @@ describe("Slack channel config handler", () => {
383
398
  expect(result.connected).toBe(false);
384
399
 
385
400
  expect(
386
- secureKeyStore[credentialKey("slack_channel", "bot_token")],
401
+ await getSecureKeyAsync(credentialKey("slack_channel", "bot_token")),
387
402
  ).toBeUndefined();
388
403
  expect(
389
- secureKeyStore[credentialKey("slack_channel", "app_token")],
404
+ await getSecureKeyAsync(credentialKey("slack_channel", "app_token")),
390
405
  ).toBeUndefined();
391
- expect(credentialMetadataStore).toHaveLength(0);
406
+ expect(listCredentialMetadata()).toHaveLength(0);
392
407
 
393
408
  // Assert config values were cleared
394
409
  const slack = configStore.slack as Record<string, unknown>;
@@ -44,9 +44,9 @@ mock.module("../config/loader.js", () => ({
44
44
  "image-generation": {
45
45
  mode: "your-own",
46
46
  provider: "gemini",
47
- model: "gemini-2.5-flash-image",
47
+ model: "gemini-3.1-flash-image-preview",
48
48
  },
49
- "web-search": { mode: "your-own", provider: "anthropic-native" },
49
+ "web-search": { mode: "your-own", provider: "inference-provider-native" },
50
50
  },
51
51
  }),
52
52
  }));
@@ -56,9 +56,9 @@ mock.module("../config/loader.js", () => ({
56
56
  "image-generation": {
57
57
  mode: "your-own",
58
58
  provider: "gemini",
59
- model: "gemini-2.5-flash-image",
59
+ model: "gemini-3.1-flash-image-preview",
60
60
  },
61
- "web-search": { mode: "your-own", provider: "anthropic-native" },
61
+ "web-search": { mode: "your-own", provider: "inference-provider-native" },
62
62
  },
63
63
  }),
64
64
  }));
@@ -36,9 +36,9 @@ mock.module("../config/loader.js", () => ({
36
36
  "image-generation": {
37
37
  mode: "your-own",
38
38
  provider: "gemini",
39
- model: "gemini-2.5-flash-image",
39
+ model: "gemini-3.1-flash-image-preview",
40
40
  },
41
- "web-search": { mode: "your-own", provider: "anthropic-native" },
41
+ "web-search": { mode: "your-own", provider: "inference-provider-native" },
42
42
  },
43
43
  }),
44
44
  getSwarmDisabledConfig: () => ({
@@ -43,9 +43,12 @@ mock.module("../util/platform.js", () => ({
43
43
  readSessionToken: () => null,
44
44
  }));
45
45
 
46
- const noopLogger = new Proxy({} as Record<string, unknown>, {
47
- get: (_target, prop) => (prop === "child" ? () => noopLogger : () => {}),
48
- });
46
+ const noopLogger: Record<string, unknown> = new Proxy(
47
+ {} as Record<string, unknown>,
48
+ {
49
+ get: (_target, prop) => (prop === "child" ? () => noopLogger : () => {}),
50
+ },
51
+ );
49
52
 
50
53
  // eslint-disable-next-line @typescript-eslint/no-require-imports
51
54
  const realLogger = require("../util/logger.js");
@@ -62,7 +65,6 @@ mock.module("../config/loader.js", () => ({
62
65
  getConfig: () => ({
63
66
  ui: {},
64
67
 
65
- sandbox: { enabled: true },
66
68
  services: {
67
69
  inference: {
68
70
  mode: "your-own",
@@ -72,9 +74,9 @@ mock.module("../config/loader.js", () => ({
72
74
  "image-generation": {
73
75
  mode: "your-own",
74
76
  provider: "gemini",
75
- model: "gemini-2.5-flash-image",
77
+ model: "gemini-3.1-flash-image-preview",
76
78
  },
77
- "web-search": { mode: "your-own", provider: "anthropic-native" },
79
+ "web-search": { mode: "your-own", provider: "inference-provider-native" },
78
80
  },
79
81
  }),
80
82
  loadConfig: () => ({}),
@@ -100,7 +102,6 @@ const {
100
102
  buildSystemPrompt,
101
103
  ensurePromptFiles,
102
104
  stripCommentLines,
103
- buildExternalCommsIdentitySection,
104
105
  SYSTEM_PROMPT_CACHE_BOUNDARY,
105
106
  } = await import("../prompts/system-prompt.js");
106
107
 
@@ -119,16 +120,13 @@ function basePrompt(result: string): string {
119
120
  boundaryIdx >= 0
120
121
  ? result.slice(boundaryIdx + SYSTEM_PROMPT_CACHE_BOUNDARY.length)
121
122
  : result;
122
- // Strip the hardcoded em-dash instruction preamble (in case boundary is absent)
123
- const emDashLine =
124
- "IMPORTANT: Never use em dashes (\u2014) in your messages. Use commas, periods, or just start a new sentence instead.";
125
- if (s.startsWith(emDashLine)) {
126
- s = s.slice(emDashLine.length).replace(/^\n\n/, "");
127
- }
128
123
  for (const heading of [
129
124
  "## Configuration",
130
125
  "## Skills Catalog",
131
126
  "## Available Skills",
127
+ "## External Communications Identity",
128
+ "## Connected Services",
129
+ "## Dynamic Skill Authoring Workflow",
132
130
  ]) {
133
131
  if (s.startsWith(heading)) {
134
132
  s = "";
@@ -211,13 +209,7 @@ describe("buildSystemPrompt", () => {
211
209
  const result = buildSystemPrompt();
212
210
  expect(result).toContain("Custom identity");
213
211
  expect(result).toContain("## Available Skills");
214
- expect(result).toContain("<available_skills>");
215
- expect(result).toContain('id="release-checklist"');
216
- expect(result).toContain('name="Release Checklist"');
217
- expect(result).toContain('description="Deployment checks."');
218
- expect(result).toContain(
219
- "call `skill_load` to load the full instructions, then use `skill_execute` to invoke the skill's tools.",
220
- );
212
+ expect(result).toContain("**release-checklist**: Deployment checks");
221
213
  });
222
214
 
223
215
  test("keeps SOUL.md and IDENTITY.md additive with skills", () => {
@@ -239,39 +231,15 @@ describe("buildSystemPrompt", () => {
239
231
  );
240
232
  });
241
233
 
242
- test("includes swarm guidance section", () => {
243
- const result = buildSystemPrompt();
244
- expect(result).toContain("## Parallel Task Orchestration");
245
- expect(result).toContain("swarm_delegate");
246
- });
247
-
248
- test("includes external service access preference section", () => {
234
+ test("includes external service access section", () => {
249
235
  const result = buildSystemPrompt();
250
- expect(result).toContain("## External Service Access Preference");
251
- expect(result).toContain("CLI tools via host_bash");
252
- expect(result).toContain("Browser automation as last resort");
236
+ expect(result).toContain("## External Service Access");
237
+ expect(result).toContain("browser automation as last resort");
253
238
  });
254
239
 
255
- test("includes external comms identity section", () => {
240
+ test("does not include removed sections", () => {
256
241
  const result = buildSystemPrompt();
257
- expect(result).toContain("## External Communications Identity");
258
- });
259
-
260
- test("external comms identity section contains assistant guidance and resolved user reference", () => {
261
- const result = buildSystemPrompt();
262
- expect(result).toContain("Refer to yourself as an **assistant**");
263
- expect(result).toContain("on behalf of **John**");
264
- });
265
-
266
- test("buildExternalCommsIdentitySection returns section with expected content", () => {
267
- const section = buildExternalCommsIdentitySection();
268
- expect(section).toContain("## External Communications Identity");
269
- expect(section).toContain("assistant");
270
- expect(section).toContain("John");
271
- expect(section).toContain(
272
- "Do not volunteer that you are an AI unless directly asked",
273
- );
274
- expect(section).toContain("Occasional variations are acceptable");
242
+ expect(result).not.toContain("## External Communications Identity");
275
243
  });
276
244
 
277
245
  test("does not include removed domain routing sections", () => {
@@ -282,18 +250,9 @@ describe("buildSystemPrompt", () => {
282
250
  expect(result).not.toContain("## Routing: Starter Tasks");
283
251
  });
284
252
 
285
- test("includes memory persistence section", () => {
253
+ test("does not include removed memory persistence section", () => {
286
254
  const result = buildSystemPrompt();
287
- expect(result).toContain("## Memory Persistence");
288
- expect(result).toContain("memory_manage");
289
- expect(result).toContain("Saved > unsaved. Always.");
290
- });
291
-
292
- test("config section uses workspace directory from platform util", () => {
293
- const result = buildSystemPrompt();
294
- expect(result).toContain(
295
- `Your configuration directory is \`${TEST_DIR}/\`.`,
296
- );
255
+ expect(result).not.toContain("## Memory Persistence");
297
256
  });
298
257
 
299
258
  test("omits user skills from catalog when none are configured", () => {
@@ -380,12 +339,6 @@ describe("buildSystemPrompt", () => {
380
339
  expect(result).not.toContain("### Update Handling");
381
340
  });
382
341
 
383
- test("config section lists UPDATES.md", () => {
384
- const result = buildSystemPrompt();
385
- expect(result).toContain("`UPDATES.md`");
386
- expect(result).toContain("Release update notes");
387
- });
388
-
389
342
  test("strips comment lines starting with _ from prompt files", () => {
390
343
  writeFileSync(
391
344
  join(TEST_DIR, "IDENTITY.md"),
@@ -0,0 +1,121 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ import { credentialKey } from "../security/credential-key.js";
4
+
5
+ let secureKeyStore: Record<string, string> = {};
6
+ let oauthConnectionStore: Record<
7
+ string,
8
+ { id: string; status: string; accountInfo?: string | null }
9
+ > = {};
10
+ const syncCalls: Array<{ providerKey: string; accountInfo?: string }> = [];
11
+
12
+ mock.module("../config/loader.js", () => ({
13
+ getConfig: () => ({ telegram: {}, ui: {} }),
14
+ loadRawConfig: () => ({}),
15
+ saveRawConfig: () => {},
16
+ saveConfig: () => {},
17
+ invalidateConfigCache: () => {},
18
+ setNestedValue: () => {},
19
+ }));
20
+
21
+ mock.module("../inbound/platform-callback-registration.js", () => ({
22
+ registerCallbackRoute: async () => {},
23
+ shouldUsePlatformCallbacks: () => false,
24
+ }));
25
+
26
+ mock.module("../daemon/handlers/shared.js", () => ({
27
+ log: {
28
+ warn: () => {},
29
+ info: () => {},
30
+ error: () => {},
31
+ debug: () => {},
32
+ },
33
+ }));
34
+
35
+ mock.module("../security/secure-keys.js", () => ({
36
+ getSecureKeyAsync: async (account: string) =>
37
+ secureKeyStore[account] ?? undefined,
38
+ setSecureKeyAsync: async (account: string, value: string) => {
39
+ secureKeyStore[account] = value;
40
+ return true;
41
+ },
42
+ deleteSecureKeyAsync: async (account: string) => {
43
+ if (account in secureKeyStore) {
44
+ delete secureKeyStore[account];
45
+ return "deleted" as const;
46
+ }
47
+ return "not-found" as const;
48
+ },
49
+ }));
50
+
51
+ mock.module("../oauth/oauth-store.js", () => ({
52
+ getConnectionByProvider: (providerKey: string) =>
53
+ oauthConnectionStore[providerKey] ?? undefined,
54
+ }));
55
+
56
+ mock.module("../oauth/manual-token-connection.js", () => ({
57
+ ensureManualTokenConnection: async () => {},
58
+ removeManualTokenConnection: () => {},
59
+ syncManualTokenConnection: async (
60
+ providerKey: string,
61
+ accountInfo?: string,
62
+ ) => {
63
+ syncCalls.push({ providerKey, accountInfo });
64
+ if (providerKey !== "telegram") return;
65
+ const hasBotToken =
66
+ !!secureKeyStore[credentialKey("telegram", "bot_token")];
67
+ const hasWebhookSecret =
68
+ !!secureKeyStore[credentialKey("telegram", "webhook_secret")];
69
+ if (hasBotToken && hasWebhookSecret) {
70
+ oauthConnectionStore[providerKey] = {
71
+ id: `conn-${providerKey}`,
72
+ status: "active",
73
+ accountInfo: accountInfo ?? null,
74
+ };
75
+ return;
76
+ }
77
+ delete oauthConnectionStore[providerKey];
78
+ },
79
+ }));
80
+
81
+ mock.module("../telegram/bot-username.js", () => ({
82
+ getTelegramBotId: () => "123456",
83
+ getTelegramBotUsername: () => "testbot",
84
+ }));
85
+
86
+ mock.module("../tools/credentials/metadata-store.js", () => ({
87
+ deleteCredentialMetadata: () => true,
88
+ upsertCredentialMetadata: () => ({}),
89
+ }));
90
+
91
+ const originalFetch = globalThis.fetch;
92
+
93
+ import { getTelegramConfig } from "../daemon/handlers/config-telegram.js";
94
+
95
+ describe("Telegram config handler", () => {
96
+ beforeEach(() => {
97
+ secureKeyStore = {};
98
+ oauthConnectionStore = {};
99
+ syncCalls.length = 0;
100
+ globalThis.fetch = originalFetch;
101
+ });
102
+
103
+ afterEach(() => {
104
+ globalThis.fetch = originalFetch;
105
+ });
106
+
107
+ test("GET backfills telegram connection metadata with @botUsername", async () => {
108
+ secureKeyStore[credentialKey("telegram", "bot_token")] = "123:abc";
109
+ secureKeyStore[credentialKey("telegram", "webhook_secret")] = "secret";
110
+
111
+ const result = await getTelegramConfig();
112
+
113
+ expect(result.success).toBe(true);
114
+ expect(result.botUsername).toBe("testbot");
115
+ expect(result.connected).toBe(true);
116
+ expect(syncCalls).toEqual([
117
+ { providerKey: "telegram", accountInfo: "@testbot" },
118
+ ]);
119
+ expect(oauthConnectionStore["telegram"]?.accountInfo).toBe("@testbot");
120
+ });
121
+ });
@@ -662,7 +662,7 @@ describe("Shell tool input validation", () => {
662
662
  };
663
663
  expect(def.name).toBe("bash");
664
664
  expect(schema.required).toContain("command");
665
- expect(schema.required).toContain("reason");
665
+ expect(schema.required).toContain("activity");
666
666
  expect(schema.properties.command).toBeDefined();
667
667
  expect(schema.properties.timeout_seconds).toBeDefined();
668
668
  expect(schema.properties.network_mode).toBeDefined();
@@ -32,8 +32,7 @@ mock.module("../config/loader.js", () => ({
32
32
  shellMaxTimeoutSec: 600,
33
33
  permissionTimeoutSec: 300,
34
34
  },
35
- sandbox: { enabled: false, backend: "native" as const },
36
- rateLimit: { maxRequestsPerMinute: 0, maxTokensPerSession: 0 },
35
+ rateLimit: { maxRequestsPerMinute: 0 },
37
36
  secretDetection: {
38
37
  enabled: false,
39
38
  action: "warn" as const,
@@ -26,7 +26,7 @@ const mockConfig = {
26
26
  network: "none" as const,
27
27
  },
28
28
  },
29
- rateLimit: { maxRequestsPerMinute: 0, maxTokensPerSession: 0 },
29
+ rateLimit: { maxRequestsPerMinute: 0 },
30
30
  secretDetection: {
31
31
  enabled: false,
32
32
  action: "warn" as const,