@vellumai/assistant 0.8.3 → 0.8.4

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 (342) hide show
  1. package/docker-entrypoint.sh +0 -1
  2. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  3. package/openapi.yaml +610 -16
  4. package/package.json +1 -1
  5. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  6. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  7. package/src/__tests__/agent-loop.test.ts +88 -3
  8. package/src/__tests__/anthropic-provider.test.ts +272 -0
  9. package/src/__tests__/approval-cascade.test.ts +1 -1
  10. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  11. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  12. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  13. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  14. package/src/__tests__/compaction-events.test.ts +1 -1
  15. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  16. package/src/__tests__/config-watcher.test.ts +1 -1
  17. package/src/__tests__/context-token-estimator.test.ts +91 -1
  18. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  19. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
  20. package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
  21. package/src/__tests__/conversation-agent-loop.test.ts +25 -7
  22. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  23. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  24. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  25. package/src/__tests__/conversation-fork-crud.test.ts +161 -0
  26. package/src/__tests__/conversation-lifecycle.test.ts +1 -1
  27. package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
  28. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  29. package/src/__tests__/conversation-pairing.test.ts +2 -2
  30. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  31. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
  32. package/src/__tests__/conversation-queue.test.ts +1 -1
  33. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  34. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  35. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  36. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  37. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  38. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  39. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  40. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
  41. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  42. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  43. package/src/__tests__/credential-security-invariants.test.ts +6 -0
  44. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  45. package/src/__tests__/dm-backfill.test.ts +64 -0
  46. package/src/__tests__/dm-persistence.test.ts +33 -0
  47. package/src/__tests__/document-find-replace.test.ts +501 -0
  48. package/src/__tests__/first-greeting.test.ts +23 -2
  49. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  50. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  51. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  52. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  53. package/src/__tests__/host-file-proxy.test.ts +8 -1
  54. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  55. package/src/__tests__/identity-routes.test.ts +57 -0
  56. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  57. package/src/__tests__/injector-chain.test.ts +2 -0
  58. package/src/__tests__/injector-document-comments.test.ts +378 -0
  59. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  60. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  61. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  62. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  63. package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
  64. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  65. package/src/__tests__/llm-resolver.test.ts +85 -1
  66. package/src/__tests__/log-export-routes.test.ts +99 -2
  67. package/src/__tests__/message-queue-steer.test.ts +114 -0
  68. package/src/__tests__/openai-provider.test.ts +105 -0
  69. package/src/__tests__/openai-responses-provider.test.ts +4 -4
  70. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  71. package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
  72. package/src/__tests__/platform.test.ts +0 -3
  73. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  74. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  75. package/src/__tests__/process-message-display-content.test.ts +21 -16
  76. package/src/__tests__/server-history-render.test.ts +83 -4
  77. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  78. package/src/__tests__/system-prompt.test.ts +51 -28
  79. package/src/__tests__/terminal-tools.test.ts +11 -1
  80. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  81. package/src/__tests__/thread-backfill.test.ts +370 -22
  82. package/src/__tests__/tool-executor.test.ts +90 -1
  83. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  84. package/src/__tests__/twilio-routes.test.ts +1 -1
  85. package/src/__tests__/web-fetch.test.ts +2 -2
  86. package/src/__tests__/workspace-git-service.test.ts +88 -5
  87. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  88. package/src/agent/attachments.ts +1 -0
  89. package/src/agent/loop.ts +57 -20
  90. package/src/background-wake/next-wake.test.ts +289 -0
  91. package/src/background-wake/next-wake.ts +172 -0
  92. package/src/browser/operations.ts +15 -0
  93. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  94. package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
  95. package/src/cli/commands/conversations.ts +128 -1
  96. package/src/cli/commands/inference-providers.ts +147 -1
  97. package/src/cli/commands/memory-v2.ts +308 -0
  98. package/src/cli/commands/notifications.ts +24 -2
  99. package/src/cli/utils/conversation-id.ts +17 -5
  100. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  101. package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
  102. package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
  103. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  104. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  105. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  106. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  107. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  108. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  109. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  110. package/src/config/bundled-tool-registry.ts +22 -12
  111. package/src/config/call-site-defaults.ts +19 -0
  112. package/src/config/feature-flag-registry.json +99 -3
  113. package/src/config/llm-resolver.ts +16 -2
  114. package/src/config/schemas/__tests__/memory-v2.test.ts +4 -0
  115. package/src/config/schemas/call-site-catalog.ts +21 -0
  116. package/src/config/schemas/llm.ts +3 -0
  117. package/src/config/schemas/memory-v2.ts +48 -1
  118. package/src/context/compactor.ts +8 -1
  119. package/src/context/token-estimator.ts +47 -4
  120. package/src/context/window-manager.ts +25 -0
  121. package/src/credential-health/credential-health-service.ts +34 -19
  122. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  123. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  124. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  125. package/src/daemon/conversation-agent-loop-handlers.ts +153 -23
  126. package/src/daemon/conversation-agent-loop.ts +223 -54
  127. package/src/daemon/conversation-lifecycle.ts +142 -116
  128. package/src/daemon/conversation-messaging.ts +3 -0
  129. package/src/daemon/conversation-process.ts +273 -0
  130. package/src/daemon/conversation-queue-manager.ts +14 -0
  131. package/src/daemon/conversation-runtime-assembly.ts +135 -75
  132. package/src/daemon/conversation-slash.ts +37 -5
  133. package/src/daemon/conversation-surfaces.ts +45 -2
  134. package/src/daemon/conversation-tool-setup.ts +7 -0
  135. package/src/daemon/conversation.ts +42 -5
  136. package/src/daemon/first-greeting.ts +10 -0
  137. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  138. package/src/daemon/handlers/config-a2a.ts +160 -0
  139. package/src/daemon/handlers/config-model.test.ts +1 -0
  140. package/src/daemon/handlers/conversations.ts +79 -0
  141. package/src/daemon/handlers/shared.ts +92 -29
  142. package/src/daemon/host-bash-proxy.ts +1 -1
  143. package/src/daemon/host-cu-proxy.ts +1 -1
  144. package/src/daemon/host-file-proxy.ts +1 -1
  145. package/src/daemon/host-transfer-proxy.ts +1 -1
  146. package/src/daemon/lifecycle.ts +18 -4
  147. package/src/daemon/message-protocol.ts +4 -0
  148. package/src/daemon/message-types/conversations.ts +8 -0
  149. package/src/daemon/message-types/document-comments.ts +50 -0
  150. package/src/daemon/message-types/messages.ts +68 -1
  151. package/src/daemon/message-types/surfaces.ts +3 -1
  152. package/src/daemon/message-types/web-activity.ts +57 -0
  153. package/src/daemon/plugin-source-watcher.ts +135 -3
  154. package/src/daemon/process-message.ts +69 -12
  155. package/src/daemon/query-complexity-router.ts +75 -0
  156. package/src/daemon/trust-context.ts +6 -0
  157. package/src/documents/document-comments-store.test.ts +338 -0
  158. package/src/documents/document-comments-store.ts +237 -0
  159. package/src/documents/document-store.ts +202 -0
  160. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
  161. package/src/heartbeat/heartbeat-service.ts +1 -0
  162. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  163. package/src/home/feed-types.ts +6 -1
  164. package/src/home/home-content-refresh.ts +52 -0
  165. package/src/home/home-greeting-cache.ts +69 -0
  166. package/src/home/home-greeting.ts +94 -0
  167. package/src/home/suggested-prompts.ts +177 -9
  168. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  169. package/src/memory/__tests__/memory-retrospective-job.test.ts +320 -6
  170. package/src/memory/conversation-crud.ts +133 -43
  171. package/src/memory/db-init.ts +16 -0
  172. package/src/memory/delivery-crud.ts +41 -0
  173. package/src/memory/delivery-status.ts +141 -15
  174. package/src/memory/external-conversation-store.ts +32 -1
  175. package/src/memory/jobs-worker.ts +21 -1
  176. package/src/memory/memory-retrospective-constants.ts +28 -0
  177. package/src/memory/memory-retrospective-enqueue.ts +3 -2
  178. package/src/memory/memory-retrospective-job.ts +408 -18
  179. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  180. package/src/memory/memory-v2-activation-log-store.ts +26 -8
  181. package/src/memory/migrations/100-core-tables.ts +1 -0
  182. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  183. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  184. package/src/memory/migrations/253-document-comments.ts +47 -0
  185. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  186. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  187. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  188. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  189. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  190. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  191. package/src/memory/migrations/index.ts +17 -0
  192. package/src/memory/migrations/registry.ts +25 -0
  193. package/src/memory/onboarding-events-store.ts +7 -0
  194. package/src/memory/schema/calls.ts +1 -0
  195. package/src/memory/schema/conversations.ts +3 -0
  196. package/src/memory/schema/infrastructure.ts +1 -0
  197. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  198. package/src/memory/v2/__tests__/injection.test.ts +31 -14
  199. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  200. package/src/memory/v2/__tests__/router.test.ts +489 -1
  201. package/src/memory/v2/consolidation-job.ts +14 -0
  202. package/src/memory/v2/injection-events.ts +101 -0
  203. package/src/memory/v2/injection.ts +21 -10
  204. package/src/memory/v2/page-index.ts +209 -7
  205. package/src/memory/v2/page-store.ts +18 -0
  206. package/src/memory/v2/router.ts +209 -55
  207. package/src/messaging/providers/index.ts +7 -1
  208. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  209. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  210. package/src/messaging/providers/slack/adapter.ts +178 -25
  211. package/src/messaging/providers/slack/api.test.ts +54 -0
  212. package/src/messaging/providers/slack/api.ts +119 -3
  213. package/src/messaging/providers/slack/client.ts +12 -0
  214. package/src/messaging/providers/slack/deep-link.ts +20 -1
  215. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  216. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  217. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  218. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  219. package/src/messaging/providers/slack/send.test.ts +77 -0
  220. package/src/messaging/providers/slack/send.ts +8 -2
  221. package/src/messaging/providers/slack/types.ts +14 -0
  222. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  223. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  224. package/src/notifications/conversation-seed-composer.ts +14 -2
  225. package/src/notifications/deferred-emit.ts +135 -0
  226. package/src/notifications/emit-signal.ts +9 -1
  227. package/src/notifications/home-feed-side-effect.ts +60 -30
  228. package/src/oauth/connect-orchestrator.ts +3 -0
  229. package/src/oauth/credential-token-resolver.ts +2 -0
  230. package/src/oauth/manual-token-connection.ts +19 -0
  231. package/src/oauth/oauth-store.ts +12 -0
  232. package/src/oauth/seed-providers.ts +22 -0
  233. package/src/permissions/prompter.ts +5 -2
  234. package/src/permissions/secret-prompter.ts +4 -1
  235. package/src/plugins/defaults/injectors.ts +82 -9
  236. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  237. package/src/prompts/normalize-onboarding.ts +40 -0
  238. package/src/prompts/sections.ts +32 -14
  239. package/src/prompts/system-prompt.ts +105 -68
  240. package/src/prompts/template-detection.ts +37 -0
  241. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  242. package/src/prompts/templates/BOOTSTRAP.md +8 -0
  243. package/src/prompts/templates/VOICE.md +3 -0
  244. package/src/prompts/templates/system-sections.ts +53 -3
  245. package/src/providers/anthropic/client.ts +132 -5
  246. package/src/providers/fireworks/client.ts +20 -2
  247. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  248. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  249. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  250. package/src/providers/inference/adapter-factory.ts +15 -1
  251. package/src/providers/inference/auth.ts +3 -3
  252. package/src/providers/inference/codex-token-refresh.ts +128 -0
  253. package/src/providers/inference/resolve-auth.ts +49 -6
  254. package/src/providers/model-catalog.ts +48 -1
  255. package/src/providers/openai/chat-completions-provider.ts +57 -20
  256. package/src/providers/openai/responses-provider.ts +9 -3
  257. package/src/providers/openrouter/client.ts +5 -1
  258. package/src/providers/types.ts +25 -0
  259. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  260. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  261. package/src/runtime/agent-wake.ts +151 -56
  262. package/src/runtime/auth/route-policy.ts +7 -3
  263. package/src/runtime/background-job-runner.ts +26 -0
  264. package/src/runtime/channel-reply-delivery.ts +182 -47
  265. package/src/runtime/channel-retry-sweep.ts +141 -16
  266. package/src/runtime/http-types.ts +7 -4
  267. package/src/runtime/pending-interactions.ts +51 -8
  268. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  269. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +55 -1
  270. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  271. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
  272. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  273. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  274. package/src/runtime/routes/approval-routes.ts +4 -1
  275. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  276. package/src/runtime/routes/content-source-routes.ts +78 -0
  277. package/src/runtime/routes/conversation-cli-routes.ts +146 -1
  278. package/src/runtime/routes/conversation-query-routes.ts +60 -1
  279. package/src/runtime/routes/conversation-routes.ts +281 -76
  280. package/src/runtime/routes/document-comments-routes.ts +287 -0
  281. package/src/runtime/routes/documents-routes.ts +33 -0
  282. package/src/runtime/routes/home-feed-routes.ts +6 -3
  283. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  284. package/src/runtime/routes/host-browser-routes.ts +8 -1
  285. package/src/runtime/routes/identity-routes.ts +21 -0
  286. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  287. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  288. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  289. package/src/runtime/routes/index.ts +12 -4
  290. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  291. package/src/runtime/routes/integrations/a2a.ts +60 -1
  292. package/src/runtime/routes/log-export-routes.ts +39 -0
  293. package/src/runtime/routes/memory-v2-routes.ts +217 -0
  294. package/src/runtime/routes/notification-routes.ts +19 -2
  295. package/src/runtime/routes/question-routes.ts +4 -1
  296. package/src/runtime/routes/sanity-routes.ts +159 -0
  297. package/src/runtime/routes/slack-channel-routes.ts +187 -0
  298. package/src/runtime/services/conversation-serializer.ts +30 -4
  299. package/src/schedule/integration-status.ts +3 -1
  300. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  301. package/src/security/oauth2-device-code.ts +307 -0
  302. package/src/security/oauth2.ts +26 -9
  303. package/src/security/secure-keys.ts +5 -0
  304. package/src/skills/catalog-install.ts +6 -2
  305. package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
  306. package/src/tools/browser/browser-execution.ts +93 -0
  307. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  308. package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
  309. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
  310. package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
  311. package/src/tools/browser/cdp-client/factory.ts +87 -3
  312. package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
  313. package/src/tools/browser/cdp-client/types.ts +36 -0
  314. package/src/tools/browser/pinned-tabs.ts +90 -0
  315. package/src/tools/document/document-comment-tool.test.ts +379 -0
  316. package/src/tools/document/document-comment-tool.ts +156 -0
  317. package/src/tools/document/document-tool.ts +128 -2
  318. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  319. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  320. package/src/tools/network/domain-normalize.ts +17 -0
  321. package/src/tools/network/web-fetch.ts +213 -64
  322. package/src/tools/network/web-search.ts +191 -66
  323. package/src/tools/terminal/safe-env.ts +3 -2
  324. package/src/tools/tool-approval-handler.ts +19 -12
  325. package/src/tools/types.ts +4 -0
  326. package/src/tools/ui-surface/definitions.ts +3 -1
  327. package/src/types/onboarding-context.ts +4 -0
  328. package/src/util/__tests__/favicon.test.ts +84 -0
  329. package/src/util/favicon.ts +40 -0
  330. package/src/util/platform.ts +0 -5
  331. package/src/workspace/git-service.ts +75 -4
  332. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  333. package/src/workspace/migrations/registry.ts +2 -0
  334. package/src/config/bundled-skills/document/SKILL.md +0 -54
  335. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  336. package/src/daemon/seed-files.ts +0 -18
  337. package/src/runtime/routes/interface-routes.ts +0 -43
  338. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  339. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  340. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  341. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  342. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Route definitions for ChatGPT subscription OAuth authentication.
