@vellumai/assistant 0.4.49 → 0.4.51

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 (353) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/integrations.md +2 -2
  4. package/docs/architecture/keychain-broker.md +6 -6
  5. package/docs/architecture/memory.md +180 -119
  6. package/knip.json +32 -0
  7. package/package.json +3 -2
  8. package/src/__tests__/agent-loop.test.ts +3 -1
  9. package/src/__tests__/anthropic-provider.test.ts +114 -23
  10. package/src/__tests__/approval-cascade.test.ts +1 -15
  11. package/src/__tests__/approval-routes-http.test.ts +2 -0
  12. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  13. package/src/__tests__/btw-routes.test.ts +61 -5
  14. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  15. package/src/__tests__/checker.test.ts +13 -0
  16. package/src/__tests__/config-schema.test.ts +1 -68
  17. package/src/__tests__/config-watcher.test.ts +8 -0
  18. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  19. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  20. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  21. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  22. package/src/__tests__/credential-security-invariants.test.ts +8 -7
  23. package/src/__tests__/credential-vault-unit.test.ts +23 -18
  24. package/src/__tests__/credential-vault.test.ts +30 -18
  25. package/src/__tests__/credentials-cli.test.ts +257 -82
  26. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  27. package/src/__tests__/date-context.test.ts +93 -77
  28. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  29. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  30. package/src/__tests__/history-repair.test.ts +245 -0
  31. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  32. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  33. package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
  34. package/src/__tests__/integration-status.test.ts +31 -30
  35. package/src/__tests__/invite-redemption-service.test.ts +166 -13
  36. package/src/__tests__/invite-routes-http.test.ts +166 -5
  37. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  38. package/src/__tests__/list-messages-attachments.test.ts +193 -0
  39. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  40. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  41. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  42. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  43. package/src/__tests__/memory-regressions.test.ts +477 -2841
  44. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  45. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  46. package/src/__tests__/mime-builder.test.ts +28 -0
  47. package/src/__tests__/native-web-search.test.ts +1 -0
  48. package/src/__tests__/oauth-cli.test.ts +824 -31
  49. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  50. package/src/__tests__/oauth-store.test.ts +363 -17
  51. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  52. package/src/__tests__/registry.test.ts +0 -1
  53. package/src/__tests__/relay-server.test.ts +55 -1
  54. package/src/__tests__/schedule-tools.test.ts +32 -0
  55. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  56. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  57. package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
  58. package/src/__tests__/secure-keys.test.ts +78 -18
  59. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  60. package/src/__tests__/server-history-render.test.ts +2 -2
  61. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  62. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  63. package/src/__tests__/session-agent-loop.test.ts +19 -15
  64. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  65. package/src/__tests__/session-error.test.ts +124 -2
  66. package/src/__tests__/session-history-web-search.test.ts +918 -0
  67. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  68. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  69. package/src/__tests__/session-queue.test.ts +37 -27
  70. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  71. package/src/__tests__/session-slash-known.test.ts +1 -15
  72. package/src/__tests__/session-slash-queue.test.ts +1 -15
  73. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  74. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  75. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  76. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  77. package/src/__tests__/skills-install-extract.test.ts +93 -0
  78. package/src/__tests__/skills.test.ts +2 -2
  79. package/src/__tests__/skillssh-registry.test.ts +451 -0
  80. package/src/__tests__/slack-channel-config.test.ts +10 -8
  81. package/src/__tests__/trust-store.test.ts +15 -0
  82. package/src/__tests__/twilio-config.test.ts +11 -10
  83. package/src/__tests__/twilio-provider.test.ts +9 -4
  84. package/src/__tests__/voice-invite-redemption.test.ts +85 -5
  85. package/src/agent/ax-tree-compaction.test.ts +51 -0
  86. package/src/agent/loop.ts +39 -12
  87. package/src/approvals/AGENTS.md +1 -1
  88. package/src/approvals/guardian-request-resolvers.ts +14 -2
  89. package/src/bundler/compiler-tools.ts +66 -2
  90. package/src/calls/call-domain.ts +134 -3
  91. package/src/calls/call-store.ts +6 -0
  92. package/src/calls/relay-server.ts +44 -6
  93. package/src/calls/relay-setup-router.ts +17 -1
  94. package/src/calls/twilio-config.ts +5 -4
  95. package/src/calls/twilio-provider.ts +14 -9
  96. package/src/calls/twilio-rest.ts +10 -7
  97. package/src/calls/types.ts +3 -1
  98. package/src/cli/commands/config.ts +14 -9
  99. package/src/cli/commands/contacts.ts +3 -0
  100. package/src/cli/commands/credentials.ts +170 -174
  101. package/src/cli/commands/doctor.ts +11 -8
  102. package/src/cli/commands/keys.ts +9 -9
  103. package/src/cli/commands/mcp.ts +46 -59
  104. package/src/cli/commands/memory.ts +16 -165
  105. package/src/cli/commands/oauth/apps.ts +68 -10
  106. package/src/cli/commands/oauth/connections.ts +475 -105
  107. package/src/cli/commands/oauth/index.ts +3 -3
  108. package/src/cli/commands/oauth/providers.ts +18 -4
  109. package/src/cli/commands/sessions.ts +5 -2
  110. package/src/cli/commands/skills.ts +173 -1
  111. package/src/cli/http-client.ts +0 -20
  112. package/src/cli/main-screen.tsx +2 -2
  113. package/src/cli/program.ts +5 -6
  114. package/src/cli.ts +20 -22
  115. package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
  116. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  117. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +35 -11
  119. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  120. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  121. package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
  135. package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
  136. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
  137. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
  138. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
  139. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
  140. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
  141. package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
  142. package/src/config/bundled-skills/messaging/SKILL.md +1 -1
  143. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  144. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  145. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
  146. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
  147. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
  148. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
  149. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
  150. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
  151. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
  152. package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
  153. package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
  154. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
  155. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
  156. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
  157. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
  158. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
  159. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
  160. package/src/config/bundled-tool-registry.ts +2 -5
  161. package/src/config/loader.ts +6 -42
  162. package/src/config/schema.ts +1 -12
  163. package/src/config/schemas/memory-lifecycle.ts +0 -9
  164. package/src/config/schemas/memory-processing.ts +0 -180
  165. package/src/config/schemas/memory-retrieval.ts +32 -104
  166. package/src/config/schemas/memory.ts +0 -10
  167. package/src/config/types.ts +0 -4
  168. package/src/contacts/contact-store.ts +39 -2
  169. package/src/contacts/contacts-write.ts +9 -0
  170. package/src/context/window-manager.ts +4 -1
  171. package/src/daemon/config-watcher.ts +55 -2
  172. package/src/daemon/daemon-control.ts +1 -1
  173. package/src/daemon/date-context.ts +114 -31
  174. package/src/daemon/handlers/config-ingress.ts +2 -2
  175. package/src/daemon/handlers/config-slack-channel.ts +59 -39
  176. package/src/daemon/handlers/config-telegram.ts +23 -14
  177. package/src/daemon/handlers/session-history.ts +1 -358
  178. package/src/daemon/handlers/sessions.ts +18 -13
  179. package/src/daemon/handlers/shared.ts +3 -17
  180. package/src/daemon/handlers/skills.ts +20 -1
  181. package/src/daemon/history-repair.ts +72 -8
  182. package/src/daemon/host-cu-proxy.ts +55 -26
  183. package/src/daemon/lifecycle.ts +39 -4
  184. package/src/daemon/mcp-reload-service.ts +2 -2
  185. package/src/daemon/message-types/computer-use.ts +1 -12
  186. package/src/daemon/message-types/memory.ts +4 -16
  187. package/src/daemon/message-types/messages.ts +1 -0
  188. package/src/daemon/message-types/sessions.ts +4 -42
  189. package/src/daemon/server.ts +6 -1
  190. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  191. package/src/daemon/session-agent-loop.ts +334 -48
  192. package/src/daemon/session-error.ts +89 -6
  193. package/src/daemon/session-history.ts +17 -7
  194. package/src/daemon/session-media-retry.ts +6 -2
  195. package/src/daemon/session-memory.ts +69 -149
  196. package/src/daemon/session-process.ts +10 -1
  197. package/src/daemon/session-runtime-assembly.ts +49 -19
  198. package/src/daemon/session-slash.ts +3 -5
  199. package/src/daemon/session-surfaces.ts +4 -1
  200. package/src/daemon/session-tool-setup.ts +7 -1
  201. package/src/daemon/session.ts +12 -2
  202. package/src/email/providers/index.ts +2 -2
  203. package/src/instrument.ts +61 -1
  204. package/src/media/avatar-router.ts +1 -1
  205. package/src/memory/admin.ts +2 -191
  206. package/src/memory/canonical-guardian-store.ts +38 -2
  207. package/src/memory/conversation-crud.ts +0 -33
  208. package/src/memory/conversation-queries.ts +25 -83
  209. package/src/memory/db-init.ts +32 -0
  210. package/src/memory/embedding-backend.ts +84 -8
  211. package/src/memory/embedding-types.ts +9 -1
  212. package/src/memory/indexer.ts +7 -46
  213. package/src/memory/invite-store.ts +19 -0
  214. package/src/memory/items-extractor.ts +274 -76
  215. package/src/memory/job-handlers/backfill.ts +2 -127
  216. package/src/memory/job-handlers/cleanup.ts +2 -16
  217. package/src/memory/job-handlers/extraction.ts +2 -138
  218. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  219. package/src/memory/job-handlers/summarization.ts +3 -148
  220. package/src/memory/job-utils.ts +21 -59
  221. package/src/memory/jobs-store.ts +1 -159
  222. package/src/memory/jobs-worker.ts +9 -52
  223. package/src/memory/migrations/104-core-indexes.ts +3 -3
  224. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  225. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  226. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  227. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  228. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  229. package/src/memory/migrations/154-drop-fts.ts +20 -0
  230. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  231. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  232. package/src/memory/migrations/157-invite-contact-id.ts +104 -0
  233. package/src/memory/migrations/index.ts +8 -0
  234. package/src/memory/migrations/registry.ts +6 -0
  235. package/src/memory/qdrant-client.ts +148 -51
  236. package/src/memory/raw-query.ts +1 -1
  237. package/src/memory/retriever.test.ts +294 -273
  238. package/src/memory/retriever.ts +421 -645
  239. package/src/memory/schema/calls.ts +2 -0
  240. package/src/memory/schema/contacts.ts +1 -0
  241. package/src/memory/schema/memory-core.ts +3 -48
  242. package/src/memory/schema/oauth.ts +2 -0
  243. package/src/memory/search/formatting.ts +263 -176
  244. package/src/memory/search/lexical.ts +1 -254
  245. package/src/memory/search/ranking.ts +0 -455
  246. package/src/memory/search/semantic.ts +100 -14
  247. package/src/memory/search/staleness.ts +47 -0
  248. package/src/memory/search/tier-classifier.ts +21 -0
  249. package/src/memory/search/types.ts +15 -77
  250. package/src/memory/task-memory-cleanup.ts +4 -6
  251. package/src/messaging/provider.ts +1 -1
  252. package/src/messaging/providers/gmail/adapter.ts +1 -1
  253. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  254. package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
  255. package/src/messaging/providers/whatsapp/adapter.ts +13 -9
  256. package/src/messaging/registry.ts +9 -5
  257. package/src/oauth/byo-connection.test.ts +40 -25
  258. package/src/oauth/connect-orchestrator.ts +4 -10
  259. package/src/oauth/connection-resolver.ts +20 -6
  260. package/src/oauth/manual-token-connection.ts +5 -5
  261. package/src/oauth/oauth-store.ts +183 -31
  262. package/src/oauth/platform-connection.test.ts +1 -1
  263. package/src/oauth/provider-behaviors.ts +503 -4
  264. package/src/oauth/seed-providers.ts +214 -8
  265. package/src/oauth/token-persistence.ts +31 -16
  266. package/src/permissions/defaults.ts +1 -0
  267. package/src/permissions/trust-store.ts +23 -1
  268. package/src/playbooks/playbook-compiler.ts +1 -1
  269. package/src/prompts/system-prompt.ts +18 -2
  270. package/src/providers/anthropic/client.ts +56 -126
  271. package/src/providers/types.ts +7 -1
  272. package/src/runtime/AGENTS.md +9 -0
  273. package/src/runtime/auth/route-policy.ts +6 -3
  274. package/src/runtime/channel-readiness-service.ts +48 -40
  275. package/src/runtime/guardian-reply-router.ts +24 -22
  276. package/src/runtime/http-server.ts +2 -2
  277. package/src/runtime/http-types.ts +2 -0
  278. package/src/runtime/invite-redemption-service.ts +72 -12
  279. package/src/runtime/invite-service.ts +43 -0
  280. package/src/runtime/middleware/twilio-validation.ts +1 -1
  281. package/src/runtime/pending-interactions.ts +2 -2
  282. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  283. package/src/runtime/routes/btw-routes.ts +10 -5
  284. package/src/runtime/routes/conversation-routes.ts +56 -11
  285. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  286. package/src/runtime/routes/integrations/slack/channel.ts +2 -2
  287. package/src/runtime/routes/integrations/telegram.ts +2 -2
  288. package/src/runtime/routes/integrations/twilio.ts +17 -17
  289. package/src/runtime/routes/invite-routes.ts +29 -4
  290. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  291. package/src/runtime/routes/memory-item-routes.ts +503 -0
  292. package/src/runtime/routes/secret-routes.ts +17 -0
  293. package/src/runtime/routes/session-management-routes.ts +3 -3
  294. package/src/runtime/routes/settings-routes.ts +3 -3
  295. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  296. package/src/runtime/routes/workspace-routes.ts +9 -4
  297. package/src/runtime/routes/workspace-utils.ts +8 -2
  298. package/src/schedule/integration-status.ts +26 -19
  299. package/src/security/keychain-broker-client.ts +17 -4
  300. package/src/security/oauth2.ts +6 -7
  301. package/src/security/secure-keys.ts +44 -19
  302. package/src/security/token-manager.ts +46 -39
  303. package/src/services/vercel-deploy.ts +0 -24
  304. package/src/signals/confirm.ts +78 -0
  305. package/src/signals/mcp-reload.ts +18 -0
  306. package/src/skills/catalog-install.ts +74 -18
  307. package/src/skills/skillssh-registry.ts +503 -0
  308. package/src/tools/assets/search.ts +5 -1
  309. package/src/tools/computer-use/definitions.ts +0 -10
  310. package/src/tools/computer-use/registry.ts +1 -1
  311. package/src/tools/credentials/vault.ts +22 -7
  312. package/src/tools/memory/definitions.ts +4 -13
  313. package/src/tools/memory/handlers.test.ts +83 -103
  314. package/src/tools/memory/handlers.ts +50 -85
  315. package/src/tools/network/script-proxy/session-manager.ts +8 -8
  316. package/src/tools/schedule/create.ts +10 -3
  317. package/src/tools/schedule/update.ts +8 -1
  318. package/src/tools/skills/load.ts +25 -2
  319. package/src/watcher/provider-types.ts +1 -1
  320. package/src/watcher/providers/github.ts +1 -1
  321. package/src/watcher/providers/gmail.ts +3 -3
  322. package/src/watcher/providers/google-calendar.ts +3 -3
  323. package/src/watcher/providers/linear.ts +1 -1
  324. package/src/__tests__/clarification-resolver.test.ts +0 -193
  325. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  326. package/src/__tests__/conflict-policy.test.ts +0 -269
  327. package/src/__tests__/conflict-store.test.ts +0 -372
  328. package/src/__tests__/contradiction-checker.test.ts +0 -361
  329. package/src/__tests__/entity-extractor.test.ts +0 -211
  330. package/src/__tests__/entity-search.test.ts +0 -1117
  331. package/src/__tests__/profile-compiler.test.ts +0 -392
  332. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  333. package/src/__tests__/session-profile-injection.test.ts +0 -557
  334. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  335. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  336. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  337. package/src/daemon/session-conflict-gate.ts +0 -167
  338. package/src/daemon/session-dynamic-profile.ts +0 -77
  339. package/src/memory/clarification-resolver.ts +0 -417
  340. package/src/memory/conflict-intent.ts +0 -205
  341. package/src/memory/conflict-policy.ts +0 -127
  342. package/src/memory/conflict-store.ts +0 -410
  343. package/src/memory/contradiction-checker.ts +0 -508
  344. package/src/memory/entity-extractor.ts +0 -535
  345. package/src/memory/format-recall.ts +0 -47
  346. package/src/memory/fts-reconciler.ts +0 -165
  347. package/src/memory/job-handlers/conflict.ts +0 -200
  348. package/src/memory/profile-compiler.ts +0 -195
  349. package/src/memory/recall-cache.ts +0 -117
  350. package/src/memory/search/entity.ts +0 -535
  351. package/src/memory/search/query-expansion.test.ts +0 -70
  352. package/src/memory/search/query-expansion.ts +0 -118
  353. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -1,11 +1,7 @@
