blume 1.7.3 → 2.0.0

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