3
+ *
4
+ * POST /v1/inference/chatgpt-subscription/auth — generate a PKCE authorize
5
+ * URL for the user to visit. Returns `{ authorize_url, state }`.
6
+ *
7
+ * POST /v1/inference/chatgpt-subscription/auth/exchange — accept the
8
+ * authorization code + state from the redirect, exchange for tokens,
9
+ * store in CES, and upsert the provider connection.
10
+ */
11
+
12
+ import { z } from "zod";
13
+
14
+ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
15
+ import { getConfigReadOnly } from "../../config/loader.js";
16
+ import { getDb } from "../../memory/db-connection.js";
17
+ import {
18
+ createConnection,
19
+ getConnection,
20
+ updateConnection,
21
+ } from "../../providers/inference/connections.js";
22
+ import type { OAuth2Config } from "../../security/oauth2.js";
23
+ import {
24
+ exchangeCodeForTokens,
25
+ generateCodeChallenge,
26
+ generateCodeVerifier,
27
+ generateState,
28
+ } from "../../security/oauth2.js";
29
+ import { setSecureKeyAsync } from "../../security/secure-keys.js";
30
+ import { getLogger } from "../../util/logger.js";
31
+ import { BadRequestError } from "./errors.js";
32
+ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
33
+
34
+ function requireFeatureFlag() {
35
+ const config = getConfigReadOnly();
36
+ if (!isAssistantFeatureFlagEnabled("chatgpt-subscription-auth", config)) {
37
+ throw new BadRequestError(
38
+ "ChatGPT subscription auth is not enabled for this assistant.",
39
+ );
40
+ }
41
+ }
42
+
43
+ const log = getLogger("chatgpt-subscription-auth");
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // OAuth config
47
+ // ---------------------------------------------------------------------------
48
+
49
+ const OPENAI_OAUTH_CONFIG: OAuth2Config = {
50
+ authorizeUrl: "https://auth.openai.com/oauth/authorize",
51
+ tokenExchangeUrl: "https://auth.openai.com/oauth/token",
52
+ clientId: "app_EMoamEEZ73f0CkXaXp7hrann",
53
+ scopes: ["openid", "profile", "email", "offline_access"],
54
+ scopeSeparator: " ",
55
+ authorizeParams: { id_token_add_organizations: "true" },
56
+ };
57
+
58
+ const REDIRECT_URI = "http://localhost:1455/auth/callback";
59
+ const CONNECTION_NAME = "chatgpt-subscription";
60
+
61
+ // ---------------------------------------------------------------------------
62
+ // Module-level PKCE state storage
63
+ // ---------------------------------------------------------------------------
64
+
65
+ interface PendingAuth {
66
+ codeVerifier: string;
67
+ createdAt: number;
68
+ }
69
+
70
+ const pendingAuths = new Map<string, PendingAuth>();
71
+
72
+ const PENDING_AUTH_TTL_MS = 10 * 60 * 1000; // 10 minutes
73
+
74
+ /** Remove entries older than 10 minutes. */
75
+ function cleanupExpiredEntries(): void {
76
+ const cutoff = Date.now() - PENDING_AUTH_TTL_MS;
77
+ for (const [key, entry] of pendingAuths) {
78
+ if (entry.createdAt < cutoff) {
79
+ pendingAuths.delete(key);
80
+ }
81
+ }
82
+ }
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Handlers
86
+ // ---------------------------------------------------------------------------
87
+
88
+ async function handleStartAuth(_args: RouteHandlerArgs) {
89
+ requireFeatureFlag();
90
+ cleanupExpiredEntries();
91
+
92
+ const codeVerifier = generateCodeVerifier();
93
+ const codeChallenge = generateCodeChallenge(codeVerifier);
94
+ const state = generateState();
95
+
96
+ pendingAuths.set(state, { codeVerifier, createdAt: Date.now() });
97
+
98
+ const params = new URLSearchParams({
99
+ response_type: "code",
100
+ client_id: OPENAI_OAUTH_CONFIG.clientId,
101
+ redirect_uri: REDIRECT_URI,
102
+ scope: OPENAI_OAUTH_CONFIG.scopes.join(
103
+ OPENAI_OAUTH_CONFIG.scopeSeparator,
104
+ ),
105
+ state,
106
+ code_challenge: codeChallenge,
107
+ code_challenge_method: "S256",
108
+ ...OPENAI_OAUTH_CONFIG.authorizeParams,
109
+ });
110
+
111
+ const authorizeUrl = `${OPENAI_OAUTH_CONFIG.authorizeUrl}?${params.toString()}`;
112
+
113
+ return { authorize_url: authorizeUrl, state };
114
+ }
115
+
116
+ async function handleExchange(args: RouteHandlerArgs) {
117
+ requireFeatureFlag();
118
+ const { code, state } = args.body as { code: string; state: string };
119
+
120
+ const pending = pendingAuths.get(state);
121
+ if (!pending) {
122
+ throw new Error(
123
+ "Invalid or expired state parameter. Please restart the auth flow.",
124
+ );
125
+ }
126
+
127
+ pendingAuths.delete(state);
128
+
129
+ // Check TTL
130
+ if (Date.now() - pending.createdAt > PENDING_AUTH_TTL_MS) {
131
+ throw new Error("Auth flow expired. Please restart the auth flow.");
132
+ }
133
+
134
+ const { tokens } = await exchangeCodeForTokens(
135
+ OPENAI_OAUTH_CONFIG,
136
+ code,
137
+ REDIRECT_URI,
138
+ pending.codeVerifier,
139
+ );
140
+
141
+ // Store tokens in CES
142
+ const accessStored = await setSecureKeyAsync(
143
+ "credential/chatgpt/access_token",
144
+ tokens.accessToken,
145
+ );
146
+ if (!accessStored) {
147
+ log.error("Failed to store ChatGPT access token in CES");
148
+ throw new Error("Failed to store access token");
149
+ }
150
+
151
+ if (tokens.refreshToken) {
152
+ const refreshStored = await setSecureKeyAsync(
153
+ "credential/chatgpt/refresh_token",
154
+ tokens.refreshToken,
155
+ );
156
+ if (!refreshStored) {
157
+ log.error("Failed to store ChatGPT refresh token in CES");
158
+ throw new Error("Failed to store refresh token");
159
+ }
160
+ }
161
+
162
+ if (tokens.expiresIn) {
163
+ const expiresAt = Math.floor(Date.now() / 1000 + tokens.expiresIn);
164
+ await setSecureKeyAsync(
165
+ "credential/chatgpt/expires_at",
166
+ String(expiresAt),
167
+ );
168
+ }
169
+
170
+ // Upsert provider connection
171
+ const db = getDb();
172
+ const authInput = {
173
+ type: "oauth_subscription" as const,
174
+ credential: "credential/chatgpt/access_token",
175
+ };
176
+
177
+ const existing = getConnection(db, CONNECTION_NAME);
178
+ if (existing) {
179
+ const updateResult = updateConnection(db, CONNECTION_NAME, {
180
+ auth: authInput,
181
+ });
182
+ if (!updateResult.ok) {
183
+ log.error(
184
+ { error: updateResult.error },
185
+ "Failed to update chatgpt-subscription connection",
186
+ );
187
+ throw new Error("Failed to update connection");
188
+ }
189
+ } else {
190
+ const createResult = createConnection(db, {
191
+ name: CONNECTION_NAME,
192
+ provider: "openai",
193
+ auth: authInput,
194
+ });
195
+ if (!createResult.ok) {
196
+ log.error(
197
+ { error: createResult.error },
198
+ "Failed to create chatgpt-subscription connection",
199
+ );
200
+ throw new Error("Failed to create connection");
201
+ }
202
+ }
203
+
204
+ log.info("ChatGPT subscription auth flow completed successfully");
205
+ return { ok: true };
206
+ }
207
+
208
+ // ---------------------------------------------------------------------------
209
+ // Route definitions
210
+ // ---------------------------------------------------------------------------
211
+
212
+ export const ROUTES: RouteDefinition[] = [
213
+ {
214
+ operationId: "inference_chatgpt_subscription_auth",
215
+ endpoint: "inference/chatgpt-subscription/auth",
216
+ method: "POST",
217
+ policyKey: "inference/provider-connections",
218
+ summary: "Start ChatGPT subscription OAuth PKCE flow",
219
+ description:
220
+ "Generate a PKCE authorize URL for ChatGPT subscription auth. Returns the URL and state for the client to open in a browser.",
221
+ tags: ["inference"],
222
+ responseBody: z.object({
223
+ authorize_url: z.string(),
224
+ state: z.string(),
225
+ }),
226
+ handler: handleStartAuth,
227
+ },
228
+ {
229
+ operationId: "inference_chatgpt_subscription_auth_exchange",
230
+ endpoint: "inference/chatgpt-subscription/auth/exchange",
231
+ method: "POST",
232
+ policyKey: "inference/provider-connections",
233
+ summary: "Exchange ChatGPT subscription OAuth authorization code",
234
+ description:
235
+ "Accept an authorization code and state from the OAuth redirect, exchange it for tokens, store them in CES, and upsert the provider connection.",
236
+ tags: ["inference"],
237
+ requestBody: z.object({
238
+ code: z.string(),
239
+ state: z.string(),
240
+ }),
241
+ responseBody: z.object({
242
+ ok: z.boolean(),
243
+ }),
244
+ handler: handleExchange,
245
+ },
246
+ ];
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Route definitions for content-source configuration.
3
+ *
4
+ * POST /v1/content-source — validate and persist a content source URL as sidecar
5
+ *
6
+ * Uses policyKey: "secrets" — writes workspace data, same policy tier as
7
+ * the existing secrets routes.
8
+ */
9
+
10
+ import { mkdirSync, writeFileSync } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+
13
+ import { z } from "zod";
14
+
15
+ import { getWorkspaceDir } from "../../util/platform.js";
16
+ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Helpers
20
+ // ---------------------------------------------------------------------------
21
+
22
+ function writeSidecar(relPath: string, data: Record<string, unknown>): void {
23
+ const workspaceDir = getWorkspaceDir();
24
+ const absPath = join(workspaceDir, relPath);
25
+ mkdirSync(dirname(absPath), { recursive: true });
26
+ writeFileSync(absPath, JSON.stringify(data, null, 2), "utf-8");
27
+ }
28
+
29
+ function validateUrl(
30
+ raw: string,
31
+ ): { ok: true; normalized: string } | { ok: false; error: "invalid_url" } {
32
+ const trimmed = raw.trim();
33
+ let parsed: URL;
34
+ try {
35
+ parsed = new URL(trimmed);
36
+ } catch {
37
+ return { ok: false, error: "invalid_url" };
38
+ }
39
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
40
+ return { ok: false, error: "invalid_url" };
41
+ }
42
+ parsed.username = "";
43
+ parsed.password = "";
44
+ return { ok: true, normalized: parsed.href };
45
+ }
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // POST /v1/content-source
49
+ // ---------------------------------------------------------------------------
50
+
51
+ function handleContentSource(args: RouteHandlerArgs): Record<string, unknown> {
52
+ const rawUrl = typeof args.body?.url === "string" ? args.body.url : "";
53
+
54
+ const result = validateUrl(rawUrl);
55
+ if (!result.ok) {
56
+ return { ok: false, error: result.error };
57
+ }
58
+
59
+ writeSidecar("data/content-source.json", { url: result.normalized });
60
+
61
+ return { ok: true };
62
+ }
63
+
64
+ // ---------------------------------------------------------------------------
65
+ // Route definition
66
+ // ---------------------------------------------------------------------------
67
+
68
+ export const ROUTES: RouteDefinition[] = [
69
+ {
70
+ operationId: "content_source_set",
71
+ endpoint: "content-source",
72
+ method: "POST",
73
+ policyKey: "secrets",
74
+ summary: "Validate and persist a content source URL",
75
+ requestBody: z.object({ url: z.string() }),
76
+ handler: handleContentSource,
77
+ },
78
+ ];
@@ -11,6 +11,7 @@ import { z } from "zod";
11
11
 