1
1
  export type CandidateType = "segment" | "item" | "summary" | "media";
2
- export type CandidateSource =
3
- | "lexical"
4
- | "semantic"
5
- | "recency"
6
- | "entity_direct"
7
- | "entity_relation"
8
- | "item_direct";
2
+ export type CandidateSource = "semantic" | "recency";
3
+
4
+ export type StalenessLevel = "fresh" | "aging" | "stale" | "very_stale";
9
5
 
10
6
  export interface Candidate {
11
7
  key: string;
@@ -18,10 +14,11 @@ export interface Candidate {
18
14
  confidence: number;
19
15
  importance: number;
20
16
  createdAt: number;
21
- lexical: number;
22
17
  semantic: number;
23
18
  recency: number;
24
19
  finalScore: number;
20
+ tier?: 1 | 2 | null;
21
+ staleness?: StalenessLevel;
25
22
  }
26
23
 
27
24
  export interface MemoryRecallCandiateDebug {
@@ -29,7 +26,6 @@ export interface MemoryRecallCandiateDebug {
29
26
  type: CandidateType;
30
27
  kind: string;
31
28
  finalScore: number;
32
- lexical: number;
33
29
  semantic: number;
34
30
  recency: number;
35
31
  }
@@ -39,7 +35,7 @@ export type DegradationReason =
39
35
  | "qdrant_unavailable"
40
36
  | "embedding_generation_failed";
41
37
 
42
- export type FallbackSource = "lexical" | "recency" | "direct_item" | "entity";
38
+ export type FallbackSource = "recency";
43
39
 
44
40
  export interface DegradationStatus {
45
41
  semanticUnavailable: boolean;
@@ -54,22 +50,22 @@ export interface MemoryRecallResult {
54
50
  reason?: string;
55
51
  provider?: string;
56
52
  model?: string;
57
- lexicalHits: number;
58
53
  semanticHits: number;
59
54
  recencyHits: number;
60
- entityHits: number;
61
- relationSeedEntityCount: number;
62
- relationTraversedEdgeCount: number;
63
- relationNeighborEntityCount: number;
64
- relationExpandedItemCount: number;
65
- earlyTerminated: boolean;
66
55
  mergedCount: number;
67
56
  selectedCount: number;
68
- rerankApplied: boolean;
69
57
  injectedTokens: number;
70
58
  injectedText: string;
71
59
  latencyMs: number;
72
60
  topCandidates: MemoryRecallCandiateDebug[];
61
+ /** Count of tier 1 candidates after demotion. */
62
+ tier1Count?: number;
63
+ /** Count of tier 2 candidates after demotion. */
64
+ tier2Count?: number;
65
+ /** Milliseconds spent in the hybrid search step. */
66
+ hybridSearchMs?: number;
67
+ /** Whether sparse vectors were used in the hybrid search. */
68
+ sparseVectorUsed?: boolean;
73
69
  }
74
70
 
75
71
  /**
@@ -99,67 +95,9 @@ export interface MemoryRecallOptions {
99
95
  maxInjectTokensOverride?: number;
100
96
  }
101
97
 
102
- export interface CollectedCandidates {
103
- lexical: Candidate[];
104
- recency: Candidate[];
105
- semantic: Candidate[];
106
- entity: Candidate[];
107
- relationSeedEntityCount: number;
108
- relationTraversedEdgeCount: number;
109
- relationNeighborEntityCount: number;
110
- relationExpandedItemCount: number;
111
- earlyTerminated: boolean;
112
- /** True when semantic search was attempted but threw an error. */
113
- semanticSearchFailed: boolean;
114
- /** True when semantic search was known to be unavailable before retrieval (no vector or breaker open). */
115
- semanticUnavailable: boolean;
116
- /** The error that caused semantic search to fail, if any. */
117
- semanticSearchError?: unknown;
118
- merged: Candidate[];
119
- }
120
-
121
- export interface EntitySearchResult {
122
- candidates: Candidate[];
123
- relationSeedEntityCount: number;
124
- relationTraversedEdgeCount: number;
125
- relationNeighborEntityCount: number;
126
- relationExpandedItemCount: number;
127
- candidateDepths?: Map<string, number>; // candidate key → BFS hop depth (1-based)
128
- }
129
-
130
- export interface MatchedEntityRow {
131
- id: string;
132
- name: string;
133
- type: string;
134
- aliases: string | null;
135
- mention_count: number;
136
- }
137
-
138
98
  export interface ItemMetadata {
139
99
  accessCount: number;
140
100
  lastUsedAt: number | null;
141
101
  verificationState: string;
142
- }
143
-
144
- import type { EntityRelationType, EntityType } from "../entity-extractor.js";
145
-
146
- export interface TraversalOptions {
147
- maxEdges: number;
148
- maxNeighborEntities: number;
149
- maxDepth?: number; // default 3
150
- relationTypes?: EntityRelationType[];
151
- entityTypes?: EntityType[];
152
- /** When true, only follow source→target edges (frontier must be on source side). */
153
- directed?: boolean;
154
- }
155
-
156
- export interface TraversalResult {
157
- neighborEntityIds: string[];
158
- traversedEdgeCount: number;
159
- neighborDepths: Map<string, number>; // entityId → depth (1-based)
160
- }
161
-
162
- export interface TraversalStep {
163
- relationTypes?: EntityRelationType[];
164
- entityTypes?: EntityType[];
102
+ sourceConversationCount?: number;
165
103
  }
@@ -1,6 +1,5 @@
1
1
  import { getLogger } from "../util/logger.js";
2
2
  import { rawGet, rawRun } from "./raw-query.js";
3
- import { bumpMemoryVersion } from "./recall-cache.js";
4
3
 
5
4
  const log = getLogger("task-memory-cleanup");
6
5
 
@@ -85,7 +84,6 @@ export function invalidateAssistantInferredItemsForConversation(
85
84
  );
86
85
 
87
86
  if (affected > 0) {
88
- bumpMemoryVersion();
89
87
  log.info(
90
88
  { conversationId, affected },
91
89
  "Invalidated assistant-inferred memory items after task failure",
@@ -96,9 +94,9 @@ export function invalidateAssistantInferredItemsForConversation(
96
94
  }
97
95
 
98
96
  /**
99
- * Cancel pending `extract_items` and `extract_entities` jobs whose messageId
100
- * belongs to the given conversation. This drains the queue so the worker never
101
- * processes them, complementing the runtime check in the extraction handler.
97
+ * Cancel pending `extract_items` jobs whose messageId belongs to the given
98
+ * conversation. This drains the queue so the worker never processes them,
99
+ * complementing the runtime check in the extraction handler.
102
100
  */
103
101
  function cancelPendingExtractionJobsForConversation(
104
102
  conversationId: string,
@@ -109,7 +107,7 @@ function cancelPendingExtractionJobsForConversation(
109
107
  SET status = 'failed',
110
108
  last_error = 'conversation_failed',
111
109
  updated_at = ?
112
- WHERE type IN ('extract_items', 'extract_entities')
110
+ WHERE type IN ('extract_items')
113
111
  AND status IN ('pending', 'running')
114
112
  AND json_extract(payload, '$.messageId') IN (
115
113
  SELECT id FROM messages WHERE conversation_id = ?
@@ -87,7 +87,7 @@ export interface MessagingProvider {
87
87
  * for providers that don't use OAuth (e.g. Telegram bot tokens stored
88
88
  * under a non-standard key).
89
89
  */
90
- isConnected?(): boolean;
90
+ isConnected?(): Promise<boolean>;
91
91
 
92
92
  /** Platform-specific capabilities for tool routing (e.g. 'reactions', 'threads', 'labels'). */
93
93
  capabilities: Set<string>;
@@ -86,7 +86,7 @@ function mapGmailMessage(msg: GmailMessage): Message {
86
86
  export const gmailMessagingProvider: MessagingProvider = {
87
87
  id: "gmail",
88
88
  displayName: "Gmail",
89
- credentialService: "integration:gmail",
89
+ credentialService: "integration:google",
90
90
  capabilities: new Set([
91
91
  "threads",
92
92
  "labels",
@@ -21,6 +21,10 @@ export interface MimeMessageOptions {
21
21
  attachments: MimeAttachment[];
22
22
  }
23
23
 
24
+ function sanitizeHeaderValue(value: string): string {
25
+ return value.replace(/[\r\n]+/g, " ").trim();
26
+ }
27
+
24
28
  function toBase64Url(input: Buffer): string {
25
29
  return input
26
30
  .toString("base64")
@@ -37,17 +41,23 @@ export function buildMultipartMime(options: MimeMessageOptions): string {
37
41
  const { to, subject, body, inReplyTo, cc, bcc, attachments } = options;
38
42
  const boundary = `----=_Part_${randomBytes(16).toString("hex")}`;
39
43
 
44
+ const sanitizedTo = sanitizeHeaderValue(to);
45
+ const sanitizedSubject = sanitizeHeaderValue(subject);
46
+ const sanitizedCc = cc ? sanitizeHeaderValue(cc) : undefined;
47
+ const sanitizedBcc = bcc ? sanitizeHeaderValue(bcc) : undefined;
48
+ const sanitizedInReplyTo = inReplyTo ? sanitizeHeaderValue(inReplyTo) : undefined;
49
+
40
50
  const headers = [
41
- `To: ${to}`,
42
- `Subject: ${subject}`,
51
+ `To: ${sanitizedTo}`,
52
+ `Subject: ${sanitizedSubject}`,
43
53
  "MIME-Version: 1.0",
44
54
  `Content-Type: multipart/mixed; boundary="${boundary}"`,
45
55
  ];
46
- if (cc) headers.push(`Cc: ${cc}`);
47
- if (bcc) headers.push(`Bcc: ${bcc}`);
48
- if (inReplyTo) {
49
- headers.push(`In-Reply-To: ${inReplyTo}`);
50
- headers.push(`References: ${inReplyTo}`);
56
+ if (sanitizedCc) headers.push(`Cc: ${sanitizedCc}`);
57
+ if (sanitizedBcc) headers.push(`Bcc: ${sanitizedBcc}`);
58
+ if (sanitizedInReplyTo) {
59
+ headers.push(`In-Reply-To: ${sanitizedInReplyTo}`);
60
+ headers.push(`References: ${sanitizedInReplyTo}`);
51
61
  }
52
62
 
53
63
  const parts: string[] = [];
@@ -18,7 +18,7 @@ import type { OAuthConnection } from "../../../oauth/connection.js";
18
18
  import { getConnectionByProvider } from "../../../oauth/oauth-store.js";
19
19
  import { mintDaemonDeliveryToken } from "../../../runtime/auth/token-service.js";
20
20
  import { credentialKey } from "../../../security/credential-key.js";
21
- import { getSecureKey } from "../../../security/secure-keys.js";
21
+ import { getSecureKeyAsync } from "../../../security/secure-keys.js";
22
22
  import type { MessagingProvider } from "../../provider.js";
23
23
  import type {
24
24
  ConnectionInfo,
@@ -44,8 +44,8 @@ function getBearerToken(): string {
44
44
  }
45
45
 
46
46
  /** Read the Telegram bot token from the credential vault. */
47
- function getBotToken(): string | undefined {
48
- return getSecureKey(credentialKey("telegram", "bot_token"));
47
+ async function getBotToken(): Promise<string | undefined> {
48
+ return getSecureKeyAsync(credentialKey("telegram", "bot_token"));
49
49
  }
50
50
 
51
51
  export const telegramBotMessagingProvider: MessagingProvider = {
@@ -55,22 +55,31 @@ export const telegramBotMessagingProvider: MessagingProvider = {
55
55
  capabilities: new Set(["send"]),
56
56
 
57
57
  /**
58
- * Custom connectivity check using the oauth_connection record as the
59
- * single source of truth, consistent with integration-status.ts.
58
+ * Custom connectivity check using both the oauth_connection record AND
59
+ * actual keychain credentials. The connection row alone can become stale
60
+ * if clearTelegramConfig() returns early on a secure-key deletion error
61
+ * without removing the row. Checking both ensures we don't report
62
+ * Telegram as connected when secrets are missing.
60
63
  *
61
64
  * Both bot_token and webhook_secret are required — the gateway's
62
65
  * /deliver/telegram endpoint rejects requests without the webhook
63
66
  * secret, so partial credentials would cause every send to fail.
64
67
  */
65
- isConnected(): boolean {
68
+ async isConnected(): Promise<boolean> {
66
69
  const conn = getConnectionByProvider("telegram");
67
- return !!(conn && conn.status === "active");
70
+ if (!(conn && conn.status === "active")) return false;
71
+ const botToken = await getBotToken();
72
+ if (botToken === undefined) return false;
73
+ const webhookSecret = await getSecureKeyAsync(
74
+ credentialKey("telegram", "webhook_secret"),
75
+ );
76
+ return !!webhookSecret;
68
77
  },
69
78
 
70
79
  async testConnection(
71
80
  _connectionOrToken: OAuthConnection | string,
72
81
  ): Promise<ConnectionInfo> {
73
- const botToken = getBotToken();
82
+ const botToken = await getBotToken();
74
83
  if (!botToken) {
75
84
  return {
76
85
  connected: false,
@@ -16,7 +16,7 @@ import * as externalConversationStore from "../../../memory/external-conversatio
16
16
  import type { OAuthConnection } from "../../../oauth/connection.js";
17
17
  import { mintDaemonDeliveryToken } from "../../../runtime/auth/token-service.js";
18
18
  import { credentialKey } from "../../../security/credential-key.js";
19
- import { getSecureKey } from "../../../security/secure-keys.js";
19
+ import { getSecureKeyAsync } from "../../../security/secure-keys.js";
20
20
  import type { MessagingProvider } from "../../provider.js";
21
21
  import type {
22
22
  ConnectionInfo,
@@ -42,11 +42,15 @@ function getBearerToken(): string {
42
42
  }
43
43
 
44
44
  /** Check whether WhatsApp credentials are stored. */
45
- function hasWhatsAppCredentials(): boolean {
46
- return (
47
- !!getSecureKey(credentialKey("whatsapp", "phone_number_id")) &&
48
- !!getSecureKey(credentialKey("whatsapp", "access_token"))
45
+ async function hasWhatsAppCredentials(): Promise<boolean> {
46
+ const phoneNumberId = await getSecureKeyAsync(
47
+ credentialKey("whatsapp", "phone_number_id"),
49
48
  );
49
+ if (!phoneNumberId) return false;
50
+ const accessToken = await getSecureKeyAsync(
51
+ credentialKey("whatsapp", "access_token"),
52
+ );
53
+ return !!accessToken;
50
54
  }
51
55
 
52
56
  export const whatsappMessagingProvider: MessagingProvider = {
@@ -58,14 +62,14 @@ export const whatsappMessagingProvider: MessagingProvider = {
58
62
  /**
59
63
  * WhatsApp is connected when Meta Cloud API credentials are stored.
60
64
  */
61
- isConnected(): boolean {
65
+ async isConnected(): Promise<boolean> {
62
66
  return hasWhatsAppCredentials();
63
67
  },
64
68
 
65
69
  async testConnection(
66
70
  _connectionOrToken: OAuthConnection | string,
67
71
  ): Promise<ConnectionInfo> {
68
- if (!hasWhatsAppCredentials()) {
72
+ if (!(await hasWhatsAppCredentials())) {
69
73
  return {
70
74
  connected: false,
71
75
  user: "unknown",
@@ -77,9 +81,9 @@ export const whatsappMessagingProvider: MessagingProvider = {
77
81
  };
78
82
  }
79
83
 
80
- const phoneNumberId = getSecureKey(
84
+ const phoneNumberId = (await getSecureKeyAsync(
81
85
  credentialKey("whatsapp", "phone_number_id"),
82
- )!;
86
+ ))!;
83
87
 
84
88
  return {
85
89
  connected: true,
@@ -23,11 +23,15 @@ export function getMessagingProvider(id: string): MessagingProvider {
23
23
  }
24
24
 
25
25
  /** Return all registered providers that have stored credentials. */
26
- export function getConnectedProviders(): MessagingProvider[] {
27
- return Array.from(providers.values()).filter((p) => {
28
- if (p.isConnected) return p.isConnected();
29
- return isProviderConnected(p.credentialService);
30
- });
26
+ export async function getConnectedProviders(): Promise<MessagingProvider[]> {
27
+ const results: MessagingProvider[] = [];
28
+ for (const p of providers.values()) {
29
+ const connected = p.isConnected
30
+ ? await p.isConnected()
31
+ : await isProviderConnected(p.credentialService);
32
+ if (connected) results.push(p);
33
+ }
34
+ return results;
31
35
  }
32
36
 
33
37
  /** Return all registered provider IDs. */
@@ -81,7 +81,12 @@ const mockConnections = new Map<
81
81
  >();
82
82
  const mockApps = new Map<
83
83
  string,
84
- { id: string; providerKey: string; clientId: string }
84
+ {
85
+ id: string;
86
+ providerKey: string;
87
+ clientId: string;
88
+ clientSecretCredentialPath: string;
89
+ }
85
90
  >();
86
91
  const mockProviders = new Map<
87
92
  string,
@@ -95,6 +100,12 @@ const mockProviders = new Map<
95
100
 
96
101
  mock.module("./oauth-store.js", () => ({
97
102
  getConnectionByProvider: (service: string) => mockConnections.get(service),
103
+ getConnection: (id: string) => {
104
+ for (const conn of mockConnections.values()) {
105
+ if (conn.id === id) return conn;
106
+ }
107
+ return undefined;
108
+ },
98
109
  getApp: (id: string) => mockApps.get(id),
99
110
  getProvider: (key: string) => mockProviders.get(key),
100
111
  updateConnection: () => {},
@@ -184,7 +195,7 @@ function setupCredential(
184
195
  tokenUrl: "https://oauth2.googleapis.com/token",
185
196
  // Only well-known providers (gmail) have a baseUrl; custom services don't
186
197
  baseUrl:
187
- service === "integration:gmail"
198
+ service === "integration:google"
188
199
  ? "https://gmail.googleapis.com/gmail/v1/users/me"
189
200
  : undefined,
190
201
  });
@@ -192,6 +203,7 @@ function setupCredential(
192
203
  id: appId,
193
204
  providerKey: service,
194
205
  clientId: "test-client-id",
206
+ clientSecretCredentialPath: `oauth_app/${appId}/client_secret`,
195
207
  });
196
208
  mockConnections.set(service, {
197
209
  id: connId,
@@ -212,7 +224,7 @@ function setupCredential(
212
224
  upsertCredentialMetadata(service, "access_token", {});
213
225
  }
214
226
 
215
- function createConnection(service = "integration:gmail"): BYOOAuthConnection {
227
+ function createConnection(service = "integration:google"): BYOOAuthConnection {
216
228
  return new BYOOAuthConnection({
217
229
  id: "test-cred-id",
218
230
  providerKey: service,
@@ -230,7 +242,7 @@ function createConnection(service = "integration:gmail"): BYOOAuthConnection {
230
242
  describe("BYOOAuthConnection", () => {
231
243
  describe("request()", () => {
232
244
  test("makes authenticated request with Bearer token", async () => {
233
- setupCredential("integration:gmail");
245
+ setupCredential("integration:google");
234
246
  const conn = createConnection();
235
247
 
236
248
  const result = await conn.request({
@@ -254,7 +266,7 @@ describe("BYOOAuthConnection", () => {
254
266
  });
255
267
 
256
268
  test("appends query parameters", async () => {
257
- setupCredential("integration:gmail");
269
+ setupCredential("integration:google");
258
270
  const conn = createConnection();
259
271
 
260
272
  await conn.request({
@@ -270,7 +282,7 @@ describe("BYOOAuthConnection", () => {
270
282
  });
271
283
 
272
284
  test("uses per-request baseUrl override", async () => {
273
- setupCredential("integration:gmail");
285
+ setupCredential("integration:google");
274
286
  const conn = createConnection();
275
287
 
276
288
  await conn.request({
@@ -284,7 +296,7 @@ describe("BYOOAuthConnection", () => {
284
296
  });
285
297
 
286
298
  test("sends JSON body for POST requests", async () => {
287
- setupCredential("integration:gmail");
299
+ setupCredential("integration:google");
288
300
  const conn = createConnection();
289
301
 
290
302
  await conn.request({
@@ -304,7 +316,7 @@ describe("BYOOAuthConnection", () => {
304
316
  });
305
317
 
306
318
  test("retries once on 401 response", async () => {
307
- setupCredential("integration:gmail");
319
+ setupCredential("integration:google");
308
320
  const conn = createConnection();
309
321
 
310
322
  // First call returns 401, second returns 200
@@ -332,7 +344,7 @@ describe("BYOOAuthConnection", () => {
332
344
  });
333
345
 
334
346
  test("handles empty response body", async () => {
335
- setupCredential("integration:gmail");
347
+ setupCredential("integration:google");
336
348
  const conn = createConnection();
337
349
 
338
350
  globalThis.fetch = mock(() =>
@@ -349,7 +361,7 @@ describe("BYOOAuthConnection", () => {
349
361
  });
350
362
 
351
363
  test("handles non-JSON response body", async () => {
352
- setupCredential("integration:gmail");
364
+ setupCredential("integration:google");
353
365
  const conn = createConnection();
354
366
 
355
367
  globalThis.fetch = mock(() =>
@@ -366,7 +378,7 @@ describe("BYOOAuthConnection", () => {
366
378
  });
367
379
 
368
380
  test("returns response headers", async () => {
369
- setupCredential("integration:gmail");
381
+ setupCredential("integration:google");
370
382
  const conn = createConnection();
371
383
 
372
384
  globalThis.fetch = mock(() =>
@@ -390,7 +402,7 @@ describe("BYOOAuthConnection", () => {
390
402
  });
391
403
 
392
404
  test("includes custom request headers", async () => {
393
- setupCredential("integration:gmail");
405
+ setupCredential("integration:google");
394
406
  const conn = createConnection();
395
407
 
396
408
  await conn.request({
@@ -409,7 +421,7 @@ describe("BYOOAuthConnection", () => {
409
421
  describe("proactive token refresh", () => {
410
422
  test("refreshes token when near expiry (within 5-minute buffer)", async () => {
411
423
  // Set token to expire in 2 minutes (within 5-min buffer)
412
- setupCredential("integration:gmail", {
424
+ setupCredential("integration:google", {
413
425
  expiresAt: Date.now() + 2 * 60 * 1000,
414
426
  });
415
427
  const conn = createConnection();
@@ -433,7 +445,7 @@ describe("BYOOAuthConnection", () => {
433
445
 
434
446
  describe("withToken()", () => {
435
447
  test("provides valid token to callback", async () => {
436
- setupCredential("integration:gmail");
448
+ setupCredential("integration:google");
437
449
  const conn = createConnection();
438
450
 
439
451
  const result = await conn.withToken(async (token) => {
@@ -444,7 +456,7 @@ describe("BYOOAuthConnection", () => {
444
456
  });
445
457
 
446
458
  test("retries callback on 401 error", async () => {
447
- setupCredential("integration:gmail");
459
+ setupCredential("integration:google");
448
460
  const conn = createConnection();
449
461
 
450
462
  let callCount = 0;
@@ -476,29 +488,31 @@ describe("BYOOAuthConnection", () => {
476
488
  });
477
489
 
478
490
  describe("resolveOAuthConnection", () => {
479
- test("returns a BYOOAuthConnection for valid credential", () => {
480
- setupCredential("integration:gmail");
481
- const conn = resolveOAuthConnection("integration:gmail");
491
+ test("returns a BYOOAuthConnection for valid credential", async () => {
492
+ setupCredential("integration:google");
493
+ const conn = await resolveOAuthConnection("integration:google");
482
494
 
483
495
  expect(conn).toBeInstanceOf(BYOOAuthConnection);
484
- expect(conn.providerKey).toBe("integration:gmail");
496
+ expect(conn.providerKey).toBe("integration:google");
485
497
  expect(conn.grantedScopes).toEqual(["read", "write"]);
486
498
  });
487
499
 
488
- test("throws when no credential metadata exists", () => {
489
- expect(() => resolveOAuthConnection("integration:unknown")).toThrow(
500
+ test("throws when no credential metadata exists", async () => {
501
+ await expect(resolveOAuthConnection("integration:unknown")).rejects.toThrow(
490
502
  /No credential found for "integration:unknown"/,
491
503
  );
492
504
  });
493
505
 
494
- test("throws when no base URL configured", () => {
506
+ test("throws when no base URL configured", async () => {
495
507
  setupCredential("integration:custom-service");
496
- expect(() => resolveOAuthConnection("integration:custom-service")).toThrow(
508
+ await expect(
509
+ resolveOAuthConnection("integration:custom-service"),
510
+ ).rejects.toThrow(
497
511
  /No base URL configured for "integration:custom-service"/,
498
512
  );
499
513
  });
500
514
 
501
- test("resolves base URL via app's canonical providerKey for custom credential_service", () => {
515
+ test("resolves base URL via app's canonical providerKey for custom credential_service", async () => {
502
516
  // Set up a well-known provider with a baseUrl
503
517
  mockProviders.set("github", {
504
518
  key: "github",
@@ -514,6 +528,7 @@ describe("resolveOAuthConnection", () => {
514
528
  id: appId,
515
529
  providerKey: "github",
516
530
  clientId: "test-client-id",
531
+ clientSecretCredentialPath: `oauth_app/${appId}/client_secret`,
517
532
  });
518
533
 
519
534
  // Connection uses the custom credential service as its providerKey
@@ -528,7 +543,7 @@ describe("resolveOAuthConnection", () => {
528
543
  });
529
544
  setSecureKey(`oauth_connection/${connId}/access_token`, "ghp-test-token");
530
545
 
531
- const conn = resolveOAuthConnection("integration:github-work");
546
+ const conn = await resolveOAuthConnection("integration:github-work");
532
547
 
533
548
  expect(conn).toBeInstanceOf(BYOOAuthConnection);
534
549
  expect(conn.providerKey).toBe("integration:github-work");
@@ -48,7 +48,6 @@ function resolveBehavior(providerKey: string): {
48
48
  setup?: OAuthProviderBehavior["setup"];
49
49
  setupSkillId?: string;
50
50
  postConnectHookId?: string;
51
- injectionTemplates?: OAuthProviderBehavior["injectionTemplates"];
52
51
  } {
53
52
  const behavior = getProviderBehavior(providerKey);
54
53
  if (!behavior) return {};
@@ -57,7 +56,6 @@ function resolveBehavior(providerKey: string): {
57
56
  setup: behavior.setup,
58
57
  setupSkillId: behavior.setupSkillId,
59
58
  postConnectHookId: behavior.postConnectHookId,
60
- injectionTemplates: behavior.injectionTemplates,
61
59
  };
62
60
  }
63
61
 
@@ -90,8 +88,6 @@ export interface OAuthConnectOptions {
90
88
  openUrl?: (url: string) => void;
91
89
  /** Send a message to the client (e.g. open_url). */
92
90
  sendToClient?: (msg: { type: string; [key: string]: unknown }) => void;
93
- /** Tools allowed to use the resulting credential. */
94
- allowedTools?: string[];
95
91
 
96
92
  /**
97
93
  * Called when the deferred (non-interactive) flow completes — either
@@ -164,7 +160,7 @@ export async function orchestrateOAuthConnect(
164
160
  | undefined;
165
161
  const callbackTransport =
166
162
  (providerRow.callbackTransport as "loopback" | "gateway" | null) ??
167
- "gateway";
163
+ "loopback";
168
164
  const loopbackPort = providerRow.loopbackPort;
169
165
 
170
166
  // Resolve scopes via the scope policy engine
@@ -216,11 +212,7 @@ export async function orchestrateOAuthConnect(
216
212
  service: resolvedService,
217
213
  clientId: options.clientId,
218
214
  clientSecret: options.clientSecret,
219
- tokenUrl,
220
- tokenEndpointAuthMethod,
221
215
  userinfoUrl,
222
- allowedTools: options.allowedTools,
223
- wellKnownInjectionTemplates: behavior.injectionTemplates,
224
216
  };
225
217
 
226
218
  // -----------------------------------------------------------------------
@@ -249,7 +241,9 @@ export async function orchestrateOAuthConnect(
249
241
  oauthConfig,
250
242
  callbackTransport === "loopback"
251
243
  ? { callbackTransport, loopbackPort: loopbackPort ?? undefined }
252
- : undefined,
244
+ : callbackTransport === "gateway"
245
+ ? { callbackTransport }
246
+ : undefined,
253
247
  );
254
248
 
255
249
  // Fire-and-forget: store tokens when the callback arrives