blume 1.7.3 → 2.0.1

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 (690) hide show
  1. package/AGENTS.md +19 -0
  2. package/CHANGELOG.md +245 -0
  3. package/README.md +34 -21
  4. package/dist/cli/{chunk-vacwm2hv.js → chunk-27g6wdth.js} +2 -2
  5. package/dist/cli/{chunk-ps4m1xh4.js → chunk-2hn4b8z7.js} +513 -550
  6. package/dist/cli/chunk-2hn4b8z7.js.map +12 -0
  7. package/dist/cli/chunk-5shv93fd.js +39 -0
  8. package/dist/cli/chunk-5shv93fd.js.map +10 -0
  9. package/dist/cli/chunk-6crbhc3x.js +361 -0
  10. package/dist/cli/chunk-6crbhc3x.js.map +14 -0
  11. package/dist/cli/{chunk-8cjtbafj.js → chunk-6hsn950k.js} +109 -383
  12. package/dist/cli/chunk-6hsn950k.js.map +10 -0
  13. package/dist/cli/chunk-6vm74dry.js +148 -0
  14. package/dist/cli/chunk-6vm74dry.js.map +10 -0
  15. package/dist/cli/{chunk-yg63d42r.js → chunk-79jhk4py.js} +87 -58
  16. package/dist/cli/chunk-79jhk4py.js.map +35 -0
  17. package/dist/cli/chunk-82bbrxdn.js +51 -0
  18. package/dist/cli/chunk-82bbrxdn.js.map +10 -0
  19. package/dist/cli/chunk-abh8yjkn.js +31 -0
  20. package/dist/cli/chunk-abh8yjkn.js.map +10 -0
  21. package/dist/cli/chunk-ah61y8py.js +75 -0
  22. package/dist/cli/chunk-ah61y8py.js.map +11 -0
  23. package/dist/cli/{chunk-dwgcp5sm.js → chunk-ce574jw2.js} +1 -1
  24. package/dist/cli/chunk-ch6g3ar0.js +102 -0
  25. package/dist/cli/chunk-ch6g3ar0.js.map +10 -0
  26. package/dist/cli/chunk-dh8cwk36.js +279 -0
  27. package/dist/cli/chunk-dh8cwk36.js.map +10 -0
  28. package/dist/cli/{chunk-rqy0s5wh.js → chunk-epjnccmv.js} +17 -16
  29. package/dist/cli/{chunk-rqy0s5wh.js.map → chunk-epjnccmv.js.map} +3 -3
  30. package/dist/cli/chunk-f2z5v128.js +97 -0
  31. package/dist/cli/chunk-f2z5v128.js.map +10 -0
  32. package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
  33. package/dist/cli/chunk-fa25z98p.js.map +11 -0
  34. package/dist/cli/{chunk-1jefwnfs.js → chunk-fs23ddbb.js} +1076 -2592
  35. package/dist/cli/chunk-fs23ddbb.js.map +35 -0
  36. package/dist/cli/{chunk-e7f42gdj.js → chunk-fxypxtvm.js} +2 -2
  37. package/dist/cli/{chunk-bvwwhd84.js → chunk-fz5wtpmh.js} +15 -15
  38. package/dist/cli/{chunk-bvwwhd84.js.map → chunk-fz5wtpmh.js.map} +1 -1
  39. package/dist/cli/chunk-hdpx1tax.js +91 -0
  40. package/dist/cli/chunk-hdpx1tax.js.map +10 -0
  41. package/dist/cli/{chunk-ct47dqpx.js → chunk-jts8mvcz.js} +67 -7
  42. package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
  43. package/dist/cli/{chunk-ahnw3kxw.js → chunk-jwyddg7y.js} +27 -22
  44. package/dist/cli/chunk-jwyddg7y.js.map +15 -0
  45. package/dist/cli/{chunk-cjtn640a.js → chunk-kdp5q7ke.js} +43 -20
  46. package/dist/cli/chunk-kdp5q7ke.js.map +10 -0
  47. package/dist/cli/{chunk-5g0w1e2c.js → chunk-kpf8rrjc.js} +28 -16
  48. package/dist/cli/{chunk-5g0w1e2c.js.map → chunk-kpf8rrjc.js.map} +4 -4
  49. package/dist/cli/chunk-m3vmjgmq.js +133 -0
  50. package/dist/cli/chunk-m3vmjgmq.js.map +10 -0
  51. package/dist/cli/{chunk-b27xqwn9.js → chunk-mb2919y2.js} +9 -5
  52. package/dist/cli/chunk-mb2919y2.js.map +10 -0
  53. package/dist/cli/{chunk-5qk08vmp.js → chunk-q5163e60.js} +133 -54
  54. package/dist/cli/chunk-q5163e60.js.map +11 -0
  55. package/dist/cli/chunk-qkqwkpte.js +12437 -0
  56. package/dist/cli/chunk-qkqwkpte.js.map +182 -0
  57. package/dist/cli/{chunk-4x36ddpw.js → chunk-qs4q5p4e.js} +81 -87
  58. package/dist/cli/chunk-qs4q5p4e.js.map +10 -0
  59. package/dist/cli/{chunk-0xjyb285.js → chunk-qwsrynx5.js} +15 -5
  60. package/dist/cli/{chunk-0xjyb285.js.map → chunk-qwsrynx5.js.map} +4 -4
  61. package/dist/cli/chunk-s1p84fyh.js +261 -0
  62. package/dist/cli/chunk-s1p84fyh.js.map +10 -0
  63. package/dist/cli/chunk-s6jhgk0q.js +176 -0
  64. package/dist/cli/chunk-s6jhgk0q.js.map +11 -0
  65. package/dist/cli/chunk-vtk4a6dg.js +374 -0
  66. package/dist/cli/chunk-vtk4a6dg.js.map +10 -0
  67. package/dist/cli/{chunk-k79xp7av.js → chunk-wgm7m9qk.js} +230 -700
  68. package/dist/cli/chunk-wgm7m9qk.js.map +36 -0
  69. package/dist/cli/chunk-wm7js3j9.js +145 -0
  70. package/dist/cli/chunk-wm7js3j9.js.map +11 -0
  71. package/dist/cli/chunk-yt5n7ppj.js +79 -0
  72. package/dist/cli/chunk-yt5n7ppj.js.map +10 -0
  73. package/dist/cli/{chunk-3r45185y.js → chunk-yw7dm696.js} +9 -11
  74. package/dist/cli/{chunk-3r45185y.js.map → chunk-yw7dm696.js.map} +3 -3
  75. package/dist/cli/{chunk-nn13znc2.js → chunk-zxcczpyx.js} +1 -1
  76. package/dist/cli/chunk-zxh4d9vy.js +122 -0
  77. package/dist/cli/chunk-zxh4d9vy.js.map +11 -0
  78. package/dist/cli/index.js +214 -57
  79. package/dist/cli/index.js.map +8 -7
  80. package/dist/types/ai/agent-readability.d.ts +52 -0
  81. package/dist/types/ai/ai-catalog.d.ts +42 -0
  82. package/dist/types/ai/api/paths.d.ts +17 -0
  83. package/dist/types/ai/api-catalog.d.ts +18 -0
  84. package/dist/types/ai/ask-context.d.ts +7 -7
  85. package/dist/types/ai/ask.d.ts +368 -0
  86. package/dist/types/ai/changelog-markdown.d.ts +2 -0
  87. package/dist/types/ai/component-markdown.d.ts +2 -2
  88. package/dist/types/ai/index.d.ts +24 -0
  89. package/dist/types/ai/link-headers.d.ts +24 -0
  90. package/dist/types/ai/llms.d.ts +25 -0
  91. package/dist/types/ai/markdown.d.ts +45 -0
  92. package/dist/types/ai/mcp/discovery.d.ts +68 -0
  93. package/dist/types/ai/mcp/tools.d.ts +16 -0
  94. package/dist/types/ai/openapi-components.d.ts +43 -0
  95. package/dist/types/ai/relative-links.d.ts +26 -0
  96. package/dist/types/ai/serializers.d.ts +15 -0
  97. package/dist/types/ai/skills.d.ts +42 -0
  98. package/dist/types/ai/tar.d.ts +25 -0
  99. package/dist/types/ai/visibility.d.ts +17 -0
  100. package/dist/types/ai/web-bot-auth.d.ts +16 -0
  101. package/dist/types/analytics/adobe.d.ts +35 -0
  102. package/dist/types/analytics/amplitude.d.ts +50 -0
  103. package/dist/types/analytics/clarity.d.ts +31 -0
  104. package/dist/types/analytics/clearbit.d.ts +29 -0
  105. package/dist/types/analytics/cloudflare.d.ts +41 -0
  106. package/dist/types/analytics/fathom.d.ts +41 -0
  107. package/dist/types/analytics/google-analytics.d.ts +44 -0
  108. package/dist/types/analytics/google-tag-manager.d.ts +40 -0
  109. package/dist/types/analytics/head.d.ts +30 -0
  110. package/dist/types/analytics/heap.d.ts +40 -0
  111. package/dist/types/analytics/hightouch.d.ts +44 -0
  112. package/dist/types/analytics/hotjar.d.ts +33 -0
  113. package/dist/types/analytics/index.d.ts +61 -0
  114. package/dist/types/analytics/inline.d.ts +17 -0
  115. package/dist/types/analytics/logrocket.d.ts +44 -0
  116. package/dist/types/analytics/mixpanel.d.ts +67 -0
  117. package/dist/types/analytics/pirsch.d.ts +42 -0
  118. package/dist/types/analytics/plausible.d.ts +56 -0
  119. package/dist/types/analytics/posthog.d.ts +45 -0
  120. package/dist/types/analytics/schema.d.ts +320 -0
  121. package/dist/types/analytics/script.d.ts +46 -0
  122. package/dist/types/analytics/segment.d.ts +50 -0
  123. package/dist/types/analytics/vercel.d.ts +48 -0
  124. package/dist/types/astro/integration.d.ts +76 -0
  125. package/dist/types/astro/markdown-negotiation.d.ts +23 -0
  126. package/dist/types/astro/module-types.d.ts +14 -0
  127. package/dist/types/astro/pages.d.ts +44 -0
  128. package/dist/types/cli/env.d.ts +12 -0
  129. package/dist/types/cli/init/scaffold.d.ts +154 -0
  130. package/dist/types/components/layout/nav-utils.d.ts +11 -0
  131. package/dist/types/core/adapter.d.ts +47 -0
  132. package/dist/types/core/api-name.d.ts +7 -0
  133. package/dist/types/core/changelog-index.d.ts +13 -0
  134. package/dist/types/core/config-input.d.ts +197 -526
  135. package/dist/types/core/config.d.ts +61 -35
  136. package/dist/types/core/content-assets.d.ts +76 -0
  137. package/dist/types/core/custom-pages.d.ts +33 -0
  138. package/dist/types/core/data.d.ts +30 -15
  139. package/dist/types/core/define-components.d.ts +12 -9
  140. package/dist/types/core/deployment-env.d.ts +6 -11
  141. package/dist/types/core/frontmatter.d.ts +10 -0
  142. package/dist/types/core/graph.d.ts +18 -0
  143. package/dist/types/core/heading-markers.d.ts +54 -0
  144. package/dist/types/core/i18n-ui.d.ts +12 -10
  145. package/dist/types/core/i18n.d.ts +87 -0
  146. package/dist/types/core/includes.d.ts +138 -0
  147. package/dist/types/core/last-modified.d.ts +47 -0
  148. package/dist/types/core/links.d.ts +95 -0
  149. package/dist/types/core/locale-links.d.ts +60 -0
  150. package/dist/types/core/manifest.d.ts +17 -0
  151. package/dist/types/core/meta.d.ts +38 -0
  152. package/dist/types/core/nav-diagnostics.d.ts +26 -0
  153. package/dist/types/core/navigation.d.ts +6 -0
  154. package/dist/types/core/node-require.d.ts +19 -0
  155. package/dist/types/core/package-json.d.ts +13 -0
  156. package/dist/types/core/probe.d.ts +42 -0
  157. package/dist/types/core/project-graph.d.ts +51 -0
  158. package/dist/types/core/project.d.ts +2 -0
  159. package/dist/types/core/safe-href.d.ts +2 -0
  160. package/dist/types/core/safe-links.d.ts +26 -0
  161. package/dist/types/core/schema.d.ts +2284 -454
  162. package/dist/types/core/site-url.d.ts +16 -0
  163. package/dist/types/core/sources/assets.d.ts +36 -0
  164. package/dist/types/core/sources/cache.d.ts +37 -0
  165. package/dist/types/core/sources/collection.d.ts +28 -0
  166. package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
  167. package/dist/types/core/sources/contentful.d.ts +40 -0
  168. package/dist/types/core/sources/filesystem.d.ts +24 -0
  169. package/dist/types/core/sources/github-releases.d.ts +31 -0
  170. package/dist/types/core/sources/json.d.ts +30 -0
  171. package/dist/types/core/sources/lexical.d.ts +19 -0
  172. package/dist/types/core/sources/lower.d.ts +75 -0
  173. package/dist/types/core/sources/mdx-remote.d.ts +28 -0
  174. package/dist/types/core/sources/normalize.d.ts +147 -0
  175. package/dist/types/core/sources/notion.d.ts +131 -0
  176. package/dist/types/core/sources/obsidian.d.ts +46 -0
  177. package/dist/types/core/sources/payload.d.ts +39 -0
  178. package/dist/types/core/sources/portable-text.d.ts +42 -0
  179. package/dist/types/core/sources/read.d.ts +23 -0
  180. package/dist/types/core/sources/remote.d.ts +74 -0
  181. package/dist/types/core/sources/resolve.d.ts +19 -0
  182. package/dist/types/core/sources/sanity.d.ts +43 -0
  183. package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
  184. package/dist/types/core/sources/strapi.d.ts +33 -0
  185. package/dist/types/core/sources/types.d.ts +7 -0
  186. package/dist/types/core/sources/watch.d.ts +45 -0
  187. package/dist/types/core/text-width.d.ts +11 -0
  188. package/dist/types/core/types.d.ts +15 -1
  189. package/dist/types/core/unrecognized-keys.d.ts +7 -0
  190. package/dist/types/core/versions.d.ts +72 -0
  191. package/dist/types/core/yaml.d.ts +9 -0
  192. package/dist/types/deploy/adapter-output.d.ts +45 -0
  193. package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
  194. package/dist/types/deploy/adapters/index.d.ts +29 -0
  195. package/dist/types/deploy/adapters/netlify.d.ts +37 -0
  196. package/dist/types/deploy/adapters/node.d.ts +37 -0
  197. package/dist/types/deploy/adapters/registry.d.ts +133 -0
  198. package/dist/types/deploy/adapters/types.d.ts +71 -0
  199. package/dist/types/deploy/adapters/vercel.d.ts +38 -0
  200. package/dist/types/deploy/artifacts.d.ts +65 -0
  201. package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
  202. package/dist/types/deploy/function-bundle.d.ts +80 -0
  203. package/dist/types/deploy/headers.d.ts +50 -0
  204. package/dist/types/deploy/node-headers.d.ts +42 -0
  205. package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
  206. package/dist/types/deploy/platforms/index.d.ts +18 -0
  207. package/dist/types/deploy/platforms/netlify.d.ts +13 -0
  208. package/dist/types/deploy/platforms/node.d.ts +11 -0
  209. package/dist/types/deploy/platforms/paths.d.ts +27 -0
  210. package/dist/types/deploy/platforms/static.d.ts +10 -0
  211. package/dist/types/deploy/platforms/types.d.ts +104 -0
  212. package/dist/types/deploy/platforms/vercel.d.ts +32 -0
  213. package/dist/types/deploy/redirects.d.ts +53 -0
  214. package/dist/types/deploy/robots.d.ts +8 -0
  215. package/dist/types/deploy/rss.d.ts +31 -0
  216. package/dist/types/deploy/sitemap.d.ts +21 -0
  217. package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
  218. package/dist/types/markdown/code-title.d.ts +32 -0
  219. package/dist/types/markdown/fence-meta.d.ts +23 -0
  220. package/dist/types/markdown/themes.d.ts +3 -3
  221. package/dist/types/openapi/asyncapi.d.ts +129 -0
  222. package/dist/types/openapi/graphql-build.d.ts +8 -0
  223. package/dist/types/openapi/graphql.d.ts +122 -0
  224. package/dist/types/openapi/model.d.ts +158 -0
  225. package/dist/types/openapi/parse.d.ts +57 -0
  226. package/dist/types/openapi/references.d.ts +37 -25
  227. package/dist/types/openapi/render-mdx.d.ts +33 -0
  228. package/dist/types/openapi/sentence.d.ts +7 -0
  229. package/dist/types/openapi/signature.d.ts +10 -0
  230. package/dist/types/openapi/source.d.ts +22 -0
  231. package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
  232. package/dist/types/reference/asyncapi.d.ts +166 -0
  233. package/dist/types/reference/graphql.d.ts +181 -0
  234. package/dist/types/reference/index.d.ts +32 -0
  235. package/dist/types/reference/openapi.d.ts +165 -0
  236. package/dist/types/reference/options.d.ts +157 -0
  237. package/dist/types/reference/scalar.d.ts +136 -0
  238. package/dist/types/reference/schema.d.ts +630 -0
  239. package/dist/types/search/adapters/algolia.d.ts +32 -0
  240. package/dist/types/search/adapters/flexsearch.d.ts +12 -0
  241. package/dist/types/search/adapters/index.d.ts +31 -0
  242. package/dist/types/search/adapters/mixedbread.d.ts +22 -0
  243. package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
  244. package/dist/types/search/adapters/orama.d.ts +13 -0
  245. package/dist/types/search/adapters/pagefind.d.ts +12 -0
  246. package/dist/types/search/adapters/registry.d.ts +228 -0
  247. package/dist/types/search/adapters/types.d.ts +34 -0
  248. package/dist/types/search/adapters/typesense.d.ts +42 -0
  249. package/dist/types/search/build.d.ts +23 -0
  250. package/dist/types/search/documents.d.ts +90 -0
  251. package/dist/types/search/facets.d.ts +3 -0
  252. package/dist/types/search/orama-index.d.ts +1 -1
  253. package/dist/types/search/sync/algolia.d.ts +14 -0
  254. package/dist/types/search/sync/index.d.ts +14 -0
  255. package/dist/types/search/sync/orama-cloud.d.ts +10 -0
  256. package/dist/types/search/sync/typesense.d.ts +14 -0
  257. package/dist/types/sources/contentful.d.ts +68 -0
  258. package/dist/types/sources/custom.d.ts +20 -0
  259. package/dist/types/sources/filesystem.d.ts +42 -0
  260. package/dist/types/sources/github-releases.d.ts +46 -0
  261. package/dist/types/sources/index.d.ts +48 -0
  262. package/dist/types/sources/mdx-remote.d.ts +63 -0
  263. package/dist/types/sources/notion.d.ts +65 -0
  264. package/dist/types/sources/obsidian.d.ts +34 -0
  265. package/dist/types/sources/payload.d.ts +68 -0
  266. package/dist/types/sources/registry.d.ts +1414 -0
  267. package/dist/types/sources/sanity.d.ts +69 -0
  268. package/dist/types/sources/shared.d.ts +46 -0
  269. package/dist/types/sources/strapi.d.ts +66 -0
  270. package/dist/types/theme/icon-kind.d.ts +11 -0
  271. package/dist/types/theme/icons.d.ts +20 -0
  272. package/docs/01-quickstart.mdx +18 -18
  273. package/docs/02-deployment.mdx +52 -28
  274. package/docs/03-upgrading.mdx +364 -0
  275. package/docs/04-migrating.mdx +58 -0
  276. package/docs/08-faq.mdx +5 -5
  277. package/docs/advanced/blog.mdx +13 -6
  278. package/docs/advanced/changelog.mdx +23 -35
  279. package/docs/advanced/custom-pages.mdx +22 -10
  280. package/docs/advanced/meta.ts +1 -8
  281. package/docs/advanced/skills.mdx +8 -0
  282. package/docs/cli/audit.mdx +646 -0
  283. package/docs/cli/doctor.mdx +29 -0
  284. package/docs/{reference/eval.mdx → cli/evals.mdx} +12 -11
  285. package/docs/cli/index.mdx +105 -0
  286. package/docs/cli/meta.ts +7 -0
  287. package/docs/{reference → cli}/translate.mdx +9 -9
  288. package/docs/cli/validate.mdx +41 -0
  289. package/docs/cli/version.mdx +40 -0
  290. package/docs/configuration/analytics.mdx +350 -59
  291. package/docs/configuration/assistant.mdx +357 -0
  292. package/docs/configuration/customization.mdx +16 -10
  293. package/docs/configuration/index.mdx +50 -31
  294. package/docs/configuration/meta.ts +1 -1
  295. package/docs/configuration/search.mdx +76 -55
  296. package/docs/configuration/theming.mdx +24 -15
  297. package/docs/content/components.mdx +21 -5
  298. package/docs/{reference → content}/frontmatter.mdx +35 -1
  299. package/docs/content/i18n.mdx +9 -7
  300. package/docs/content/includes.mdx +2 -4
  301. package/docs/content/index.mdx +1 -1
  302. package/docs/content/islands.mdx +11 -6
  303. package/docs/content/meta.mdx +1 -1
  304. package/docs/content/meta.ts +1 -0
  305. package/docs/content/navigation.mdx +9 -7
  306. package/docs/content/sources.mdx +145 -50
  307. package/docs/content/syntax.mdx +16 -12
  308. package/docs/content/versioning.mdx +3 -3
  309. package/docs/discoverability/agent-discovery.mdx +12 -12
  310. package/docs/discoverability/index.mdx +4 -4
  311. package/docs/discoverability/json-api.mdx +4 -4
  312. package/docs/discoverability/llms-txt.mdx +6 -6
  313. package/docs/discoverability/markdown.mdx +4 -4
  314. package/docs/discoverability/mcp.mdx +11 -11
  315. package/docs/discoverability/sitemap-and-robots.mdx +3 -3
  316. package/docs/index.mdx +4 -4
  317. package/docs/references/asyncapi.mdx +59 -0
  318. package/docs/{advanced → references}/graphql.mdx +45 -32
  319. package/docs/{reference → references}/meta.ts +2 -2
  320. package/docs/references/openapi.mdx +171 -0
  321. package/docs/references/scalar.mdx +64 -0
  322. package/package.json +42 -8
  323. package/skills/blume/SKILL.md +23 -10
  324. package/skills/blume-migrate/SKILL.md +22 -21
  325. package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
  326. package/skills/blume-migrate/references/docusaurus.md +5 -4
  327. package/skills/blume-migrate/references/fumadocs.md +4 -4
  328. package/skills/blume-migrate/references/mintlify.md +23 -8
  329. package/skills/blume-migrate/references/monorepo.md +6 -6
  330. package/skills/blume-migrate/references/starlight.md +4 -4
  331. package/src/ai/agent-readability.ts +25 -26
  332. package/src/ai/ai-catalog.ts +50 -32
  333. package/src/ai/api/handlers.ts +46 -11
  334. package/src/ai/api/paths.ts +1 -1
  335. package/src/ai/api-catalog.ts +8 -8
  336. package/src/ai/ask-context.ts +7 -7
  337. package/src/ai/ask-data.ts +3 -3
  338. package/src/ai/ask.ts +637 -100
  339. package/src/ai/changelog-markdown.ts +91 -0
  340. package/src/ai/component-markdown.ts +328 -12
  341. package/src/ai/cors.ts +3 -3
  342. package/src/ai/index.ts +45 -0
  343. package/src/ai/link-headers.ts +7 -6
  344. package/src/ai/llms.ts +20 -15
  345. package/src/ai/markdown.ts +35 -5
  346. package/src/ai/mcp/data.ts +9 -5
  347. package/src/ai/openapi-components.ts +5 -2
  348. package/src/ai/relative-links.ts +170 -0
  349. package/src/ai/serializers.ts +3 -3
  350. package/src/ai/skills.ts +1 -1
  351. package/src/ai/visibility.ts +1 -1
  352. package/src/ai/web-bot-auth.ts +2 -2
  353. package/src/analytics/adobe.ts +46 -0
  354. package/src/analytics/amplitude.ts +79 -0
  355. package/src/analytics/clarity.ts +46 -0
  356. package/src/analytics/clearbit.ts +47 -0
  357. package/src/analytics/cloudflare.ts +67 -0
  358. package/src/analytics/fathom.ts +64 -0
  359. package/src/analytics/google-analytics.ts +84 -0
  360. package/src/analytics/google-tag-manager.ts +61 -0
  361. package/src/analytics/head.ts +130 -0
  362. package/src/analytics/heap.ts +65 -0
  363. package/src/analytics/hightouch.ts +77 -0
  364. package/src/analytics/hotjar.ts +47 -0
  365. package/src/analytics/index.ts +71 -0
  366. package/src/analytics/inline.ts +21 -0
  367. package/src/analytics/logrocket.ts +71 -0
  368. package/src/analytics/mixpanel.ts +92 -0
  369. package/src/analytics/pirsch.ts +66 -0
  370. package/src/analytics/plausible.ts +83 -0
  371. package/src/analytics/posthog.ts +78 -0
  372. package/src/analytics/schema.ts +60 -0
  373. package/src/analytics/script.ts +60 -0
  374. package/src/analytics/segment.ts +85 -0
  375. package/src/analytics/vercel.ts +50 -0
  376. package/src/astro/adapter-root.ts +7 -9
  377. package/src/astro/component-slots.ts +131 -91
  378. package/src/astro/generate.ts +129 -361
  379. package/src/astro/integration.ts +2 -6
  380. package/src/astro/module-types.ts +1 -1
  381. package/src/astro/pages.ts +13 -101
  382. package/src/astro/render-deps.ts +379 -0
  383. package/src/astro/runtime-deps.ts +201 -0
  384. package/src/astro/templates.ts +575 -562
  385. package/src/audit/agent.ts +24 -0
  386. package/src/audit/catalog.ts +2 -2
  387. package/src/audit/checks/assets.ts +2 -2
  388. package/src/audit/checks/dns-aid.ts +1 -1
  389. package/src/audit/checks/duplicates.ts +3 -1
  390. package/src/audit/checks/i18n.ts +1 -1
  391. package/src/audit/checks/indexability.ts +7 -7
  392. package/src/audit/checks/links.ts +2 -2
  393. package/src/audit/checks/llms.ts +6 -6
  394. package/src/audit/checks/network.ts +3 -3
  395. package/src/audit/checks/og-image.ts +2 -2
  396. package/src/audit/checks/robots.ts +1 -1
  397. package/src/audit/checks/sitemap.ts +2 -2
  398. package/src/audit/checks/social.ts +1 -1
  399. package/src/audit/run.ts +4 -3
  400. package/src/audit/terms.ts +31 -0
  401. package/src/audit/url.ts +13 -13
  402. package/src/blume-modules.d.ts +2 -2
  403. package/src/cli/command-meta.ts +10 -0
  404. package/src/cli/commands/audit.ts +40 -21
  405. package/src/cli/commands/build.ts +71 -316
  406. package/src/cli/commands/check.ts +1 -0
  407. package/src/cli/commands/dev.ts +40 -1
  408. package/src/cli/commands/doctor.ts +92 -14
  409. package/src/cli/commands/eject.ts +44 -7
  410. package/src/cli/commands/eval.ts +5 -5
  411. package/src/cli/commands/init.ts +161 -41
  412. package/src/cli/commands/migrate.ts +121 -0
  413. package/src/cli/commands/preview.ts +7 -1
  414. package/src/cli/commands/translate.ts +5 -5
  415. package/src/cli/commands/upgrade.ts +141 -0
  416. package/src/cli/commands/version.ts +57 -44
  417. package/src/cli/eject-scripts.ts +121 -6
  418. package/src/cli/index.ts +11 -1
  419. package/src/cli/init/install.ts +70 -0
  420. package/src/cli/init/questions.ts +7 -0
  421. package/src/cli/init/scaffold.ts +459 -75
  422. package/src/cli/lazy-command.ts +37 -1
  423. package/src/cli/prepare.ts +40 -6
  424. package/src/cli/required-secrets.ts +39 -12
  425. package/src/cli/unknown-flags.ts +266 -0
  426. package/src/cli/yarn-pnp.ts +52 -0
  427. package/src/components/content/AccordionItem.astro +7 -1
  428. package/src/components/content/Card.astro +4 -3
  429. package/src/components/content/ColorItem.astro +22 -4
  430. package/src/components/content/GithubInfo.astro +2 -2
  431. package/src/components/content/Prompt.astro +25 -25
  432. package/src/components/content/Tabs.astro +3 -1
  433. package/src/components/content/Tile.astro +2 -3
  434. package/src/components/content/Tooltip.astro +57 -9
  435. package/src/components/content/content-strings.ts +34 -0
  436. package/src/components/content/diff.ts +1 -1
  437. package/src/components/content/mermaid-element.ts +13 -2
  438. package/src/components/content/prompt-markdown.ts +292 -0
  439. package/src/components/content/tooltip-id.ts +41 -0
  440. package/src/components/copy-feedback.ts +1 -1
  441. package/src/components/islands/{AskAI.astro → Assistant.astro} +10 -10
  442. package/src/components/islands/{ask-ai.tsx → assistant.tsx} +23 -23
  443. package/src/components/islands/hooks.ts +36 -11
  444. package/src/components/layout/Analytics.astro +21 -79
  445. package/src/components/layout/Banner.astro +3 -1
  446. package/src/components/layout/DiscoveryLinks.astro +69 -0
  447. package/src/components/layout/Header.astro +93 -30
  448. package/src/components/layout/LanguageSwitcher.astro +4 -1
  449. package/src/components/layout/Logo.astro +23 -2
  450. package/src/components/layout/NavSelector.astro +13 -2
  451. package/src/components/layout/NavTree.astro +12 -3
  452. package/src/components/layout/NavTreeScript.astro +17 -3
  453. package/src/components/layout/PageActions.astro +3 -3
  454. package/src/components/layout/PageFeedback.astro +11 -1
  455. package/src/components/layout/PageLayout.astro +58 -11
  456. package/src/components/layout/Pagination.astro +7 -7
  457. package/src/components/layout/ReferenceLayout.astro +22 -13
  458. package/src/components/layout/RootLayout.astro +75 -72
  459. package/src/components/layout/Search.astro +43 -19
  460. package/src/components/layout/WebMcp.astro +1 -1
  461. package/src/components/layout/analytics-client.ts +73 -16
  462. package/src/components/layout/drawer-inert.ts +113 -15
  463. package/src/components/layout/dropdown-clamp.ts +105 -0
  464. package/src/components/layout/head-scripts.ts +15 -6
  465. package/src/components/layout/nav-utils.ts +17 -0
  466. package/src/components/layout/search/algolia.ts +8 -8
  467. package/src/components/layout/search/orama-cloud.ts +9 -7
  468. package/src/components/layout/search/typesense.ts +11 -17
  469. package/src/components/openapi/MessageComposer.astro +2 -2
  470. package/src/components/openapi/Playground.astro +2 -2
  471. package/src/components/openapi/description.ts +2 -2
  472. package/src/components/openapi/playground-client.ts +79 -10
  473. package/src/core/changelog-index.ts +24 -0
  474. package/src/core/code-fences.ts +1 -1
  475. package/src/core/component-overrides.ts +399 -154
  476. package/src/core/config-input.ts +201 -566
  477. package/src/core/config.ts +131 -42
  478. package/src/core/custom-pages.ts +105 -0
  479. package/src/core/data.ts +34 -15
  480. package/src/core/define-components.ts +12 -9
  481. package/src/core/deployment-env.ts +18 -74
  482. package/src/core/diagnostics.ts +14 -7
  483. package/src/core/graph.ts +69 -25
  484. package/src/core/i18n-ui.ts +41 -11
  485. package/src/core/i18n.ts +17 -0
  486. package/src/core/includes.ts +156 -38
  487. package/src/core/last-modified.ts +6 -11
  488. package/src/core/links.ts +166 -2
  489. package/src/core/manifest.ts +10 -3
  490. package/src/core/navigation.ts +115 -16
  491. package/src/core/new-tab.ts +35 -0
  492. package/src/core/node-require.ts +21 -0
  493. package/src/core/project-graph.ts +42 -26
  494. package/src/core/project.ts +9 -4
  495. package/src/core/request-body.ts +61 -0
  496. package/src/core/safe-href.ts +28 -0
  497. package/src/core/safe-links.ts +68 -0
  498. package/src/core/schema.ts +528 -745
  499. package/src/core/server-features.ts +10 -11
  500. package/src/core/sources/assets.ts +47 -11
  501. package/src/core/sources/collection.ts +67 -0
  502. package/src/core/sources/contentful-rich-text.ts +285 -0
  503. package/src/core/sources/contentful.ts +173 -0
  504. package/src/core/sources/github-releases.ts +51 -1
  505. package/src/core/sources/json.ts +71 -0
  506. package/src/core/sources/lexical.ts +195 -0
  507. package/src/core/sources/lower.ts +226 -0
  508. package/src/core/sources/normalize.ts +52 -2
  509. package/src/core/sources/notion.ts +39 -28
  510. package/src/core/sources/payload.ts +135 -0
  511. package/src/core/sources/portable-text.ts +11 -16
  512. package/src/core/sources/remote.ts +226 -0
  513. package/src/core/sources/resolve.ts +104 -166
  514. package/src/core/sources/sanity.ts +16 -49
  515. package/src/core/sources/strapi-blocks.ts +124 -0
  516. package/src/core/sources/strapi.ts +191 -0
  517. package/src/core/sources/types.ts +12 -1
  518. package/src/core/types.ts +15 -1
  519. package/src/core/ui-packs/ar.ts +10 -7
  520. package/src/core/ui-packs/bg.ts +10 -7
  521. package/src/core/ui-packs/bn.ts +10 -7
  522. package/src/core/ui-packs/ca.ts +7 -6
  523. package/src/core/ui-packs/cs.ts +10 -7
  524. package/src/core/ui-packs/da.ts +10 -7
  525. package/src/core/ui-packs/de.ts +10 -7
  526. package/src/core/ui-packs/el.ts +7 -6
  527. package/src/core/ui-packs/es.ts +7 -6
  528. package/src/core/ui-packs/fa.ts +10 -7
  529. package/src/core/ui-packs/fi.ts +10 -7
  530. package/src/core/ui-packs/fr.ts +7 -6
  531. package/src/core/ui-packs/he.ts +10 -7
  532. package/src/core/ui-packs/hi.ts +10 -7
  533. package/src/core/ui-packs/hr.ts +10 -7
  534. package/src/core/ui-packs/hu.ts +10 -7
  535. package/src/core/ui-packs/id.ts +10 -7
  536. package/src/core/ui-packs/it.ts +7 -6
  537. package/src/core/ui-packs/ja.ts +7 -6
  538. package/src/core/ui-packs/ko.ts +7 -6
  539. package/src/core/ui-packs/nl.ts +10 -7
  540. package/src/core/ui-packs/no.ts +10 -7
  541. package/src/core/ui-packs/pl.ts +10 -7
  542. package/src/core/ui-packs/pt-br.ts +7 -6
  543. package/src/core/ui-packs/pt.ts +7 -6
  544. package/src/core/ui-packs/ro.ts +10 -7
  545. package/src/core/ui-packs/ru.ts +10 -7
  546. package/src/core/ui-packs/sk.ts +10 -7
  547. package/src/core/ui-packs/sr.ts +10 -7
  548. package/src/core/ui-packs/sv.ts +10 -7
  549. package/src/core/ui-packs/th.ts +7 -6
  550. package/src/core/ui-packs/tr.ts +10 -7
  551. package/src/core/ui-packs/uk.ts +10 -7
  552. package/src/core/ui-packs/vi.ts +7 -6
  553. package/src/core/ui-packs/zh-tw.ts +7 -6
  554. package/src/core/ui-packs/zh.ts +7 -6
  555. package/src/core/unrecognized-keys.ts +10 -0
  556. package/src/core/version-cut.ts +116 -8
  557. package/src/deploy/adapter-output.ts +57 -97
  558. package/src/deploy/adapters/cloudflare.ts +39 -0
  559. package/src/deploy/adapters/index.ts +41 -0
  560. package/src/deploy/adapters/netlify.ts +34 -0
  561. package/src/deploy/adapters/node.ts +34 -0
  562. package/src/deploy/adapters/registry.ts +127 -0
  563. package/src/deploy/adapters/types.ts +92 -0
  564. package/src/deploy/adapters/vercel.ts +35 -0
  565. package/src/deploy/artifacts.ts +55 -27
  566. package/src/deploy/cloudflare-negotiation.ts +179 -100
  567. package/src/deploy/function-bundle.ts +18 -3
  568. package/src/deploy/headers.ts +124 -23
  569. package/src/deploy/node-headers.ts +198 -0
  570. package/src/deploy/platforms/cloudflare.ts +312 -0
  571. package/src/deploy/platforms/index.ts +67 -0
  572. package/src/deploy/platforms/netlify.ts +52 -0
  573. package/src/deploy/platforms/node.ts +40 -0
  574. package/src/deploy/platforms/paths.ts +42 -0
  575. package/src/deploy/platforms/static.ts +29 -0
  576. package/src/deploy/platforms/types.ts +112 -0
  577. package/src/deploy/platforms/vercel.ts +193 -0
  578. package/src/deploy/redirects.ts +30 -18
  579. package/src/deploy/robots.ts +3 -3
  580. package/src/deploy/rss.ts +2 -2
  581. package/src/deploy/sitemap.ts +2 -2
  582. package/src/deploy/vercel-negotiation.ts +2 -2
  583. package/src/eval/agents.ts +32 -1
  584. package/src/eval/findings.ts +19 -11
  585. package/src/eval/report.ts +10 -2
  586. package/src/markdown/external-links.ts +65 -0
  587. package/src/markdown/include.ts +45 -27
  588. package/src/markdown/index.ts +34 -9
  589. package/src/markdown/inline-code.ts +12 -6
  590. package/src/markdown/relative-links.ts +324 -0
  591. package/src/markdown/themes.ts +3 -3
  592. package/src/migrate/migrate.ts +149 -0
  593. package/src/openapi/parse.ts +64 -16
  594. package/src/openapi/proxy.ts +62 -10
  595. package/src/openapi/references.ts +147 -147
  596. package/src/openapi/render-mdx.ts +32 -10
  597. package/src/openapi/scalar.ts +15 -13
  598. package/src/openapi/sentence.ts +14 -0
  599. package/src/openapi/source.ts +37 -21
  600. package/src/openapi/spec-dependency-error.ts +15 -0
  601. package/src/reference/asyncapi.ts +83 -0
  602. package/src/reference/graphql.ts +89 -0
  603. package/src/reference/index.ts +40 -0
  604. package/src/reference/openapi.ts +83 -0
  605. package/src/reference/options.ts +201 -0
  606. package/src/reference/scalar.ts +136 -0
  607. package/src/reference/schema.ts +88 -0
  608. package/src/registry/eject.ts +109 -53
  609. package/src/search/adapters/algolia.ts +46 -0
  610. package/src/search/adapters/flexsearch.ts +29 -0
  611. package/src/search/adapters/index.ts +39 -0
  612. package/src/search/adapters/mixedbread.ts +39 -0
  613. package/src/search/adapters/orama-cloud.ts +51 -0
  614. package/src/search/adapters/orama.ts +24 -0
  615. package/src/search/adapters/pagefind.ts +27 -0
  616. package/src/search/adapters/registry.ts +131 -0
  617. package/src/search/adapters/types.ts +46 -0
  618. package/src/search/adapters/typesense.ts +57 -0
  619. package/src/search/build.ts +8 -4
  620. package/src/search/documents.ts +8 -2
  621. package/src/search/orama-index.ts +1 -1
  622. package/src/search/sync/algolia.ts +12 -11
  623. package/src/search/sync/index.ts +35 -20
  624. package/src/search/sync/orama-cloud.ts +12 -9
  625. package/src/search/sync/typesense.ts +15 -13
  626. package/src/sources/contentful.ts +63 -0
  627. package/src/sources/custom.ts +38 -0
  628. package/src/sources/filesystem.ts +51 -0
  629. package/src/sources/github-releases.ts +52 -0
  630. package/src/sources/index.ts +60 -0
  631. package/src/sources/mdx-remote.ts +76 -0
  632. package/src/sources/notion.ts +63 -0
  633. package/src/sources/obsidian.ts +38 -0
  634. package/src/sources/payload.ts +60 -0
  635. package/src/sources/registry.ts +182 -0
  636. package/src/sources/sanity.ts +66 -0
  637. package/src/sources/shared.ts +52 -0
  638. package/src/sources/strapi.ts +58 -0
  639. package/src/theme/entry.ts +24 -2
  640. package/src/translate/report.ts +40 -7
  641. package/src/upgrade/upgrade.ts +499 -0
  642. package/dist/cli/chunk-0qymqwzz.js +0 -164
  643. package/dist/cli/chunk-0qymqwzz.js.map +0 -15
  644. package/dist/cli/chunk-1jefwnfs.js.map +0 -48
  645. package/dist/cli/chunk-2mzebbbz.js +0 -69
  646. package/dist/cli/chunk-2z47ypj8.js.map +0 -11
  647. package/dist/cli/chunk-4x36ddpw.js.map +0 -11
  648. package/dist/cli/chunk-5093q3n7.js +0 -68
  649. package/dist/cli/chunk-5093q3n7.js.map +0 -10
  650. package/dist/cli/chunk-5qk08vmp.js.map +0 -11
  651. package/dist/cli/chunk-7s8hm3b6.js +0 -5347
  652. package/dist/cli/chunk-7s8hm3b6.js.map +0 -58
  653. package/dist/cli/chunk-8cjtbafj.js.map +0 -13
  654. package/dist/cli/chunk-97r59kpr.js +0 -381
  655. package/dist/cli/chunk-97r59kpr.js.map +0 -12
  656. package/dist/cli/chunk-ahnw3kxw.js.map +0 -15
  657. package/dist/cli/chunk-b27xqwn9.js.map +0 -10
  658. package/dist/cli/chunk-bf6bt1xt.js +0 -185
  659. package/dist/cli/chunk-bf6bt1xt.js.map +0 -11
  660. package/dist/cli/chunk-cjtn640a.js.map +0 -10
  661. package/dist/cli/chunk-ct47dqpx.js.map +0 -11
  662. package/dist/cli/chunk-esphfr8p.js +0 -107
  663. package/dist/cli/chunk-esphfr8p.js.map +0 -11
  664. package/dist/cli/chunk-ex56aa81.js +0 -1016
  665. package/dist/cli/chunk-ex56aa81.js.map +0 -13
  666. package/dist/cli/chunk-garjf5z9.js +0 -30
  667. package/dist/cli/chunk-garjf5z9.js.map +0 -10
  668. package/dist/cli/chunk-js7saxwm.js +0 -1045
  669. package/dist/cli/chunk-js7saxwm.js.map +0 -22
  670. package/dist/cli/chunk-k79xp7av.js.map +0 -39
  671. package/dist/cli/chunk-ps4m1xh4.js.map +0 -15
  672. package/dist/cli/chunk-q4rae3bg.js +0 -60
  673. package/dist/cli/chunk-q4rae3bg.js.map +0 -10
  674. package/dist/cli/chunk-rz9jmfhz.js +0 -108
  675. package/dist/cli/chunk-rz9jmfhz.js.map +0 -10
  676. package/dist/cli/chunk-vh9w1sgp.js +0 -73
  677. package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
  678. package/dist/cli/chunk-vrfp10qk.js +0 -81
  679. package/dist/cli/chunk-vrfp10qk.js.map +0 -10
  680. package/dist/cli/chunk-yg63d42r.js.map +0 -34
  681. package/docs/advanced/api-reference.mdx +0 -240
  682. package/docs/configuration/ask-ai.mdx +0 -256
  683. package/docs/reference/cli.mdx +0 -197
  684. package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
  685. package/src/components/content/changelog-element.ts +0 -69
  686. package/src/search/providers.ts +0 -91
  687. /package/dist/cli/{chunk-vacwm2hv.js.map → chunk-27g6wdth.js.map} +0 -0
  688. /package/dist/cli/{chunk-dwgcp5sm.js.map → chunk-ce574jw2.js.map} +0 -0
  689. /package/dist/cli/{chunk-e7f42gdj.js.map → chunk-fxypxtvm.js.map} +0 -0
  690. /package/dist/cli/{chunk-nn13znc2.js.map → chunk-zxcczpyx.js.map} +0 -0