12
12
  import { clearAllConversations as clearAllActive } from "../../daemon/handlers/conversations.js";
13
13
  import { formatJson, formatMarkdown } from "../../export/formatter.js";
14
+ import { ipcCall as ipcCallGateway } from "../../ipc/gateway-client.js";
14
15
  import {
15
16
  addMessage,
16
17
  createConversation,
@@ -19,8 +20,10 @@ import {
19
20
  } from "../../memory/conversation-crud.js";
20
21
  import { setConversationKey } from "../../memory/conversation-key-store.js";
21
22
  import { listConversations } from "../../memory/conversation-queries.js";
23
+ import { getBindingByConversation } from "../../memory/external-conversation-store.js";
24
+ import { sendSlackReply } from "../../messaging/providers/slack/send.js";
22
25
  import { getLogger } from "../../util/logger.js";
23
- import { BadRequestError, NotFoundError } from "./errors.js";
26
+ import { BadGatewayError, BadRequestError, NotFoundError } from "./errors.js";
24
27
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
25
28
 
26
29
  const log = getLogger("conversation-cli-routes");
@@ -150,6 +153,136 @@ async function handleClearCli(_args: RouteHandlerArgs) {
150
153
  return { cleared };
151
154
  }
152
155
 
156
+ // ---------------------------------------------------------------------------
157
+ // slack detach (CLI)
158
+ // ---------------------------------------------------------------------------
159
+
160
+ const slackDetachRequestSchema = z.object({
161
+ conversationId: z.string().trim().min(1).optional(),
162
+ channelId: z.string().trim().min(1).optional(),
163
+ threadTs: z.string().trim().min(1).optional(),
164
+ });
165
+
166
+ const slackDetachResponseSchema = z.object({
167
+ detached: z.boolean(),
168
+ channelId: z.string(),
169
+ threadTs: z.string(),
170
+ source: z.enum(["explicit", "conversation_binding"]),
171
+ conversationId: z.string().optional(),
172
+ });
173
+
174
+ type SlackDetachGatewayResponse = {
175
+ detached: boolean;
176
+ channelId: string;
177
+ threadTs: string;
178
+ };
179
+
180
+ const SLACK_DETACH_CONFIRMATION_TEXT =
181
+ "Muted this Slack thread. I won't respond to further replies here unless you mention me again.";
182
+
183
+ function isSlackDetachGatewayResponse(
184
+ value: unknown,
185
+ ): value is SlackDetachGatewayResponse {
186
+ return (
187
+ value != null &&
188
+ typeof value === "object" &&
189
+ typeof (value as SlackDetachGatewayResponse).detached === "boolean" &&
190
+ typeof (value as SlackDetachGatewayResponse).channelId === "string" &&
191
+ typeof (value as SlackDetachGatewayResponse).threadTs === "string"
192
+ );
193
+ }
194
+
195
+ async function handleSlackDetachCli({ body = {} }: RouteHandlerArgs) {
196
+ const parsed = slackDetachRequestSchema.parse(body);
197
+ const explicitChannelId = parsed.channelId;
198
+ const explicitThreadTs = parsed.threadTs;
199
+
200
+ let channelId: string;
201
+ let threadTs: string;
202
+ let source: "explicit" | "conversation_binding";
203
+ let conversationId: string | undefined;
204
+
205
+ if (explicitChannelId || explicitThreadTs) {
206
+ if (!explicitChannelId || !explicitThreadTs) {
207
+ throw new BadRequestError(
208
+ "Both channelId and threadTs are required when detaching by explicit Slack identifiers",
209
+ );
210
+ }
211
+ channelId = explicitChannelId;
212
+ threadTs = explicitThreadTs;
213
+ source = "explicit";
214
+ } else {
215
+ if (!parsed.conversationId) {
216
+ throw new BadRequestError(
217
+ "conversationId is required unless channelId and threadTs are provided",
218
+ );
219
+ }
220
+
221
+ const binding = getBindingByConversation(parsed.conversationId);
222
+ if (!binding) {
223
+ throw new NotFoundError(
224
+ `No channel binding found for conversation ${parsed.conversationId}`,
225
+ );
226
+ }
227
+ if (binding.sourceChannel !== "slack") {
228
+ throw new BadRequestError(
229
+ `Conversation ${parsed.conversationId} is bound to ${binding.sourceChannel}, not Slack`,
230
+ );
231
+ }
232
+ if (!binding.externalThreadId) {
233
+ throw new BadRequestError(
234
+ `Conversation ${parsed.conversationId} is not bound to a Slack thread`,
235
+ );
236
+ }
237
+
238
+ channelId = binding.externalChatId;
239
+ threadTs = binding.externalThreadId;
240
+ source = "conversation_binding";
241
+ conversationId = parsed.conversationId;
242
+ }
243
+
244
+ const gatewayResult = await ipcCallGateway(
245
+ "detach_slack_active_thread",
246
+ { channelId, threadTs },
247
+ 5_000,
248
+ );
249
+ if (!isSlackDetachGatewayResponse(gatewayResult)) {
250
+ throw new BadGatewayError(
251
+ "Could not detach Slack thread from assistant listening",
252
+ );
253
+ }
254
+
255
+ if (gatewayResult.detached) {
256
+ try {
257
+ await sendSlackReply(
258
+ gatewayResult.channelId,
259
+ SLACK_DETACH_CONFIRMATION_TEXT,
260
+ { threadTs: gatewayResult.threadTs },
261
+ );
262
+ } catch (err) {
263
+ log.warn(
264
+ {
265
+ err,
266
+ channelId: gatewayResult.channelId,
267
+ threadTs: gatewayResult.threadTs,
268
+ },
269
+ "Slack thread detached, but confirmation message failed",
270
+ );
271
+ throw new BadGatewayError(
272
+ "Detached Slack thread but could not send confirmation",
273
+ );
274
+ }
275
+ }
276
+
277
+ return {
278
+ detached: gatewayResult.detached,
279
+ channelId: gatewayResult.channelId,
280
+ threadTs: gatewayResult.threadTs,
281
+ source,
282
+ ...(conversationId ? { conversationId } : {}),
283
+ };
284
+ }
285
+
153
286
  // ---------------------------------------------------------------------------
154
287
  // Route definitions
155
288
  // ---------------------------------------------------------------------------
@@ -230,4 +363,16 @@ export const ROUTES: RouteDefinition[] = [
230
363
  }),
