@vellumai/assistant 0.8.2 → 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 (503) hide show
  1. package/ARCHITECTURE.md +11 -12
  2. package/docker-entrypoint.sh +13 -2
  3. package/docker-init-apt-root.sh +79 -6
  4. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  5. package/openapi.yaml +945 -36
  6. package/package.json +1 -1
  7. package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
  8. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  9. package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +272 -0
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  14. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  15. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  16. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  17. package/src/__tests__/compaction-events.test.ts +1 -1
  18. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  19. package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
  20. package/src/__tests__/config-get-vision-flag.test.ts +136 -0
  21. package/src/__tests__/config-loader-backfill.test.ts +115 -18
  22. package/src/__tests__/config-watcher.test.ts +1 -1
  23. package/src/__tests__/context-token-estimator.test.ts +112 -57
  24. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  25. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
  26. package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
  27. package/src/__tests__/conversation-agent-loop.test.ts +77 -3
  28. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  29. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  30. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  31. package/src/__tests__/conversation-fork-crud.test.ts +161 -0
  32. package/src/__tests__/conversation-lifecycle.test.ts +1 -1
  33. package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
  34. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  35. package/src/__tests__/conversation-media-retry.test.ts +19 -8
  36. package/src/__tests__/conversation-pairing.test.ts +2 -2
  37. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  38. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
  39. package/src/__tests__/conversation-queue.test.ts +1 -1
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
  41. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  42. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  43. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  44. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  45. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  46. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  47. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
  48. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  49. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  50. package/src/__tests__/credential-security-invariants.test.ts +6 -0
  51. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  52. package/src/__tests__/date-context.test.ts +45 -0
  53. package/src/__tests__/dm-backfill.test.ts +64 -0
  54. package/src/__tests__/dm-persistence.test.ts +33 -0
  55. package/src/__tests__/document-find-replace.test.ts +501 -0
  56. package/src/__tests__/external-plugin-loader.test.ts +91 -19
  57. package/src/__tests__/first-greeting.test.ts +23 -2
  58. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
  59. package/src/__tests__/guardian-dispatch.test.ts +1 -0
  60. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  61. package/src/__tests__/heartbeat-service.test.ts +24 -164
  62. package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
  63. package/src/__tests__/host-app-control-proxy.test.ts +241 -0
  64. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  65. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  66. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  67. package/src/__tests__/host-file-proxy.test.ts +8 -1
  68. package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
  69. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  70. package/src/__tests__/identity-routes.test.ts +57 -0
  71. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  72. package/src/__tests__/injector-background-turn.test.ts +153 -0
  73. package/src/__tests__/injector-chain.test.ts +7 -0
  74. package/src/__tests__/injector-document-comments.test.ts +378 -0
  75. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  76. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
  77. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  78. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  79. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  80. package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
  81. package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
  82. package/src/__tests__/llm-catalog-parity.test.ts +3 -0
  83. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  84. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
  85. package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
  86. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
  87. package/src/__tests__/llm-resolver.test.ts +340 -3
  88. package/src/__tests__/log-export-routes.test.ts +99 -2
  89. package/src/__tests__/managed-profile-guard.test.ts +10 -0
  90. package/src/__tests__/message-queue-steer.test.ts +114 -0
  91. package/src/__tests__/notification-decision-fallback.test.ts +0 -91
  92. package/src/__tests__/notification-decision-strategy.test.ts +14 -31
  93. package/src/__tests__/notification-deep-link.test.ts +15 -0
  94. package/src/__tests__/notification-guardian-path.test.ts +1 -2
  95. package/src/__tests__/notification-platform-adapter.test.ts +5 -4
  96. package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
  97. package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
  98. package/src/__tests__/openai-provider.test.ts +323 -3
  99. package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
  100. package/src/__tests__/openai-responses-provider.test.ts +4 -4
  101. package/src/__tests__/openrouter-provider-only.test.ts +51 -3
  102. package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
  103. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  104. package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
  105. package/src/__tests__/platform-proxy-context.test.ts +6 -1
  106. package/src/__tests__/platform.test.ts +0 -3
  107. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  108. package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
  109. package/src/__tests__/plugin-types.test.ts +2 -2
  110. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  111. package/src/__tests__/process-message-display-content.test.ts +21 -16
  112. package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
  113. package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
  114. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
  115. package/src/__tests__/server-history-render.test.ts +83 -4
  116. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  117. package/src/__tests__/system-prompt.test.ts +57 -101
  118. package/src/__tests__/terminal-tools.test.ts +11 -1
  119. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  120. package/src/__tests__/thread-backfill.test.ts +370 -22
  121. package/src/__tests__/tool-executor.test.ts +90 -1
  122. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  123. package/src/__tests__/twilio-routes.test.ts +1 -1
  124. package/src/__tests__/web-fetch.test.ts +2 -2
  125. package/src/__tests__/workspace-git-service.test.ts +88 -5
  126. package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
  127. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  128. package/src/a2a/__tests__/agent-card.test.ts +98 -0
  129. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
  130. package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
  131. package/src/a2a/__tests__/task-store.test.ts +246 -0
  132. package/src/a2a/agent-card.ts +58 -0
  133. package/src/a2a/feature-gate.ts +8 -0
  134. package/src/a2a/protocol-constants.ts +21 -0
  135. package/src/a2a/protocol-errors.ts +50 -0
  136. package/src/a2a/protocol-types.ts +162 -0
  137. package/src/a2a/task-store.ts +168 -0
  138. package/src/agent/attachments.ts +1 -0
  139. package/src/agent/loop.ts +208 -22
  140. package/src/background-wake/next-wake.test.ts +289 -0
  141. package/src/background-wake/next-wake.ts +172 -0
  142. package/src/browser/operations.ts +15 -0
  143. package/src/channels/config.ts +9 -0
  144. package/src/channels/types.ts +14 -0
  145. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  146. package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
  147. package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
  148. package/src/cli/commands/__tests__/schedules.test.ts +469 -0
  149. package/src/cli/commands/conversations.ts +128 -1
  150. package/src/cli/commands/inference-providers.ts +147 -1
  151. package/src/cli/commands/memory-v2.ts +308 -0
  152. package/src/cli/commands/notifications.ts +89 -37
  153. package/src/cli/commands/plugins.ts +67 -0
  154. package/src/cli/commands/schedules.ts +297 -5
  155. package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
  156. package/src/cli/lib/install-from-github.ts +8 -9
  157. package/src/cli/lib/search-plugins.ts +163 -0
  158. package/src/cli/program.ts +14 -0
  159. package/src/cli/utils/conversation-id.ts +17 -5
  160. package/src/config/assistant-feature-flags.ts +24 -54
  161. package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
  162. package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
  163. package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
  164. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  165. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  166. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  167. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  168. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  169. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  170. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  171. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  172. package/src/config/bundled-tool-registry.ts +22 -12
  173. package/src/config/call-site-defaults.ts +124 -0
  174. package/src/config/feature-flag-registry.json +111 -23
  175. package/src/config/llm-resolver.ts +66 -1
  176. package/src/config/schema.ts +2 -0
  177. package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
  178. package/src/config/schemas/call-site-catalog.ts +21 -0
  179. package/src/config/schemas/channels.ts +9 -0
  180. package/src/config/schemas/conversations.ts +10 -0
  181. package/src/config/schemas/heartbeat.ts +14 -0
  182. package/src/config/schemas/llm.ts +4 -3
  183. package/src/config/schemas/memory-retrospective.ts +1 -1
  184. package/src/config/schemas/memory-v2.ts +51 -4
  185. package/src/config/schemas/memory.ts +3 -1
  186. package/src/config/seed-inference-profiles.ts +99 -29
  187. package/src/context/compactor.ts +80 -13
  188. package/src/context/token-estimator.ts +72 -31
  189. package/src/context/window-manager.ts +25 -0
  190. package/src/credential-health/credential-health-service.ts +34 -19
  191. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
  192. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  193. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  194. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  195. package/src/daemon/conversation-agent-loop-handlers.ts +231 -23
  196. package/src/daemon/conversation-agent-loop.ts +252 -56
  197. package/src/daemon/conversation-lifecycle.ts +142 -116
  198. package/src/daemon/conversation-messaging.ts +3 -0
  199. package/src/daemon/conversation-process.ts +273 -0
  200. package/src/daemon/conversation-queue-manager.ts +14 -0
  201. package/src/daemon/conversation-runtime-assembly.ts +144 -75
  202. package/src/daemon/conversation-slash.ts +37 -5
  203. package/src/daemon/conversation-surfaces.ts +45 -2
  204. package/src/daemon/conversation-tool-setup.ts +7 -0
  205. package/src/daemon/conversation.ts +42 -12
  206. package/src/daemon/date-context.ts +40 -0
  207. package/src/daemon/first-greeting.ts +10 -0
  208. package/src/daemon/guardian-action-generators.ts +1 -125
  209. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  210. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
  211. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
  212. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
  213. package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
  214. package/src/daemon/handlers/config-a2a.ts +449 -0
  215. package/src/daemon/handlers/config-model.test.ts +1 -0
  216. package/src/daemon/handlers/conversations.ts +80 -0
  217. package/src/daemon/handlers/shared.ts +92 -29
  218. package/src/daemon/host-app-control-proxy.ts +69 -18
  219. package/src/daemon/host-bash-proxy.ts +1 -1
  220. package/src/daemon/host-cu-proxy.ts +1 -1
  221. package/src/daemon/host-file-proxy.ts +1 -1
  222. package/src/daemon/host-proxy-preactivation.ts +85 -18
  223. package/src/daemon/host-transfer-proxy.ts +1 -1
  224. package/src/daemon/lifecycle.ts +67 -65
  225. package/src/daemon/memory-v2-startup.ts +49 -13
  226. package/src/daemon/message-protocol.ts +4 -0
  227. package/src/daemon/message-types/conversations.ts +8 -0
  228. package/src/daemon/message-types/document-comments.ts +50 -0
  229. package/src/daemon/message-types/messages.ts +68 -1
  230. package/src/daemon/message-types/notifications.ts +21 -0
  231. package/src/daemon/message-types/surfaces.ts +3 -1
  232. package/src/daemon/message-types/web-activity.ts +57 -0
  233. package/src/daemon/pkb-reminder-builder.test.ts +10 -53
  234. package/src/daemon/pkb-reminder-builder.ts +4 -19
  235. package/src/daemon/plugin-source-watcher.ts +135 -3
  236. package/src/daemon/process-message.ts +72 -12
  237. package/src/daemon/query-complexity-router.ts +75 -0
  238. package/src/daemon/skill-memory-refresh.ts +5 -1
  239. package/src/daemon/trust-context.ts +6 -0
  240. package/src/daemon/wake-target-adapter.ts +2 -0
  241. package/src/documents/document-comments-store.test.ts +338 -0
  242. package/src/documents/document-comments-store.ts +237 -0
  243. package/src/documents/document-store.ts +202 -0
  244. package/src/export/__tests__/transcript-formatter.test.ts +121 -0
  245. package/src/export/transcript-formatter.ts +54 -20
  246. package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
  247. package/src/heartbeat/heartbeat-service.ts +35 -191
  248. package/src/home/__tests__/feed-types.test.ts +40 -0
  249. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  250. package/src/home/feed-types.ts +20 -3
  251. package/src/home/home-content-refresh.ts +52 -0
  252. package/src/home/home-greeting-cache.ts +69 -0
  253. package/src/home/home-greeting.ts +94 -0
  254. package/src/home/suggested-prompts.ts +177 -9
  255. package/src/ipc/cli-client.ts +147 -45
  256. package/src/memory/__tests__/conversation-queries.test.ts +220 -0
  257. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  258. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
  259. package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
  260. package/src/memory/conversation-crud.ts +133 -43
  261. package/src/memory/conversation-queries.ts +87 -1
  262. package/src/memory/conversation-title-service.ts +26 -4
  263. package/src/memory/db-init.ts +22 -0
  264. package/src/memory/delivery-crud.ts +41 -0
  265. package/src/memory/delivery-status.ts +141 -15
  266. package/src/memory/external-conversation-store.ts +32 -1
  267. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
  268. package/src/memory/graph/conversation-graph-memory.ts +18 -6
  269. package/src/memory/graph/tools.ts +6 -37
  270. package/src/memory/invite-store.ts +53 -0
  271. package/src/memory/jobs-worker.ts +21 -1
  272. package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
  273. package/src/memory/llm-request-log-store.ts +92 -1
  274. package/src/memory/memory-retrospective-constants.ts +28 -0
  275. package/src/memory/memory-retrospective-enqueue.ts +4 -22
  276. package/src/memory/memory-retrospective-job.ts +438 -21
  277. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  278. package/src/memory/memory-v2-activation-log-store.ts +26 -8
  279. package/src/memory/migrations/100-core-tables.ts +1 -0
  280. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  281. package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
  282. package/src/memory/migrations/251-a2a-tasks.ts +49 -0
  283. package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
  284. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  285. package/src/memory/migrations/253-document-comments.ts +47 -0
  286. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  287. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  288. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  289. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  290. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  291. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  292. package/src/memory/migrations/index.ts +20 -0
  293. package/src/memory/migrations/registry.ts +33 -0
  294. package/src/memory/onboarding-events-store.ts +7 -0
  295. package/src/memory/schema/a2a.ts +15 -0
  296. package/src/memory/schema/calls.ts +1 -0
  297. package/src/memory/schema/conversations.ts +3 -0
  298. package/src/memory/schema/index.ts +1 -0
  299. package/src/memory/schema/inference.ts +2 -0
  300. package/src/memory/schema/infrastructure.ts +2 -0
  301. package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
  302. package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
  303. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
  304. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  305. package/src/memory/v2/__tests__/injection.test.ts +221 -17
  306. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  307. package/src/memory/v2/__tests__/router.test.ts +489 -1
  308. package/src/memory/v2/__tests__/static-context.test.ts +12 -1
  309. package/src/memory/v2/activation-store.ts +14 -16
  310. package/src/memory/v2/cli-command-content.ts +19 -0
  311. package/src/memory/v2/cli-command-store.ts +304 -0
  312. package/src/memory/v2/consolidation-job.ts +14 -0
  313. package/src/memory/v2/frontmatter-sweep.ts +7 -1
  314. package/src/memory/v2/injection-events.ts +101 -0
  315. package/src/memory/v2/injection.ts +69 -29
  316. package/src/memory/v2/page-index.ts +246 -19
  317. package/src/memory/v2/page-store.ts +18 -0
  318. package/src/memory/v2/router.ts +209 -55
  319. package/src/memory/v2/static-context.ts +4 -4
  320. package/src/memory/v2/types.ts +23 -0
  321. package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
  322. package/src/messaging/providers/a2a/deliver.ts +156 -0
  323. package/src/messaging/providers/gmail/client.ts +9 -2
  324. package/src/messaging/providers/index.ts +18 -3
  325. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  326. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  327. package/src/messaging/providers/slack/adapter.ts +178 -25
  328. package/src/messaging/providers/slack/api.test.ts +54 -0
  329. package/src/messaging/providers/slack/api.ts +119 -3
  330. package/src/messaging/providers/slack/client.ts +12 -0
  331. package/src/messaging/providers/slack/deep-link.ts +20 -1
  332. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  333. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  334. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  335. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  336. package/src/messaging/providers/slack/send.test.ts +77 -0
  337. package/src/messaging/providers/slack/send.ts +8 -2
  338. package/src/messaging/providers/slack/types.ts +14 -0
  339. package/src/notifications/__tests__/broadcaster.test.ts +203 -0
  340. package/src/notifications/__tests__/decision-engine.test.ts +283 -0
  341. package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
  342. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
  343. package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
  344. package/src/notifications/adapters/macos.ts +12 -2
  345. package/src/notifications/broadcaster.ts +29 -4
  346. package/src/notifications/conversation-seed-composer.ts +14 -2
  347. package/src/notifications/copy-composer.ts +17 -64
  348. package/src/notifications/decision-engine.ts +111 -44
  349. package/src/notifications/deferred-emit.ts +135 -0
  350. package/src/notifications/deterministic-checks.ts +96 -0
  351. package/src/notifications/emit-signal.ts +10 -1
  352. package/src/notifications/home-feed-side-effect.ts +136 -27
  353. package/src/notifications/signal.ts +0 -4
  354. package/src/notifications/types.ts +8 -0
  355. package/src/oauth/connect-orchestrator.ts +3 -0
  356. package/src/oauth/credential-token-resolver.ts +2 -0
  357. package/src/oauth/manual-token-connection.ts +19 -0
  358. package/src/oauth/oauth-store.ts +12 -0
  359. package/src/oauth/platform-connection.test.ts +43 -3
  360. package/src/oauth/platform-connection.ts +13 -4
  361. package/src/oauth/seed-providers.ts +22 -0
  362. package/src/permissions/prompter.ts +5 -2
  363. package/src/permissions/secret-prompter.ts +4 -1
  364. package/src/plugins/defaults/injectors.ts +118 -26
  365. package/src/plugins/external-plugin-loader.ts +82 -10
  366. package/src/plugins/types.ts +16 -7
  367. package/src/prompts/__tests__/system-prompt.test.ts +44 -45
  368. package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
  369. package/src/prompts/normalize-onboarding.ts +40 -0
  370. package/src/prompts/sections.ts +32 -14
  371. package/src/prompts/system-prompt.ts +105 -76
  372. package/src/prompts/template-detection.ts +37 -0
  373. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  374. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  375. package/src/prompts/templates/VOICE.md +3 -0
  376. package/src/prompts/templates/system-sections.ts +51 -10
  377. package/src/providers/__tests__/inference.test.ts +2 -0
  378. package/src/providers/anthropic/client.ts +132 -5
  379. package/src/providers/call-site-routing.ts +24 -6
  380. package/src/providers/connection-resolution.ts +63 -13
  381. package/src/providers/fireworks/client.ts +20 -2
  382. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
  383. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  384. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  385. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  386. package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
  387. package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
  388. package/src/providers/inference/adapter-factory.ts +24 -21
  389. package/src/providers/inference/auth.ts +15 -3
  390. package/src/providers/inference/backfill.ts +14 -1
  391. package/src/providers/inference/codex-token-refresh.ts +128 -0
  392. package/src/providers/inference/connections.ts +85 -5
  393. package/src/providers/inference/resolve-auth.ts +50 -5
  394. package/src/providers/model-catalog.ts +244 -242
  395. package/src/providers/model-intents.ts +3 -3
  396. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
  397. package/src/providers/openai/chat-completions-provider.ts +215 -25
  398. package/src/providers/openai/responses-provider.ts +9 -3
  399. package/src/providers/openrouter/client.ts +46 -4
  400. package/src/providers/platform-proxy/constants.ts +3 -4
  401. package/src/providers/provider-catalog-visibility.ts +3 -1
  402. package/src/providers/provider-send-message.ts +27 -12
  403. package/src/providers/registry.ts +30 -1
  404. package/src/providers/types.ts +25 -0
  405. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  406. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  407. package/src/runtime/agent-wake.ts +212 -57
  408. package/src/runtime/auth/route-policy.ts +20 -3
  409. package/src/runtime/background-job-runner.ts +26 -0
  410. package/src/runtime/channel-reply-delivery.ts +182 -47
  411. package/src/runtime/channel-retry-sweep.ts +141 -16
  412. package/src/runtime/http-server.ts +7 -16
  413. package/src/runtime/http-types.ts +7 -51
  414. package/src/runtime/pending-interactions.ts +51 -8
  415. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
  416. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  417. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
  418. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
  419. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
  420. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  421. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
  422. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  423. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  424. package/src/runtime/routes/approval-routes.ts +4 -1
  425. package/src/runtime/routes/channel-availability-routes.ts +5 -0
  426. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  427. package/src/runtime/routes/consolidation-routes.ts +100 -0
  428. package/src/runtime/routes/content-source-routes.ts +78 -0
  429. package/src/runtime/routes/conversation-cli-routes.ts +146 -1
  430. package/src/runtime/routes/conversation-query-routes.ts +130 -12
  431. package/src/runtime/routes/conversation-routes.ts +288 -76
  432. package/src/runtime/routes/document-comments-routes.ts +287 -0
  433. package/src/runtime/routes/documents-routes.ts +33 -0
  434. package/src/runtime/routes/home-feed-routes.ts +6 -3
  435. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  436. package/src/runtime/routes/host-browser-routes.ts +8 -1
  437. package/src/runtime/routes/identity-routes.ts +21 -0
  438. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  439. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  440. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  441. package/src/runtime/routes/index.ts +14 -4
  442. package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
  443. package/src/runtime/routes/integrations/a2a.ts +294 -0
  444. package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
  445. package/src/runtime/routes/log-export-routes.ts +39 -0
  446. package/src/runtime/routes/memory-v2-routes.ts +217 -0
  447. package/src/runtime/routes/notification-routes.ts +19 -2
  448. package/src/runtime/routes/question-routes.ts +4 -1
  449. package/src/runtime/routes/sanity-routes.ts +159 -0
  450. package/src/runtime/routes/slack-channel-routes.ts +187 -0
  451. package/src/runtime/routes/subagents-routes.ts +41 -0
  452. package/src/runtime/services/conversation-serializer.ts +30 -4
  453. package/src/schedule/integration-status.ts +3 -1
  454. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  455. package/src/security/oauth2-device-code.ts +307 -0
  456. package/src/security/oauth2.ts +26 -9
  457. package/src/security/secure-keys.ts +5 -0
  458. package/src/skills/catalog-install.ts +6 -2
  459. package/src/subagent/manager.ts +2 -0
  460. package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
  461. package/src/tools/browser/browser-execution.ts +93 -0
  462. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  463. package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
  464. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
  465. package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
  466. package/src/tools/browser/cdp-client/factory.ts +87 -3
  467. package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
  468. package/src/tools/browser/cdp-client/types.ts +36 -0
  469. package/src/tools/browser/pinned-tabs.ts +90 -0
  470. package/src/tools/document/document-comment-tool.test.ts +379 -0
  471. package/src/tools/document/document-comment-tool.ts +156 -0
  472. package/src/tools/document/document-tool.ts +128 -2
  473. package/src/tools/memory/register.ts +1 -9
  474. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  475. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  476. package/src/tools/network/domain-normalize.ts +17 -0
  477. package/src/tools/network/web-fetch.ts +213 -64
  478. package/src/tools/network/web-search.ts +191 -66
  479. package/src/tools/registry.ts +2 -2
  480. package/src/tools/terminal/safe-env.ts +3 -2
  481. package/src/tools/tool-approval-handler.ts +19 -12
  482. package/src/tools/types.ts +41 -2
  483. package/src/tools/ui-surface/definitions.ts +3 -1
  484. package/src/types/onboarding-context.ts +4 -0
  485. package/src/util/__tests__/favicon.test.ts +84 -0
  486. package/src/util/favicon.ts +40 -0
  487. package/src/util/platform.ts +0 -5
  488. package/src/workspace/git-service.ts +75 -4
  489. package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
  490. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  491. package/src/workspace/migrations/registry.ts +4 -0
  492. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
  493. package/src/config/bundled-skills/document/SKILL.md +0 -54
  494. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  495. package/src/daemon/seed-files.ts +0 -18
  496. package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
  497. package/src/runtime/guardian-action-conversation-turn.ts +0 -99
  498. package/src/runtime/routes/interface-routes.ts +0 -43
  499. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  500. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  501. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  502. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  503. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -21,6 +21,13 @@ interface FakeChunk {
21
21
  choices: Array<{
22
22
  delta: {
23
23
  content?: string | null;
24
+ reasoning_content?: string | null;
25
+ reasoning?: string | null;
26
+ reasoning_details?: Array<{
27
+ type?: string;
28
+ summary?: string | null;
29
+ text?: string | null;
30
+ }> | null;
24
31
  tool_calls?: Array<{
25
32
  index: number;
26
33
  id?: string;
@@ -209,6 +216,44 @@ function cachedUsageChunk(
209
216
  };
210
217
  }
211
218
 
219
+ function reasoningChunk(
220
+ reasoning: string,
221
+ finish: string | null = null,
222
+ ): FakeChunk {
223
+ return {
224
+ choices: [
225
+ { delta: { reasoning_content: reasoning }, finish_reason: finish },
226
+ ],
227
+ usage: null,
228
+ model: "gpt-5.2",
229
+ };
230
+ }
231
+
232
+ // OpenRouter spec uses `delta.reasoning` rather than `delta.reasoning_content`.
233
+ function openRouterReasoningChunk(
234
+ reasoning: string,
235
+ finish: string | null = null,
236
+ ): FakeChunk {
237
+ return {
238
+ choices: [{ delta: { reasoning }, finish_reason: finish }],
239
+ usage: null,
240
+ model: "gpt-5.2",
241
+ };
242
+ }
243
+
244
+ // OpenRouter's documented reasoning-summary shape: a `reasoning_details` array
245
+ // with entries tagged `reasoning.summary` / `reasoning.text` / `reasoning.encrypted`.
246
+ function reasoningDetailsChunk(
247
+ details: Array<{ type?: string; summary?: string; text?: string }>,
248
+ finish: string | null = null,
249
+ ): FakeChunk {
250
+ return {
251
+ choices: [{ delta: { reasoning_details: details }, finish_reason: finish }],
252
+ usage: null,
253
+ model: "gpt-5.2",
254
+ };
255
+ }
256
+
212
257
  // ---------------------------------------------------------------------------
213
258
  // Class extraction sanity checks
214
259
  // ---------------------------------------------------------------------------
@@ -339,6 +384,153 @@ describe("OpenAIProvider", () => {
339
384
  expect(events[1]).toEqual({ type: "text_delta", text: ", world!" });
340
385
  });
341
386
 
387
+ // -----------------------------------------------------------------------
388
+ // Reasoning content (MiniMax / DeepSeek extension)
389
+ // -----------------------------------------------------------------------
390
+ test("parses reasoning_content into thinking block", async () => {
391
+ fakeChunks = [
392
+ reasoningChunk("Let me think..."),
393
+ textChunk("The answer is 42."),
394
+ usageChunk(10, 20),
395
+ ];
396
+
397
+ const result = await provider.sendMessage([userMsg("Hi")]);
398
+
399
+ expect(result.content).toHaveLength(2);
400
+ expect(result.content[0]).toEqual({
401
+ type: "thinking",
402
+ thinking: "Let me think...",
403
+ signature: "",
404
+ });
405
+ expect(result.content[1]).toEqual({
406
+ type: "text",
407
+ text: "The answer is 42.",
408
+ });
409
+ expect(result.usage).toEqual({ inputTokens: 10, outputTokens: 20 });
410
+ });
411
+
412
+ test("fires thinking_delta events during streaming", async () => {
413
+ fakeChunks = [
414
+ reasoningChunk("Let me think..."),
415
+ textChunk("The answer is 42."),
416
+ usageChunk(10, 20),
417
+ ];
418
+
419
+ const events: ProviderEvent[] = [];
420
+ await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
421
+ onEvent: (e) => events.push(e),
422
+ });
423
+
424
+ expect(events).toHaveLength(2);
425
+ expect(events[0]).toEqual({
426
+ type: "thinking_delta",
427
+ thinking: "Let me think...",
428
+ });
429
+ expect(events[1]).toEqual({
430
+ type: "text_delta",
431
+ text: "The answer is 42.",
432
+ });
433
+ });
434
+
435
+ test("reasoning + tool calls orders correctly (thinking → tool_use)", async () => {
436
+ fakeChunks = [
437
+ reasoningChunk("Planning..."),
438
+ ...toolCallChunks([
439
+ { id: "call_1", name: "file_read", args: '{"path":"/a"}' },
440
+ ]),
441
+ usageChunk(10, 30),
442
+ ];
443
+
444
+ const result = await provider.sendMessage([userMsg("Read /a")]);
445
+
446
+ expect(result.content).toHaveLength(2);
447
+ expect(result.content[0].type).toBe("thinking");
448
+ expect(result.content[1].type).toBe("tool_use");
449
+ });
450
+
451
+ test("no thinking block when reasoning_content is absent", async () => {
452
+ fakeChunks = [textChunk("Just text"), usageChunk(10, 5)];
453
+
454
+ const result = await provider.sendMessage([userMsg("Hi")]);
455
+
456
+ expect(result.content).toHaveLength(1);
457
+ expect(result.content[0].type).toBe("text");
458
+ });
459
+
460
+ test("parses OpenRouter's `delta.reasoning` field into thinking block", async () => {
461
+ fakeChunks = [
462
+ openRouterReasoningChunk("Hmm, let me think..."),
463
+ textChunk("Final answer."),
464
+ usageChunk(10, 8),
465
+ ];
466
+
467
+ const events: ProviderEvent[] = [];
468
+ const result = await provider.sendMessage(
469
+ [userMsg("Hi")],
470
+ undefined,
471
+ undefined,
472
+ {
473
+ onEvent: (e) => events.push(e),
474
+ },
475
+ );
476
+
477
+ expect(result.content).toHaveLength(2);
478
+ expect(result.content[0]).toEqual({
479
+ type: "thinking",
480
+ thinking: "Hmm, let me think...",
481
+ signature: "",
482
+ });
483
+ expect(result.content[1]).toEqual({ type: "text", text: "Final answer." });
484
+ expect(events).toContainEqual({
485
+ type: "thinking_delta",
486
+ thinking: "Hmm, let me think...",
487
+ });
488
+ });
489
+
490
+ test("parses OpenRouter `delta.reasoning_details` summary/text entries and skips encrypted", async () => {
491
+ fakeChunks = [
492
+ reasoningDetailsChunk([
493
+ { type: "reasoning.summary", summary: "Plan step one. " },
494
+ { type: "reasoning.encrypted", text: "ENCRYPTED_BLOB" },
495
+ { type: "reasoning.text", text: "Detailed thought." },
496
+ ]),
497
+ textChunk("Done."),
498
+ usageChunk(10, 8),
499
+ ];
500
+
501
+ const events: ProviderEvent[] = [];
502
+ const result = await provider.sendMessage(
503
+ [userMsg("Hi")],
504
+ undefined,
505
+ undefined,
506
+ {
507
+ onEvent: (e) => events.push(e),
508
+ },
509
+ );
510
+
511
+ expect(result.content).toHaveLength(2);
512
+ expect(result.content[0]).toEqual({
513
+ type: "thinking",
514
+ thinking: "Plan step one. Detailed thought.",
515
+ signature: "",
516
+ });
517
+ expect(result.content[1]).toEqual({ type: "text", text: "Done." });
518
+ expect(events).toContainEqual({
519
+ type: "thinking_delta",
520
+ thinking: "Plan step one. ",
521
+ });
522
+ expect(events).toContainEqual({
523
+ type: "thinking_delta",
524
+ thinking: "Detailed thought.",
525
+ });
526
+ // Encrypted blob must never surface as visible thinking.
527
+ for (const e of events) {
528
+ if (e.type === "thinking_delta") {
529
+ expect(e.thinking).not.toContain("ENCRYPTED_BLOB");
530
+ }
531
+ }
532
+ });
533
+
342
534
  // -----------------------------------------------------------------------
343
535
  // System prompt
344
536
  // -----------------------------------------------------------------------
@@ -1306,14 +1498,17 @@ describe("OpenRouterProvider reasoning", () => {
1306
1498
  shouldThrow = null;
1307
1499
  });
1308
1500
 
1309
- test("sends reasoning.enabled=true when thinking config is present", async () => {
1501
+ test("sends reasoning.enabled=true with default detailed summary when thinking config is present", async () => {
1310
1502
  const provider = new OpenRouterProvider("or-key", "x-ai/grok-4");
1311
1503
  await provider.sendMessage([userMsg("hi")], undefined, undefined, {
1312
1504
  config: { thinking: { type: "adaptive" } },
1313
1505
  });
1314
1506
 
1315
1507
  expect(lastCreateParams).toBeTruthy();
1316
- expect(lastCreateParams!.reasoning).toEqual({ enabled: true });
1508
+ expect(lastCreateParams!.reasoning).toEqual({
1509
+ enabled: true,
1510
+ summary: "detailed",
1511
+ });
1317
1512
  });
1318
1513
 
1319
1514
  test("sends reasoning.enabled=false when thinking is explicitly disabled", async () => {
@@ -1376,7 +1571,10 @@ describe("OpenRouterProvider reasoning", () => {
1376
1571
  await retry.sendMessage([userMsg("hi")], undefined, undefined, {
1377
1572
  config: { thinking: { type: "adaptive" } },
1378
1573
  });
1379
- expect(lastCreateParams!.reasoning).toEqual({ enabled: true });
1574
+ expect(lastCreateParams!.reasoning).toEqual({
1575
+ enabled: true,
1576
+ summary: "detailed",
1577
+ });
1380
1578
  });
1381
1579
 
1382
1580
  test("RetryProvider + OpenRouterProvider disables thinking end-to-end", async () => {
@@ -1389,6 +1587,23 @@ describe("OpenRouterProvider reasoning", () => {
1389
1587
  });
1390
1588
  expect(lastCreateParams!.reasoning).toEqual({ enabled: false });
1391
1589
  });
1590
+
1591
+ test("nests effort under reasoning and omits top-level reasoning_effort", async () => {
1592
+ const provider = new OpenRouterProvider("or-key", "moonshotai/kimi-k2.6");
1593
+ await provider.sendMessage([userMsg("hi")], undefined, undefined, {
1594
+ config: { thinking: { enabled: true }, effort: "max" },
1595
+ });
1596
+
1597
+ expect(lastCreateParams).toBeTruthy();
1598
+ expect(lastCreateParams!.reasoning).toEqual({
1599
+ enabled: true,
1600
+ effort: "xhigh",
1601
+ summary: "detailed",
1602
+ });
1603
+ // Critical: must NOT also send the OpenAI-native flat field — OpenRouter
1604
+ // rejects requests that carry both forms for reasoning models.
1605
+ expect(lastCreateParams).not.toHaveProperty("reasoning_effort");
1606
+ });
1392
1607
  });
1393
1608
 
1394
1609
  describe("OpenRouterProvider Anthropic-compatible errors", () => {
@@ -1529,4 +1744,109 @@ describe("OpenAIProvider reasoning_effort", () => {
1529
1744
  });
1530
1745
  expect(lastCreateParams!.reasoning_effort).toBe("medium");
1531
1746
  });
1747
+
1748
+ test('maxReasoningEffort: "max" passes "max" through unclamped', async () => {
1749
+ const uncapped = new OpenAIProvider("test-key", "gpt-5", {
1750
+ maxReasoningEffort: "max",
1751
+ });
1752
+ await uncapped.sendMessage([userMsg("hi")], undefined, "system", {
1753
+ config: { effort: "max" },
1754
+ });
1755
+ expect(lastCreateParams!.reasoning_effort).toBe("max");
1756
+ await uncapped.sendMessage([userMsg("hi")], undefined, "system", {
1757
+ config: { effort: "xhigh" },
1758
+ });
1759
+ expect(lastCreateParams!.reasoning_effort).toBe("xhigh");
1760
+ });
1761
+ });
1762
+
1763
+ describe("FireworksProvider reasoning_effort ceiling", () => {
1764
+ beforeEach(() => {
1765
+ fakeChunks = [];
1766
+ lastCreateParams = null;
1767
+ });
1768
+
1769
+ test('DeepSeek V4 Pro accepts "max" unclamped', async () => {
1770
+ const fw = new FireworksProvider(
1771
+ "fw-key",
1772
+ "accounts/fireworks/models/deepseek-v4-pro",
1773
+ );
1774
+ await fw.sendMessage([userMsg("hi")], undefined, "system", {
1775
+ config: { effort: "max" },
1776
+ });
1777
+ expect(lastCreateParams!.reasoning_effort).toBe("max");
1778
+ });
1779
+
1780
+ test('DeepSeek V4 Pro accepts "xhigh" unclamped', async () => {
1781
+ const fw = new FireworksProvider(
1782
+ "fw-key",
1783
+ "accounts/fireworks/models/deepseek-v4-pro",
1784
+ );
1785
+ await fw.sendMessage([userMsg("hi")], undefined, "system", {
1786
+ config: { effort: "xhigh" },
1787
+ });
1788
+ expect(lastCreateParams!.reasoning_effort).toBe("xhigh");
1789
+ });
1790
+
1791
+ test('Kimi K2.6 clamps "xhigh"/"max" down to "high"', async () => {
1792
+ const fw = new FireworksProvider(
1793
+ "fw-key",
1794
+ "accounts/fireworks/models/kimi-k2p6",
1795
+ );
1796
+ await fw.sendMessage([userMsg("hi")], undefined, "system", {
1797
+ config: { effort: "xhigh" },
1798
+ });
1799
+ expect(lastCreateParams!.reasoning_effort).toBe("high");
1800
+ await fw.sendMessage([userMsg("hi")], undefined, "system", {
1801
+ config: { effort: "max" },
1802
+ });
1803
+ expect(lastCreateParams!.reasoning_effort).toBe("high");
1804
+ });
1805
+
1806
+ test('unknown Fireworks model falls back to "high" ceiling', async () => {
1807
+ const fw = new FireworksProvider(
1808
+ "fw-key",
1809
+ "accounts/fireworks/models/some-future-model",
1810
+ );
1811
+ await fw.sendMessage([userMsg("hi")], undefined, "system", {
1812
+ config: { effort: "max" },
1813
+ });
1814
+ expect(lastCreateParams!.reasoning_effort).toBe("high");
1815
+ });
1816
+
1817
+ test("effort below ceiling is forwarded verbatim", async () => {
1818
+ const fw = new FireworksProvider(
1819
+ "fw-key",
1820
+ "accounts/fireworks/models/deepseek-v4-pro",
1821
+ );
1822
+ await fw.sendMessage([userMsg("hi")], undefined, "system", {
1823
+ config: { effort: "medium" },
1824
+ });
1825
+ expect(lastCreateParams!.reasoning_effort).toBe("medium");
1826
+ });
1827
+
1828
+ test('effort: "none" passes through regardless of ceiling', async () => {
1829
+ const fw = new FireworksProvider(
1830
+ "fw-key",
1831
+ "accounts/fireworks/models/kimi-k2p6",
1832
+ );
1833
+ await fw.sendMessage([userMsg("hi")], undefined, "system", {
1834
+ config: { effort: "none" },
1835
+ });
1836
+ expect(lastCreateParams!.reasoning_effort).toBe("none");
1837
+ });
1838
+
1839
+ test("model override picks ceiling from runtime model, not constructor model", async () => {
1840
+ const fw = new FireworksProvider(
1841
+ "fw-key",
1842
+ "accounts/fireworks/models/kimi-k2p6",
1843
+ );
1844
+ await fw.sendMessage([userMsg("hi")], undefined, "system", {
1845
+ config: {
1846
+ effort: "max",
1847
+ model: "accounts/fireworks/models/deepseek-v4-pro",
1848
+ },
1849
+ });
1850
+ expect(lastCreateParams!.reasoning_effort).toBe("max");
1851
+ });
1532
1852
  });
@@ -92,9 +92,9 @@ describe("OpenAI Responses API cutover guard", () => {
92
92
 
93
93
  // The factory must NOT instantiate OpenAIChatCompletionsProvider or
94
94
  // OpenAIProvider (the backward-compatible alias) inside the `openai:`
95
- // factory entry. Other entries (e.g. `zai:`, `deepseek:`, `minimax:`)
96
- // may legitimately use OpenAIChatCompletionsProvider since that's the
97
- // OpenAI Chat Completions transport for third-party endpoints.
95
+ // factory entry. Other entries (e.g. `openai-compatible:`) may legitimately
96
+ // use OpenAIChatCompletionsProvider since that's the OpenAI Chat Completions
97
+ // transport for third-party endpoints.
98
98
  const openaiEntryRegion =
99
99
  /(?:^|\s)openai\s*:\s*\([^)]*\)\s*=>\s*[\s\S]{0,400}?(?=\}\s*,\s*[a-z-]+\s*:|\}\s*;)/m.exec(
100
100
  source,
@@ -714,16 +714,16 @@ describe("OpenAIResponsesProvider", () => {
714
714
  });
715
715
 
716
716
  // -----------------------------------------------------------------------
717
- // store: false
717
+ // store — omitted so prompt caching can persist across turns
718
718
  // -----------------------------------------------------------------------
719
- test("sends store: false in params", async () => {
719
+ test("does not set store in params (defaults to true server-side)", async () => {
720
720
  fakeStreamEvents = [textDeltaEvent("OK"), completedEvent(10, 2)];
721
721
 
722
722
  await provider.sendMessage([
723
723
  { role: "user", content: [{ type: "text", text: "Hi" }] },
724
724
  ]);
725
725
 
726
- expect(lastStreamParams!.store).toBe(false);
726
+ expect(lastStreamParams!.store).toBeUndefined();
727
727
  });
728
728
 
729
729
  // -----------------------------------------------------------------------
@@ -1122,7 +1122,7 @@ describe("OpenAIResponsesProvider", () => {
1122
1122
  const rawReq = result.rawRequest as Record<string, unknown>;
1123
1123
  expect(rawReq.model).toBe("gpt-5.2");
1124
1124
  expect(rawReq.instructions).toBe("System prompt");
1125
- expect(rawReq.store).toBe(false);
1125
+ expect(rawReq.store).toBeUndefined();
1126
1126
 
1127
1127
  // rawResponse should contain the final response object, including `output`
1128
1128
  // which downstream normalization relies on for Responses API detection.
@@ -116,7 +116,7 @@ describe("OpenRouter provider.only plumbing", () => {
116
116
  expect(extras.provider).toBe(undefined);
117
117
  });
118
118
 
119
- test("still carries reasoning flag alongside provider.only", () => {
119
+ test("enables thinking with default detailed summary alongside provider.only", () => {
120
120
  const provider = new ProbeOpenRouterProvider(
121
121
  "fake-key",
122
122
  "x-ai/grok-4.20-beta",
@@ -128,12 +128,12 @@ describe("OpenRouter provider.only plumbing", () => {
128
128
  },
129
129
  });
130
130
  expect(extras).toEqual({
131
- reasoning: { enabled: true },
131
+ reasoning: { enabled: true, summary: "detailed" },
132
132
  provider: { only: ["xAI"] },
133
133
  });
134
134
  });
135
135
 
136
- test("disabled thinking keeps reasoning disabled alongside provider.only", () => {
136
+ test("disabled thinking keeps reasoning disabled and omits summary", () => {
137
137
  const provider = new ProbeOpenRouterProvider(
138
138
  "fake-key",
139
139
  "x-ai/grok-4.20-beta",
@@ -149,5 +149,53 @@ describe("OpenRouter provider.only plumbing", () => {
149
149
  provider: { only: ["xAI"] },
150
150
  });
151
151
  });
152
+
153
+ test("nests effort under reasoning and maps `max` to xhigh", () => {
154
+ const provider = new ProbeOpenRouterProvider(
155
+ "fake-key",
156
+ "moonshotai/kimi-k2.6",
157
+ );
158
+ const extras = provider.probeExtras({
159
+ config: {
160
+ thinking: { enabled: true },
161
+ effort: "max",
162
+ },
163
+ });
164
+ expect(extras).toEqual({
165
+ reasoning: { enabled: true, effort: "xhigh", summary: "detailed" },
166
+ });
167
+ });
168
+
169
+ test("honors a per-call summary override", () => {
170
+ const provider = new ProbeOpenRouterProvider(
171
+ "fake-key",
172
+ "moonshotai/kimi-k2.6",
173
+ );
174
+ const extras = provider.probeExtras({
175
+ config: {
176
+ thinking: { enabled: true },
177
+ openrouter: { reasoning: { summary: "concise" } },
178
+ },
179
+ });
180
+ expect(extras).toEqual({
181
+ reasoning: { enabled: true, summary: "concise" },
182
+ });
183
+ });
184
+
185
+ test("ignores an invalid summary override and falls back to detailed", () => {
186
+ const provider = new ProbeOpenRouterProvider(
187
+ "fake-key",
188
+ "moonshotai/kimi-k2.6",
189
+ );
190
+ const extras = provider.probeExtras({
191
+ config: {
192
+ thinking: { enabled: true },
193
+ openrouter: { reasoning: { summary: "verbose" } },
194
+ },
195
+ });
196
+ expect(extras).toEqual({
197
+ reasoning: { enabled: true, summary: "detailed" },
198
+ });
199
+ });
152
200
  });
153
201
  });
@@ -5,7 +5,11 @@ import { OpenRouterProvider } from "../providers/openrouter/client.js";
5
5
  import type { Message } from "../providers/types.js";
6
6
 
7
7
  /** Build a minimal valid PNG header encoding the given dimensions. */
8
- function makePngBase64(width: number, height: number, paddingBytes = 0): string {
8
+ function makePngBase64(
9
+ width: number,
10
+ height: number,
11
+ paddingBytes = 0,
12
+ ): string {
9
13
  const header = Buffer.alloc(24);
10
14
  header[0] = 0x89;
11
15
  header[1] = 0x50;
@@ -41,13 +45,13 @@ describe("OpenRouterProvider token estimation routing", () => {
41
45
  expect(provider.tokenEstimationProvider).toBe("openrouter");
42
46
  });
43
47
 
44
- test("estimatePromptTokens applies Anthropic image scaling when routed via OpenRouter", () => {
48
+ test("estimatePromptTokens applies dimension-based image scaling when routed via OpenRouter to Anthropic", () => {
45
49
  const provider = new OpenRouterProvider(
46
50
  "fake-key",
47
51
  "anthropic/claude-opus-4-6",
48
52
  );
49
53
  // 1920x1080 screenshot with ~200 KB of pixel data → base64/4 would be ~65k
50
- // tokens; dimension-based Anthropic rules land around 1.6k tokens.
54
+ // tokens; dimension-based rules land around 1.6k tokens.
51
55
  const messages: Message[] = [
52
56
  {
53
57
  role: "user",
@@ -68,33 +72,38 @@ describe("OpenRouterProvider token estimation routing", () => {
68
72
  providerName: provider.tokenEstimationProvider,
69
73
  });
70
74
 
71
- // Dimension-based estimate should be well under 5k; base64/4 would exceed 50k.
72
75
  expect(estimated).toBeLessThan(5_000);
73
76
  });
74
77
 
75
- test("estimatePromptTokens falls back to base64/4 for non-Anthropic OpenRouter models", () => {
76
- const provider = new OpenRouterProvider("fake-key", "x-ai/grok-4.20-beta");
77
- const messages: Message[] = [
78
- {
79
- role: "user",
80
- content: [
81
- {
82
- type: "image",
83
- source: {
84
- type: "base64",
85
- media_type: "image/png",
86
- data: makePngBase64(1920, 1080, 200_000),
78
+ test("estimatePromptTokens applies dimension-based image scaling for non-Anthropic OpenRouter models", () => {
79
+ // A naive base64/4 estimate on a 1920x1080 screenshot (~200 KB) lands near
80
+ // 65k tokens and trips spurious compaction long before the real context
81
+ // window fills. Vision models on OpenRouter — both anthropic/* and
82
+ // non-Anthropic (Kimi K2.6, Grok, etc.) — must use the dimension-based
83
+ // formula.
84
+ for (const model of ["moonshotai/kimi-k2.6", "x-ai/grok-4.20-beta"]) {
85
+ const provider = new OpenRouterProvider("fake-key", model);
86
+ const messages: Message[] = [
87
+ {
88
+ role: "user",
89
+ content: [
90
+ {
91
+ type: "image",
92
+ source: {
93
+ type: "base64",
94
+ media_type: "image/png",
95
+ data: makePngBase64(1920, 1080, 200_000),
96
+ },
87
97
  },
88
- },
89
- ],
90
- },
91
- ];
98
+ ],
99
+ },
100
+ ];
92
101
 
93
- const estimated = estimatePromptTokens(messages, "system", {
94
- providerName: provider.tokenEstimationProvider,
95
- });
102
+ const estimated = estimatePromptTokens(messages, "system", {
103
+ providerName: provider.tokenEstimationProvider,
104
+ });
96
105
 
97
- // Base64/4 heuristic on ~200 KB of image data → far more than 10k tokens.
98
- expect(estimated).toBeGreaterThan(50_000);
106
+ expect(estimated).toBeLessThan(5_000);
107
+ }
99
108
  });
100
109
  });