package/src/ai/ask.ts CHANGED
@@ -1,134 +1,671 @@
1
- import type { AskAiConfig } from "../core/schema.ts";
1
+ import { z } from "zod";
2
+
3
+ import type { AdapterDescriptor, JsonValue } from "../core/adapter.ts";
4
+ import { adapterDescriptorSchema } from "../core/adapter.ts";
5
+ import { unrecognizedKeysMessage } from "../core/unrecognized-keys.ts";
2
6
 
3
7
  /**
4
- * The concrete backend the Ask AI endpoint is generated against. `gateway` uses
5
- * the AI SDK core (`streamText({ model })`) and the Vercel AI Gateway;
6
- * `openrouter` uses its dedicated provider; everything else streams through the
7
- * AI SDK's OpenAI-compatible provider.
8
+ * The `reasoning` levels the adapters accept: the AI SDK's top-level
9
+ * `reasoning` values minus `provider-default`, which is what omitting the
10
+ * option means.
8
11
  */
9
- export type AskBackend =
10
- | { headers?: AskHeaders; kind: "gateway"; model: string }
11
- | {
12
- apiKeyEnv: string;
13
- headers?: AskHeaders;
14
- kind: "openrouter";
15
- model: string;
16
- }
17
- | {
18
- apiKeyEnv: string;
19
- baseUrl: string;
20
- headers?: AskHeaders;
21
- kind: "openai-compatible";
22
- model: string;
23
- name: string;
24
- };
12
+ export const assistantReasoningLevels = [
13
+ "none",
14
+ "minimal",
15
+ "low",
16
+ "medium",
17
+ "high",
18
+ "xhigh",
19
+ ] as const;
20
+
21
+ /** How much the model reasons before answering (an adapter's `reasoning`). */
22
+ export type AssistantReasoning = (typeof assistantReasoningLevels)[number];
25
23
 