231
364
  handler: handleClearCli,
232
365
  },
366
+ {
367
+ operationId: "conversation_slack_detach_cli",
368
+ endpoint: "conversations/cli/slack/detach",
369
+ method: "POST",
370
+ summary: "Detach the assistant from a Slack thread (CLI)",
371
+ description:
372
+ "Stops Slack active-thread listening for a Slack thread. The CLI resolves current conversation defaults.",
373
+ tags: ["conversations"],
374
+ requestBody: slackDetachRequestSchema,
375
+ responseBody: slackDetachResponseSchema,
376
+ handler: handleSlackDetachCli,
377
+ },
233
378
  ];
@@ -15,6 +15,7 @@
15
15
  * GET /v1/messages/:id/llm-context — LLM request logs for a message
16
16
  * GET /v1/llm-request-logs/:id/payload — raw payload for a single log
17
17
  * DELETE /v1/messages/queued/:id — delete queued message
18
+ * POST /v1/messages/queued/:id/steer — steer to a queued message
18
19
  */
19
20
 
20
21
  import { z } from "zod";
@@ -49,7 +50,10 @@ import {
49
50
  getMessageContent,
50
51
  performConversationSearch,
51
52
  } from "../../daemon/handlers/conversation-history.js";
52
- import { deleteQueuedMessage } from "../../daemon/handlers/conversations.js";
53
+ import {
54
+ deleteQueuedMessage,
55
+ steerToMessage,
56
+ } from "../../daemon/handlers/conversations.js";
53
57
  import {
54
58
  CONFIG_RELOAD_DEBOUNCE_MS,
55
59
  log,
@@ -854,6 +858,12 @@ async function handleGetLlmContext({ pathParams = {} }: RouteHandlerArgs) {
854
858
  requestPayload: null,
855
859
  responsePayload: null,
856
860
  createdAt: log.createdAt,
861
+ // Agent-loop exit reason for the iteration that produced this
862
+ // call, stamped onto the most-recent unstamped log by
863
+ // `conversation-agent-loop-handlers.ts` after the loop yields.
864
+ // Only the terminal call in each loop iteration carries a value;
865
+ // non-terminal calls land here as `null`.
866
+ agentLoopExitReason: log.agentLoopExitReason ?? null,
857
867
  ...result,
858
868
  };
859
869
  }),
@@ -909,6 +919,36 @@ function handleDeleteQueuedMessage({
909
919
  throw new NotFoundError("Queued message not found");
910
920
  }
911
921
 
922
+ function handleSteerToMessage({
923
+ queryParams = {},
924
+ pathParams = {},
925
+ body,
926
+ }: RouteHandlerArgs) {
927
+ const conversationId =
928
+ queryParams.conversationId ??
929
+ (body && typeof body === "object" && "conversationId" in body
930
+ ? (body as Record<string, unknown>).conversationId
931
+ : undefined);
932
+ if (!conversationId || typeof conversationId !== "string") {
933
+ throw new BadRequestError(
934
+ "Missing required parameter: conversationId",
935
+ );
936
+ }
937
+ const result = steerToMessage(conversationId, pathParams.id ?? "");
938
+ if (result.steered) {
939
+ return { ok: true, conversationId, requestId: pathParams.id };
940
+ }
941
+ if (result.reason === "conversation_not_found") {
942
+ throw new NotFoundError("Conversation not found");
943
+ }
944
+ if (result.reason === "not_processing") {
945
+ throw new BadRequestError(
946
+ "Cannot steer: conversation is not currently processing",
947
+ );
948
+ }
949
+ throw new NotFoundError("Queued message not found");
950
+ }
951
+
912
952
  // ---------------------------------------------------------------------------
913
953
  // Route definitions (shared HTTP + IPC)
914
954
  // ---------------------------------------------------------------------------
@@ -1140,4 +1180,23 @@ export const ROUTES: RouteDefinition[] = [
1140
1180
  ],
1141
1181
  handler: handleDeleteQueuedMessage,
1142
1182
  },
1183
+ {
1184
+ operationId: "messages_queued_steer",
1185
+ endpoint: "messages/queued/:id/steer",
1186
+ method: "POST",
1187
+ policyKey: "messages/queued",
1188
+ summary: "Steer to a queued message",
1189
+ description:
1190
+ "Promote a queued message to the head of the queue and abort the current generation so it is processed next.",
1191
+ tags: ["messages"],
1192
+ queryParams: [
1193
+ {
1194
+ name: "conversationId",
1195
+ schema: { type: "string" },
1196
+ required: true,
1197
+ description: "Conversation ID (required)",
1198
+ },
1199
+ ],
1200
+ handler: handleSteerToMessage,
1201
+ },
1143
1202
  ];