26
24
  /**
27
- * Static request headers (`ai.ask.headers`) every backend forwards to its
28
- * provider factory. Every provider Blume generates against accepts the same
29
- * `headers` option, so the map travels unchanged; the OpenAI-compatible
30
- * provider applies them after the `Authorization` header it derives from the
31
- * API key, so a custom header can't displace auth.
25
+ * The AI SDK's `providerOptions` shape, forwarded to `streamText` verbatim:
26
+ * `{ [provider]: { [option]: value } }`. The escape hatch for model controls
27
+ * Blume doesn't name, so a new provider knob never needs a Blume field.
32
28
  */
33
- export type AskHeaders = Record<string, string>;
29
+ export type AssistantProviderOptions = Record<
30
+ string,
31
+ Record<string, JsonValue>
32
+ >;
34
33
 
35
- interface AskPreset {
36
- apiKeyEnv: string;
34
+ /** The AI SDK provider package the OpenAI-compatible adapters install. */
35
+ const OPENAI_COMPATIBLE_DEP = "@ai-sdk/openai-compatible";
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Shared options
39
+ // ---------------------------------------------------------------------------
40
+
41
+ /** The options every assistant adapter accepts. */
42
+ export interface AssistantAdapterOptions {
43
+ /**
44
+ * Name of the env var holding the provider's API key. Each adapter has its
45
+ * own default; set this only to point at a different variable.
46
+ */
47
+ apiKeyEnv?: string;
48
+ /**
49
+ * Static request headers sent to the provider on every call — a
50
+ * caller-identifying header for a shared backend, for example. Values are
51
+ * written into the generated route as literals, so keep secrets in
52
+ * `apiKeyEnv` rather than here.
53
+ */
54
+ headers?: Record<string, string>;
55
+ /**
56
+ * Options passed to `streamText` as its `providerOptions`, untouched, in the
57
+ * AI SDK's own shape (`{ openai: { textVerbosity: "low" } }`, say).
58
+ */
59
+ providerOptions?: AssistantProviderOptions;
60
+ }
61
+
62
+ /**
63
+ * `providerOptions`, forwarded to `streamText` verbatim. JSON-only, because
64
+ * the generated and ejected routes inline it as a literal.
65
+ */
66
+ const providerOptionsSchema = z.record(
67
+ z.string(),
68
+ z.record(z.string(), z.json())
69
+ );
70
+
71
+ /** The shared option schema, with the adapter's own key env var default. */
72
+ const sharedOptions = (apiKeyEnv: string) => ({
73
+ apiKeyEnv: z.string().min(1).default(apiKeyEnv),
74
+ headers: z.record(z.string(), z.string()).optional(),
75
+ providerOptions: providerOptionsSchema.optional(),
76
+ });
77
+
78
+ const reasoningOption = z.enum(assistantReasoningLevels).optional();
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // gateway()
82
+ // ---------------------------------------------------------------------------
83
+
84
+ const GATEWAY_API_KEY_ENV = "AI_GATEWAY_API_KEY";
85
+ /** The model the gateway adapter uses when none is configured. */
86
+ const DEFAULT_GATEWAY_MODEL = "openai/gpt-5.5";
87
+
88
+ /** Options for {@link gateway}. */
89
+ export interface AssistantGatewayOptions extends AssistantAdapterOptions {
90
+ /** A `provider/model` id routed by the gateway. Defaults to `openai/gpt-5.5`. */
91
+ model?: string;
92
+ /**
93
+ * How much the model reasons before answering. Sent as the AI SDK's
94
+ * top-level `reasoning` option, which the gateway maps to the model's own
95
+ * control (OpenAI's `reasoning_effort`, for example); the model has to
96
+ * offer the level you pick. Omitted keeps the model's default.
97
+ */
98
+ reasoning?: AssistantReasoning;
99
+ }
100
+
101
+ const gatewayOptionsSchema = z.strictObject({
102
+ ...sharedOptions(GATEWAY_API_KEY_ENV),
103
+ model: z.string().min(1).default(DEFAULT_GATEWAY_MODEL),
104
+ reasoning: reasoningOption,
105
+ });
106
+
107
+ export type AssistantGatewayAdapter = AdapterDescriptor<
108
+ "gateway",
109
+ AssistantGatewayOptions
110
+ >;
111
+
112
+ export const gatewayAdapterSchema = adapterDescriptorSchema(
113
+ "gateway",
114
+ gatewayOptionsSchema
115
+ );
116
+
117
+ /**
118
+ * Route the assistant through the Vercel AI Gateway (the default). `model` is a
119
+ * `provider/model` string; the key is `AI_GATEWAY_API_KEY`, or Vercel's OIDC
120
+ * token when deployed there. Needs no provider SDK beyond the `ai` package
121
+ * Blume ships.
122
+ */
123
+ export const gateway = (
124
+ options: AssistantGatewayOptions = {}
125
+ ): AssistantGatewayAdapter => ({
126
+ kind: "gateway",
127
+ options,
128
+ requiredSecrets: [options.apiKeyEnv ?? GATEWAY_API_KEY_ENV],
129
+ runtimeDeps: [],
130
+ });
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // openrouter()
134
+ // ---------------------------------------------------------------------------
135
+
136
+ const OPENROUTER_API_KEY_ENV = "OPENROUTER_API_KEY";
137
+
138
+ /** Options for {@link openrouter}. */
139
+ export interface AssistantOpenRouterOptions extends AssistantAdapterOptions {
140
+ /** The OpenRouter model id (`anthropic/claude-sonnet-4-5`). */
141
+ model: string;
142
+ /**
143
+ * How much the model reasons before answering. Set on the model as
144
+ * OpenRouter's `reasoning.effort`, because its provider ignores the AI
145
+ * SDK's call-level option. Omitted keeps the model's default.
146
+ */
147
+ reasoning?: AssistantReasoning;
148
+ }
149
+
150
+ const openrouterOptionsSchema = z.strictObject({
151
+ ...sharedOptions(OPENROUTER_API_KEY_ENV),
152
+ model: z.string().min(1),
153
+ reasoning: reasoningOption,
154
+ });
155
+
156
+ export type AssistantOpenRouterAdapter = AdapterDescriptor<
157
+ "openrouter",
158
+ AssistantOpenRouterOptions
159
+ >;
160
+
161
+ export const openrouterAdapterSchema = adapterDescriptorSchema(
162
+ "openrouter",
163
+ openrouterOptionsSchema
164
+ );
165
+
166
+ /**
167
+ * Route the assistant through OpenRouter. Reads `OPENROUTER_API_KEY` and needs
168
+ * `@openrouter/ai-sdk-provider` installed in the project.
169
+ */
170
+ export const openrouter = (
171
+ options: AssistantOpenRouterOptions
172
+ ): AssistantOpenRouterAdapter => ({
173
+ kind: "openrouter",
174
+ options,
175
+ requiredSecrets: [options.apiKeyEnv ?? OPENROUTER_API_KEY_ENV],
176
+ runtimeDeps: ["@openrouter/ai-sdk-provider"],
177
+ });
178
+
179
+ // ---------------------------------------------------------------------------
180
+ // llmgateway()
181
+ // ---------------------------------------------------------------------------
182
+
183
+ const LLMGATEWAY_API_KEY_ENV = "LLMGATEWAY_API_KEY";
184
+
185
+ /** Options for {@link llmgateway}. */
186
+ export interface AssistantLlmGatewayOptions extends AssistantAdapterOptions {
187
+ /** Overrides the preset endpoint (`https://api.llmgateway.io/v1`). */
37
188
  baseUrl?: string;
38
- kind: "openai-compatible" | "openrouter";
39
- name: string;
40
- runtimeDep: string;
189
+ /** The model id LLMGateway serves. */
190
+ model: string;
191
+ /**
192
+ * How much the model reasons before answering, sent in the request as
193
+ * `reasoning_effort`. Omitted keeps the model's default.
194
+ */
195
+ reasoning?: AssistantReasoning;
41
196
  }
42
197
 
198
+ const llmgatewayOptionsSchema = z.strictObject({
199
+ ...sharedOptions(LLMGATEWAY_API_KEY_ENV),
200
+ baseUrl: z.url().default("https://api.llmgateway.io/v1"),
201
+ model: z.string().min(1),
202
+ reasoning: reasoningOption,
203
+ });
204
+
205
+ export type AssistantLlmGatewayAdapter = AdapterDescriptor<
206
+ "llmgateway",
207
+ AssistantLlmGatewayOptions
208
+ >;
209
+
210
+ export const llmgatewayAdapterSchema = adapterDescriptorSchema(
211
+ "llmgateway",
212
+ llmgatewayOptionsSchema
213
+ );
214
+
43
215
  /**
44
- * Connection presets for the named, non-gateway providers. OpenRouter has a
45
- * dedicated AI SDK provider; LLMGateway and Inkeep are OpenAI-compatible
46
- * endpoints with no dedicated provider, so they reuse `@ai-sdk/openai-compatible`.
216
+ * Route the assistant through LLMGateway's OpenAI-compatible endpoint. Reads
217
+ * `LLMGATEWAY_API_KEY` and needs `@ai-sdk/openai-compatible` installed.
47
218
  */
48
- /** The discriminant/name shared by the OpenAI-compatible providers. */
49
- const OPENAI_COMPATIBLE = "openai-compatible";
50
- /** The AI SDK provider package the OpenAI-compatible providers install. */
51
- const OPENAI_COMPATIBLE_DEP = "@ai-sdk/openai-compatible";
219
+ export const llmgateway = (
220
+ options: AssistantLlmGatewayOptions
221
+ ): AssistantLlmGatewayAdapter => ({
222
+ kind: "llmgateway",
223
+ options,
224
+ requiredSecrets: [options.apiKeyEnv ?? LLMGATEWAY_API_KEY_ENV],
225
+ runtimeDeps: [OPENAI_COMPATIBLE_DEP],
226
+ });
227
+
228
+ // ---------------------------------------------------------------------------
229
+ // inkeep()
230
+ // ---------------------------------------------------------------------------
231
+
232
+ const INKEEP_API_KEY_ENV = "INKEEP_API_KEY";
52
233
 
53
234
  /**
54
- * Connection presets keyed by provider name. Open-keyed on purpose: lookups
55
- * use the configured `ai.ask.provider`, which includes values with no preset
56
- * (the generic `openai-compatible`).
235
+ * Options for {@link inkeep}. No `reasoning`: Inkeep runs its own QA pipeline
236
+ * behind an OpenAI-compatible endpoint with no reasoning control.
57
237
  */
58
- interface AskPresetRegistry {
59
- [provider: string]: AskPreset;
238
+ export interface AssistantInkeepOptions extends AssistantAdapterOptions {
239
+ /** Overrides the preset endpoint (`https://api.inkeep.com/v1`). */
240
+ baseUrl?: string;
241
+ /** The Inkeep QA model id. */
242
+ model: string;
60
243
  }
61
244
 
62
- const ASK_PRESETS: AskPresetRegistry = {
63
- inkeep: {
64
- apiKeyEnv: "INKEEP_API_KEY",
65
- baseUrl: "https://api.inkeep.com/v1",
66
- kind: OPENAI_COMPATIBLE,
67
- name: "inkeep",
68
- runtimeDep: OPENAI_COMPATIBLE_DEP,
69
- },
70
- llmgateway: {
71
- apiKeyEnv: "LLMGATEWAY_API_KEY",
72
- baseUrl: "https://api.llmgateway.io/v1",
73
- kind: OPENAI_COMPATIBLE,
74
- name: "llmgateway",
75
- runtimeDep: OPENAI_COMPATIBLE_DEP,
76
- },
77
- openrouter: {
78
- apiKeyEnv: "OPENROUTER_API_KEY",
79
- kind: "openrouter",
80
- name: "openrouter",
81
- runtimeDep: "@openrouter/ai-sdk-provider",
245
+ const inkeepOptionsSchema = z.strictObject({
246
+ ...sharedOptions(INKEEP_API_KEY_ENV),
247
+ baseUrl: z.url().default("https://api.inkeep.com/v1"),
248
+ model: z.string().min(1),
249
+ });
250
+
251
+ export type AssistantInkeepAdapter = AdapterDescriptor<
252
+ "inkeep",
253
+ AssistantInkeepOptions
254
+ >;
255
+
256
+ export const inkeepAdapterSchema = adapterDescriptorSchema(
257
+ "inkeep",
258
+ inkeepOptionsSchema
259
+ );
260
+
261
+ /**
262
+ * Answer with Inkeep, which retrieves from the content indexed in its own
263
+ * dashboard, so Blume leaves it ungrounded and it takes no `reasoning`.
264
+ * Reads `INKEEP_API_KEY` and needs `@ai-sdk/openai-compatible` installed.
265
+ */
266
+ export const inkeep = (
267
+ options: AssistantInkeepOptions
268
+ ): AssistantInkeepAdapter => ({
269
+ kind: "inkeep",
270
+ options,
271
+ requiredSecrets: [options.apiKeyEnv ?? INKEEP_API_KEY_ENV],
272
+ runtimeDeps: [OPENAI_COMPATIBLE_DEP],
273
+ });
274
+
275
+ // ---------------------------------------------------------------------------
276
+ // openaiCompatible()
277
+ // ---------------------------------------------------------------------------
278
+
279
+ /** Options for {@link openaiCompatible}. */
280
+ export interface AssistantOpenAICompatibleOptions extends AssistantAdapterOptions {
281
+ /** Name of the env var holding the endpoint's API key. */
282
+ apiKeyEnv: string;
283
+ /** The endpoint's base URL (`https://my-gateway.example.com/v1`). */
284
+ baseUrl: string;
285
+ /** The model id the endpoint serves. */
286
+ model: string;
287
+ /** The provider name the AI SDK reports. Defaults to `openai-compatible`. */
288
+ name?: string;
289
+ /**
290
+ * How much the model reasons before answering, sent in the request as
291
+ * `reasoning_effort`, so the endpoint has to accept that parameter.
292
+ * Omitted keeps the model's default.
293
+ */
294
+ reasoning?: AssistantReasoning;
295
+ }
296
+
297
+ const openaiCompatibleOptionsSchema = z.strictObject({
298
+ ...sharedOptions("API_KEY"),
299
+ // A generic endpoint has no preset, so the caller names the key env var.
300
+ apiKeyEnv: z.string().min(1),
301
+ baseUrl: z.url(),
302
+ model: z.string().min(1),
303
+ name: z.string().min(1).default("openai-compatible"),
304
+ reasoning: reasoningOption,
305
+ });
306
+
307
+ export type AssistantOpenAICompatibleAdapter = AdapterDescriptor<
308
+ "openai-compatible",
309
+ AssistantOpenAICompatibleOptions
310
+ >;
311
+
312
+ export const openaiCompatibleAdapterSchema = adapterDescriptorSchema(
313
+ "openai-compatible",
314
+ openaiCompatibleOptionsSchema
315
+ );
316
+
317
+ /**
318
+ * Route the assistant through any OpenAI-compatible endpoint: supply its `baseUrl`,
319
+ * the `model` it serves, and the env var holding its key. Needs
320
+ * `@ai-sdk/openai-compatible` installed.
321
+ */
322
+ export const openaiCompatible = (
323
+ options: AssistantOpenAICompatibleOptions
324
+ ): AssistantOpenAICompatibleAdapter => ({
325
+ kind: "openai-compatible",
326
+ options,
327
+ requiredSecrets: [options.apiKeyEnv],
328
+ runtimeDeps: [OPENAI_COMPATIBLE_DEP],
329
+ });
330
+
331
+ // ---------------------------------------------------------------------------
332
+ // The `ai.assistant.provider` schema
333
+ // ---------------------------------------------------------------------------
334
+
335
+ /** Which backend answers the assistant: the value of `gateway()`, `openrouter()`, … */
336
+ export type AssistantAdapter =
337
+ | AssistantGatewayAdapter
338
+ | AssistantOpenRouterAdapter
339
+ | AssistantLlmGatewayAdapter
340
+ | AssistantInkeepAdapter
341
+ | AssistantOpenAICompatibleAdapter;
342
+
343
+ // ---------------------------------------------------------------------------
344
+ // Blume 1 hints
345
+ // ---------------------------------------------------------------------------
346
+
347
+ /**
348
+ * The 1.x `ai.ask.provider` names — also the adapters' `kind`s — each with the
349
+ * `blume/ai` factory that replaced it.
350
+ */
351
+ const FACTORY_BY_PROVIDER = new Map([
352
+ ["gateway", "gateway"],
353
+ ["inkeep", "inkeep"],
354
+ ["llmgateway", "llmgateway"],
355
+ ["openai-compatible", "openaiCompatible"],
356
+ ["openrouter", "openrouter"],
357
+ ]);
358
+
359
+ /** The 1.x flat `ai.ask` fields: each is now an option of the provider adapter. */
360
+ const MOVED_TO_PROVIDER: ReadonlySet<string> = new Set([
361
+ "apiKeyEnv",
362
+ "baseUrl",
363
+ "headers",
364
+ "model",
365
+ "reasoning",
366
+ ]);
367
+
368
+ /** The provider an `ai.assistant` object names: a 1.x string or a descriptor's `kind`. */
369
+ const assistantProviderNameProbe = z.looseObject({
370
+ provider: z.union([
371
+ z.string(),
372
+ z.looseObject({ kind: z.string() }).transform(({ kind }) => kind),
373
+ ]),
374
+ });
375
+
376
+ /** The factory a failing `ai.assistant` object's provider names, or the gateway. */
377
+ const providerFactory = (issue: z.core.$ZodRawIssue): string => {
378
+ const probe = assistantProviderNameProbe.safeParse(issue.input);
379
+ return (
380
+ (probe.success && FACTORY_BY_PROVIDER.get(probe.data.provider)) || "gateway"
381
+ );
382
+ };
383
+
384
+ /**
385
+ * Error params for `ai.assistant`: a 1.x flat provider field (`model`, `apiKeyEnv`,
386
+ * `baseUrl`, `headers`, `reasoning`) names the adapter call it moves into —
387
+ * the one the object's `provider` picks, 1.x string or descriptor — instead
388
+ * of Zod's bare "Unrecognized key"; any other unknown key keeps its wording.
389
+ */
390
+ export const assistantMovedFieldsHint = {
391
+ error: (issue: z.core.$ZodRawIssue): string | undefined => {
392
+ if (issue.code !== "unrecognized_keys") {
393
+ return;
394
+ }
395
+ const moved = issue.keys.filter((key) => MOVED_TO_PROVIDER.has(key));
396
+ if (moved.length === 0) {
397
+ return;
398
+ }
399
+ const fields = moved.map((key) => `ai.assistant.${key}`).join(", ");
400
+ const hint = `${fields} moved into the provider adapter: \`provider: ${providerFactory(issue)}({ ${moved.join(", ")} })\`, imported from "blume/ai".`;
401
+ const others = issue.keys.filter((key) => !MOVED_TO_PROVIDER.has(key));
402
+ return others.length > 0
403
+ ? `${hint} ${unrecognizedKeysMessage(others)}`
404
+ : hint;
82
405
  },
83
406
  };
84
407
 
85
- const DEFAULT_MODEL = "openai/gpt-5.5";
408
+ /** A value that is a 1.x provider name, for the `ai.assistant.provider` hint. */
409
+ const providerNameProbe = z.string();
86
410
 
87
411
  /**
88
- * The `headers` field every backend variant shares. An empty map is dropped so
89
- * the generated route only carries a `headers` option when there is something
90
- * to send.
412
+ * The message for an `ai.assistant.provider` that isn't a descriptor: a 1.x
413
+ * provider name names the factory that replaced it; anything else lists them.
91
414
  */
92
- const askHeadersField = (ask?: AskAiConfig): { headers?: AskHeaders } =>
93
- ask?.headers && Object.keys(ask.headers).length > 0
94
- ? { headers: ask.headers }
95
- : {};
415
+ const providerNotAdapterMessage = (issue: z.core.$ZodRawIssue): string => {
416
+ const name = providerNameProbe.safeParse(issue.input);
417
+ const factory = name.success ? FACTORY_BY_PROVIDER.get(name.data) : undefined;
418
+ return factory
419
+ ? `ai.assistant.provider takes an adapter from "blume/ai", not a provider name: \`provider: ${factory}({ model })\`. The 1.x model, apiKeyEnv, baseUrl, headers, and reasoning fields move into the call.`
420
+ : 'ai.assistant.provider takes an adapter from "blume/ai": gateway(), openrouter(), llmgateway(), inkeep(), or openaiCompatible().';
421
+ };
96
422
 
97
- /** Resolve the `ai.ask` config into the backend the endpoint is built against. */
98
- export const resolveAskBackend = (ask?: AskAiConfig): AskBackend => {
99
- const provider = ask?.provider ?? "gateway";
100
- const model = ask?.model ?? DEFAULT_MODEL;
101
- const headers = askHeadersField(ask);
102
- if (provider === "gateway") {
103
- return { ...headers, kind: "gateway", model };
423
+ /**
424
+ * `ai.assistant.provider`: the descriptor an adapter factory returned, validated
425
+ * against that adapter's own option schema. A value that isn't a descriptor
426
+ * at all (a 1.x provider name) names the factory that replaced it.
427
+ */
428
+ export const assistantAdapterSchema = z.discriminatedUnion(
429
+ "kind",
430
+ [
431
+ gatewayAdapterSchema,
432
+ openrouterAdapterSchema,
433
+ llmgatewayAdapterSchema,
434
+ inkeepAdapterSchema,
435
+ openaiCompatibleAdapterSchema,
436
+ ],
437
+ {
438
+ // A non-object (a 1.x provider name) fails before any discriminator is
439
+ // read — `invalid_type` at runtime, though Zod types the union's own
440
+ // issues as `invalid_union` only; a bad `kind` keeps Zod's message.
441
+ error: (issue) =>
442
+ issue.code === "invalid_union"
443
+ ? undefined
444
+ : providerNotAdapterMessage(issue),
104
445
  }
105
- const preset = ASK_PRESETS[provider];
106
- const apiKeyEnv = ask?.apiKeyEnv ?? preset?.apiKeyEnv ?? "API_KEY";
107
- if (provider === "openrouter") {
108
- return { apiKeyEnv, ...headers, kind: "openrouter", model };
446
+ );
447
+
448
+ /** A resolved (post-defaults) `ai.assistant.provider` descriptor. */
449
+ export type AssistantAdapterConfig = z.output<typeof assistantAdapterSchema>;
450
+ export type AssistantAdapterKind = AssistantAdapterConfig["kind"];
451
+
452
+ /** The provider when `ai.assistant.provider` is unset: the gateway with its defaults. */
453
+ export const DEFAULT_ASSISTANT_PROVIDER: AssistantAdapter = gateway();
454
+
455
+ // ---------------------------------------------------------------------------
456
+ // Resolved backend
457
+ // ---------------------------------------------------------------------------
458
+
459
+ /** The route fragments an adapter contributes to `askEndpointTemplate`. */
460
+ export interface AskBackendTemplate {
461
+ /**
462
+ * Extra `streamText` fields as `key: value` source lines: the adapter's
463
+ * reasoning mapping (when it is a call option) and `providerOptions`.
464
+ */
465
+ fields: string[];
466
+ /** Import lines after the shared `astro` and `astro:env/server` ones. */
467
+ imports: string[];
468
+ /**
469
+ * The up-front credential guard: a statement that returns a 503, since the
470
+ * endpoint exists but can't answer until the deployment sets its key.
471
+ */
472
+ keyCheck: string;
473
+ /** The `model:` expression passed to `streamText`. */
474
+ model: string;
475
+ /** Module-level provider setup (the provider factory call). */
476
+ setup: string;
477
+ }
478
+
479
+ /**
480
+ * What the endpoint template and the diagnostics read from an adapter beyond
481
+ * the descriptor itself (`kind`, `requiredSecrets`, `runtimeDeps` travel on
482
+ * the descriptor; `generate`, `eject`, the required-secrets check, and the
483
+ * runtime-dependency manifest read those directly).
484
+ */
485
+ export interface AskBackend {
486
+ /** Whether Blume grounds answers in the docs (Inkeep retrieves itself). */
487
+ grounded: boolean;
488
+ kind: AssistantAdapterKind;
489
+ /** Human-readable adapter name for diagnostics ("AI Gateway"). */
490
+ label: string;
491
+ /** Appended to the missing-secret warning (an alternative credential, say). */
492
+ secretNote?: string;
493
+ template: AskBackendTemplate;
494
+ }
495
+
496
+ const secretExpr = (env: string): string => `getSecret(${JSON.stringify(env)})`;
497
+
498
+ /**
499
+ * The `headers` line of a provider factory call. Every provider Blume
500
+ * generates against takes the same option; the OpenAI-compatible provider
501
+ * applies it after the `Authorization` header it derives from the API key, so
502
+ * a custom header can't displace auth. An empty map is dropped so the route
503
+ * only carries `headers` when there is something to send.
504
+ */
505
+ const headersLine = (headers?: Record<string, string>): string =>
506
+ headers && Object.keys(headers).length > 0
507
+ ? `\n headers: ${JSON.stringify(headers)},`
508
+ : "";
509
+
510
+ /** Refuse a request up front when the adapter's key env var is unset. */
511
+ const keyCheck = (env: string): string => ` if (!${secretExpr(env)}) {
512
+ return new Response(
513
+ ${JSON.stringify(`The assistant is not configured: set ${env}.`)},
514
+ { status: 503 }
515
+ );
516
+ }`;
517
+
518
+ /**
519
+ * The `streamText` fields shared by the adapters that take `reasoning` as the
520
+ * AI SDK's top-level call option, plus the verbatim `providerOptions`.
521
+ */
522
+ const callFields = (options: {
523
+ providerOptions?: z.output<typeof providerOptionsSchema>;
524
+ reasoning?: AssistantReasoning;
525
+ }): string[] => {
526
+ const fields: string[] = [];
527
+ if (options.reasoning) {
528
+ fields.push(`reasoning: ${JSON.stringify(options.reasoning)}`);
529
+ }
530
+ if (options.providerOptions) {
531
+ fields.push(`providerOptions: ${JSON.stringify(options.providerOptions)}`);
109
532
  }
110
- // `llmgateway`, `inkeep`, and the generic `openai-compatible` provider all
111
- // stream through the AI SDK's OpenAI-compatible provider. The schema requires
112
- // `baseUrl` for the generic case; the named providers fall back to a preset.
533
+ return fields;
534
+ };
535
+
536
+ const gatewayBackend = (
537
+ options: z.output<typeof gatewayOptionsSchema>
538
+ ): AskBackend => ({
539
+ grounded: true,
540
+ kind: "gateway",
541
+ label: "AI Gateway",
542
+ secretNote: "on Vercel the gateway can also authenticate via OIDC",
543
+ template: {
544
+ // The gateway maps the AI SDK's top-level `reasoning` to the model's own
545
+ // control (OpenAI's `reasoning_effort`, say).
546
+ fields: callFields(options),
547
+ // The gateway provider reads the key (or Vercel's OIDC token) from the
548
+ // environment itself; passing the key explicitly lets a binding-backed
549
+ // secret store reach it too.
550
+ imports: [
551
+ 'import { createGateway, createTextStreamResponse, streamText, toTextStream } from "ai";',
552
+ ],
553
+ keyCheck: ` // The AI Gateway authenticates with an API key or Vercel's OIDC token.
554
+ if (!(${secretExpr(options.apiKeyEnv)} || getSecret("VERCEL_OIDC_TOKEN"))) {
555
+ return new Response(
556
+ ${JSON.stringify(`The assistant is not configured: set ${options.apiKeyEnv} (or deploy on Vercel with OIDC).`)},
557
+ { status: 503 }
558
+ );
559
+ }`,
560
+ model: `gateway(${JSON.stringify(options.model)})`,
561
+ setup: `\nconst gateway = createGateway({
562
+ apiKey: ${secretExpr(options.apiKeyEnv)},${headersLine(options.headers)}
563
+ });\n`,
564
+ },
565
+ });
566
+
567
+ const openrouterBackend = (
568
+ options: z.output<typeof openrouterOptionsSchema>
569
+ ): AskBackend => {
570
+ // The OpenRouter provider ignores the AI SDK's top-level `reasoning` call
571
+ // option and only reads its own model-level setting, so the level rides on
572
+ // the model as `reasoning.effort` and nowhere else.
573
+ const settings = options.reasoning
574
+ ? `, { reasoning: { effort: ${JSON.stringify(options.reasoning)} } }`
575
+ : "";
113
576
  return {
114
- apiKeyEnv,
115
- baseUrl: ask?.baseUrl ?? preset?.baseUrl ?? "",
116
- ...headers,
117
- kind: OPENAI_COMPATIBLE,
118
- model,
119
- name: preset?.name ?? OPENAI_COMPATIBLE,
577
+ grounded: true,
578
+ kind: "openrouter",
579
+ label: "OpenRouter",
580
+ template: {
581
+ fields: callFields({ providerOptions: options.providerOptions }),
582
+ imports: [
583
+ 'import { createTextStreamResponse, streamText, toTextStream } from "ai";',
584
+ 'import { createOpenRouter } from "@openrouter/ai-sdk-provider";',
585
+ ],
586
+ keyCheck: keyCheck(options.apiKeyEnv),
587
+ model: `openrouter(${JSON.stringify(options.model)}${settings})`,
588
+ setup: `\nconst openrouter = createOpenRouter({
589
+ apiKey: ${secretExpr(options.apiKeyEnv)},${headersLine(options.headers)}
590
+ });\n`,
591
+ },
120
592
  };
121
593
  };
122
594
 
123
595
  /**
124
- * The provider SDK a project must install for the configured backend, or
125
- * `undefined` for `gateway` (which only needs the core `ai` package). Declared
126
- * in the generated runtime so a project pulls in exactly the backend it uses.
596
+ * The backend shared by the adapters that stream through the AI SDK's
597
+ * OpenAI-compatible provider, which sends the top-level `reasoning` call
598
+ * option as `reasoning_effort`.
127
599
  */
128
- export const askBackendRuntimeDep = (ask?: AskAiConfig): string | undefined => {
129
- const provider = ask?.provider ?? "gateway";
130
- if (provider === "gateway") {
131
- return undefined;
600
+ const openaiCompatibleBackend = (
601
+ kind: AssistantAdapterKind,
602
+ label: string,
603
+ grounded: boolean,
604
+ options: {
605
+ apiKeyEnv: string;
606
+ baseUrl: string;
607
+ headers?: Record<string, string>;
608
+ model: string;
609
+ name: string;
610
+ providerOptions?: z.output<typeof providerOptionsSchema>;
611
+ reasoning?: AssistantReasoning;
612
+ }
613
+ ): AskBackend => ({
614
+ grounded,
615
+ kind,
616
+ label,
617
+ template: {
618
+ fields: callFields(options),
619
+ imports: [
620
+ 'import { createTextStreamResponse, streamText, toTextStream } from "ai";',
621
+ 'import { createOpenAICompatible } from "@ai-sdk/openai-compatible";',
622
+ ],
623
+ keyCheck: keyCheck(options.apiKeyEnv),
624
+ model: `provider(${JSON.stringify(options.model)})`,
625
+ // `headers` sits between the key and the name so the API key's
626
+ // `Authorization` header is applied first.
627
+ setup: `\nconst provider = createOpenAICompatible({
628
+ apiKey: ${secretExpr(options.apiKeyEnv)},
629
+ baseURL: ${JSON.stringify(options.baseUrl)},${headersLine(options.headers)}
630
+ name: ${JSON.stringify(options.name)},
631
+ });\n`,
632
+ },
633
+ });
634
+
635
+ /** Resolve a parsed `ai.assistant.provider` descriptor into its backend. */
636
+ export const resolveAskBackend = (
637
+ provider: AssistantAdapterConfig = assistantAdapterSchema.parse(
638
+ DEFAULT_ASSISTANT_PROVIDER
639
+ )
640
+ ): AskBackend => {
641
+ switch (provider.kind) {
642
+ case "gateway": {
643
+ return gatewayBackend(provider.options);
644
+ }
645
+ case "openrouter": {
646
+ return openrouterBackend(provider.options);
647
+ }
648
+ case "llmgateway": {
649
+ return openaiCompatibleBackend("llmgateway", "LLMGateway", true, {
650
+ ...provider.options,
651
+ name: "llmgateway",
652
+ });
653
+ }
654
+ case "inkeep": {
655
+ // Inkeep answers from the content indexed in its dashboard, so injected
656
+ // excerpts would conflict with its own retrieval.
657
+ return openaiCompatibleBackend("inkeep", "Inkeep", false, {
658
+ ...provider.options,
659
+ name: "inkeep",
660
+ });
661
+ }
662
+ default: {
663
+ return openaiCompatibleBackend(
664
+ "openai-compatible",
665
+ "OpenAI-compatible",
666
+ true,
667
+ provider.options
668
+ );
669
+ }
132
670
  }
133
- return ASK_PRESETS[provider]?.runtimeDep ?? OPENAI_COMPATIBLE_DEP;
134
671
  };