blume 2.0.0 → 2.0.2
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.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +110 -0
- package/README.md +2 -2
- package/dist/cli/{chunk-f2972sbt.js → chunk-00gs3wqs.js} +1 -1
- package/dist/cli/{chunk-fa25z98p.js → chunk-273ygyr4.js} +4 -3
- package/dist/cli/chunk-273ygyr4.js.map +11 -0
- package/dist/cli/{chunk-pat2zzwc.js → chunk-3yce002v.js} +21 -8
- package/dist/cli/{chunk-pat2zzwc.js.map → chunk-3yce002v.js.map} +4 -4
- package/dist/cli/{chunk-d1tadaw7.js → chunk-4e9b9ra6.js} +17 -7
- package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
- package/dist/cli/{chunk-zg2gtj10.js → chunk-5r8g91qn.js} +352 -676
- package/dist/cli/chunk-5r8g91qn.js.map +34 -0
- package/dist/cli/{chunk-11j0384y.js → chunk-6dtt0zfn.js} +14 -14
- package/dist/cli/{chunk-11j0384y.js.map → chunk-6dtt0zfn.js.map} +3 -3
- package/dist/cli/{chunk-bw22s759.js → chunk-6k4ftwze.js} +38 -19
- package/dist/cli/{chunk-bw22s759.js.map → chunk-6k4ftwze.js.map} +4 -4
- package/dist/cli/{chunk-sqn5t4q0.js → chunk-7mbqtmgb.js} +16 -7
- package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
- package/dist/cli/{chunk-79njf86q.js → chunk-7vtckvaw.js} +21 -19
- package/dist/cli/chunk-7vtckvaw.js.map +11 -0
- package/dist/cli/{chunk-fh5hj5jt.js → chunk-8g8ytmgx.js} +17 -18
- package/dist/cli/{chunk-fh5hj5jt.js.map → chunk-8g8ytmgx.js.map} +2 -2
- package/dist/cli/{chunk-1w8dp3qb.js → chunk-91ws1n6j.js} +18 -15
- package/dist/cli/chunk-91ws1n6j.js.map +10 -0
- package/dist/cli/{chunk-7ez8ny0t.js → chunk-bbnwccaz.js} +2 -2
- package/dist/cli/{chunk-5a2z0198.js → chunk-bfwp9vp6.js} +18 -10
- package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
- package/dist/cli/{chunk-ernrthtr.js → chunk-d1v5rhy0.js} +14 -15
- package/dist/cli/{chunk-ernrthtr.js.map → chunk-d1v5rhy0.js.map} +2 -2
- package/dist/cli/{chunk-a9kptbw5.js → chunk-ddndchfr.js} +21 -6
- package/dist/cli/chunk-ddndchfr.js.map +14 -0
- package/dist/cli/{chunk-zxccj738.js → chunk-esh98wmb.js} +1 -1
- package/dist/cli/{chunk-88cpgt6h.js → chunk-fsmrqk8a.js} +1 -1
- package/dist/cli/{chunk-b5aj94ah.js → chunk-g698a744.js} +5 -5
- package/dist/cli/{chunk-jts8mvcz.js → chunk-gs7r695n.js} +9 -3
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-gs7r695n.js.map} +3 -3
- package/dist/cli/{chunk-41za066z.js → chunk-h2ez8dzb.js} +4 -4
- package/dist/cli/{chunk-by2290sx.js → chunk-h7k3nq3v.js} +2 -2
- package/dist/cli/{chunk-j8mw0za6.js → chunk-hqp2ajnh.js} +252 -123
- package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
- package/dist/cli/{chunk-mnqj32sj.js → chunk-hr8ne106.js} +119 -50
- package/dist/cli/chunk-hr8ne106.js.map +13 -0
- package/dist/cli/{chunk-mwt1k8n7.js → chunk-j85scx15.js} +74 -30
- package/dist/cli/chunk-j85scx15.js.map +10 -0
- package/dist/cli/{chunk-z01ze5c1.js → chunk-k7pj68a8.js} +63 -22
- package/dist/cli/chunk-k7pj68a8.js.map +11 -0
- package/dist/cli/{chunk-2q1dwty4.js → chunk-mqc662a6.js} +8 -8
- package/dist/cli/{chunk-2q1dwty4.js.map → chunk-mqc662a6.js.map} +4 -4
- package/dist/cli/{chunk-y3e45rc8.js → chunk-n1yg3tj3.js} +4 -4
- package/dist/cli/{chunk-bctazmbk.js → chunk-nfcyttvj.js} +17 -6
- package/dist/cli/chunk-nfcyttvj.js.map +10 -0
- package/dist/cli/{chunk-6k8vp3ta.js → chunk-pbg5a4s3.js} +60 -28
- package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
- package/dist/cli/{chunk-d80hr03s.js → chunk-ppzjqwx2.js} +24 -17
- package/dist/cli/{chunk-d80hr03s.js.map → chunk-ppzjqwx2.js.map} +4 -4
- package/dist/cli/{chunk-beat36xx.js → chunk-qkb5a8sa.js} +25 -10
- package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
- package/dist/cli/{chunk-bnbmcwfb.js → chunk-sqw4ekg1.js} +5 -5
- package/dist/cli/{chunk-bnbmcwfb.js.map → chunk-sqw4ekg1.js.map} +3 -3
- package/dist/cli/{chunk-xaz13gwg.js → chunk-v6ya5kcb.js} +3268 -1150
- package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
- package/dist/cli/{chunk-tzne8qfq.js → chunk-w4bxdvsa.js} +18 -15
- package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
- package/dist/cli/{chunk-f7t03s3g.js → chunk-wdrt2k2v.js} +2 -2
- package/dist/cli/{chunk-z1f5arsg.js → chunk-xh43dwgw.js} +170 -55
- package/dist/cli/chunk-xh43dwgw.js.map +36 -0
- package/dist/cli/{chunk-pnnvybbk.js → chunk-zp79m0ts.js} +5 -5
- package/dist/cli/{chunk-pnnvybbk.js.map → chunk-zp79m0ts.js.map} +2 -2
- package/dist/cli/index.js +160 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-readability.d.ts +1 -1
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api/paths.d.ts +1 -1
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +14 -7
- package/dist/types/ai/ask.d.ts +43 -43
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/index.d.ts +3 -3
- package/dist/types/ai/openapi-components.d.ts +1 -1
- package/dist/types/ai/relative-links.d.ts +9 -4
- package/dist/types/ai/serializers.d.ts +1 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/visibility.d.ts +1 -1
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- package/dist/types/cli/env.d.ts +5 -0
- package/dist/types/cli/init/scaffold.d.ts +19 -3
- package/dist/types/cli/init/starter-spec.d.ts +11 -0
- package/dist/types/core/base-path.d.ts +9 -0
- package/dist/types/core/config-input.d.ts +21 -21
- package/dist/types/core/config.d.ts +5 -5
- package/dist/types/core/data.d.ts +3 -3
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/i18n-ui.d.ts +37 -8
- package/dist/types/core/i18n.d.ts +7 -1
- package/dist/types/core/links.d.ts +3 -1
- package/dist/types/core/load-module.d.ts +10 -0
- package/dist/types/core/locale-links.d.ts +12 -2
- package/dist/types/core/meta.d.ts +5 -1
- package/dist/types/core/nav-diagnostics.d.ts +10 -0
- package/dist/types/core/navigation.d.ts +38 -0
- package/dist/types/core/ordering-prefix.d.ts +4 -0
- package/dist/types/core/safe-links.d.ts +3 -1
- package/dist/types/core/schema.d.ts +57 -18
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +14 -2
- package/dist/types/core/sources/normalize.d.ts +10 -1
- package/dist/types/core/sources/remote.d.ts +11 -1
- package/dist/types/core/sources/resolve.d.ts +12 -0
- package/dist/types/core/sources/types.d.ts +31 -0
- package/dist/types/core/types.d.ts +9 -0
- package/dist/types/core/unrecognized-keys.d.ts +1 -1
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +31 -7
- package/dist/types/deploy/node-headers.d.ts +43 -8
- package/dist/types/deploy/platforms/netlify.d.ts +27 -2
- package/dist/types/deploy/platforms/node.d.ts +6 -5
- package/dist/types/deploy/platforms/types.d.ts +7 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +7 -2
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/documents.d.ts +1 -1
- package/dist/types/search/orama-index.d.ts +1 -1
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +21 -12
- package/docs/03-upgrading.mdx +22 -9
- package/docs/04-migrating.mdx +4 -4
- package/docs/08-faq.mdx +12 -5
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +5 -3
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +5 -5
- package/docs/cli/doctor.mdx +4 -4
- package/docs/cli/evals.mdx +9 -9
- package/docs/cli/index.mdx +6 -3
- package/docs/cli/translate.mdx +8 -8
- package/docs/configuration/analytics.mdx +23 -2
- package/docs/configuration/{ask-ai.mdx → assistant.mdx} +20 -20
- package/docs/configuration/customization.mdx +5 -4
- package/docs/configuration/index.mdx +7 -5
- package/docs/configuration/meta.ts +1 -1
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -3
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +5 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -12
- package/docs/content/versioning.mdx +1 -0
- package/docs/discoverability/agent-discovery.mdx +22 -8
- package/docs/discoverability/index.mdx +3 -3
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +5 -3
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +6 -4
- package/docs/discoverability/rss.mdx +3 -1
- package/docs/index.mdx +2 -2
- package/docs/references/asyncapi.mdx +1 -1
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +3 -3
- package/package.json +1 -1
- package/skills/blume/SKILL.md +5 -5
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- package/skills/blume-migrate/references/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +1 -1
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +2 -2
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-readability.ts +4 -4
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/api/paths.ts +1 -1
- package/src/ai/api/spec.ts +15 -2
- package/src/ai/api-catalog.ts +7 -1
- package/src/ai/ask-context.ts +21 -9
- package/src/ai/ask-data.ts +28 -14
- package/src/ai/ask.ts +84 -71
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/cors.ts +3 -3
- package/src/ai/index.ts +16 -16
- package/src/ai/link-headers.ts +8 -3
- package/src/ai/llms.ts +4 -3
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/server.ts +78 -7
- package/src/ai/openapi-components.ts +1 -1
- package/src/ai/relative-links.ts +78 -10
- package/src/ai/serializers.ts +1 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/visibility.ts +46 -15
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +90 -45
- package/src/astro/module-types.ts +1 -1
- package/src/astro/runtime-deps.ts +6 -6
- package/src/astro/templates.ts +87 -49
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +25 -5
- package/src/audit/checks/content.ts +20 -2
- package/src/audit/checks/i18n.ts +46 -8
- package/src/audit/checks/indexability.ts +39 -19
- package/src/audit/checks/links.ts +14 -0
- package/src/audit/checks/llms.ts +6 -3
- package/src/audit/checks/network.ts +3 -1
- package/src/audit/checks/og-image.ts +10 -0
- package/src/audit/checks/robots.ts +6 -1
- package/src/audit/checks/sitemap.ts +56 -31
- package/src/audit/checks/social.ts +21 -2
- package/src/audit/crawl.ts +88 -15
- package/src/audit/report.ts +54 -17
- package/src/audit/run.ts +1 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/blume-modules.d.ts +2 -2
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +8 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +7 -5
- package/src/cli/commands/eval.ts +4 -10
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/migrate.ts +2 -2
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +12 -9
- package/src/cli/commands/upgrade.ts +13 -2
- package/src/cli/eject-scripts.ts +32 -7
- package/src/cli/env.ts +12 -1
- package/src/cli/init/scaffold.ts +117 -11
- package/src/cli/init/starter-spec.ts +235 -0
- package/src/cli/required-secrets.ts +3 -3
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +2 -9
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +9 -3
- package/src/components/content/Expandable.astro +5 -1
- package/src/components/content/Frame.astro +2 -7
- package/src/components/content/GithubInfo.astro +12 -2
- package/src/components/content/Prompt.astro +2 -7
- package/src/components/content/Tabs.astro +54 -5
- package/src/components/content/Tile.astro +1 -1
- package/src/components/content/Tooltip.astro +69 -7
- package/src/components/content/Tree.astro +7 -2
- package/src/components/content/TypeTable.astro +10 -5
- package/src/components/content/Update.astro +8 -2
- package/src/components/content/auto-type-table.ts +4 -1
- package/src/components/content/badge-color.ts +17 -0
- package/src/components/content/base-href.ts +18 -3
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +36 -9
- package/src/components/islands/{AskAI.astro → Assistant.astro} +10 -10
- package/src/components/islands/{ask-ai.tsx → assistant.tsx} +39 -25
- package/src/components/islands/hooks.ts +21 -14
- package/src/components/islands/webmcp.ts +12 -8
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Header.astro +32 -19
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +6 -1
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +15 -6
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageLayout.astro +28 -14
- package/src/components/layout/Pagination.astro +7 -7
- package/src/components/layout/ReferenceLayout.astro +5 -2
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +18 -14
- package/src/components/layout/analytics-client.ts +3 -1
- package/src/components/layout/drawer-inert.ts +1 -1
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +21 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +9 -5
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +27 -52
- package/src/components/openapi/description.ts +2 -2
- package/src/components/openapi/helpers.ts +90 -12
- package/src/components/openapi/message-composer.ts +8 -0
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +4 -1
- package/src/components/openapi/operation-model.ts +40 -8
- package/src/components/openapi/panel.ts +29 -5
- package/src/components/openapi/playground-client.ts +37 -7
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +2 -0
- package/src/components/openapi/schema-tree.ts +203 -0
- package/src/components/openapi/snippets.ts +30 -15
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/core/base-path.ts +15 -0
- package/src/core/code-fences.ts +1 -1
- package/src/core/config-input.ts +23 -23
- package/src/core/config.ts +21 -7
- package/src/core/data.ts +3 -3
- package/src/core/diagnostics.ts +217 -30
- package/src/core/graph.ts +120 -11
- package/src/core/i18n-ui.ts +74 -11
- package/src/core/i18n.ts +13 -2
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +17 -17
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +69 -6
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +245 -76
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +23 -1
- package/src/core/request-body.ts +1 -1
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +95 -34
- package/src/core/server-features.ts +2 -2
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +3 -2
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +5 -1
- package/src/core/sources/github-releases.ts +106 -5
- package/src/core/sources/lexical.ts +9 -4
- package/src/core/sources/lower.ts +79 -26
- package/src/core/sources/mdx-remote.ts +1 -0
- package/src/core/sources/normalize.ts +132 -30
- package/src/core/sources/notion.ts +26 -10
- package/src/core/sources/obsidian.ts +17 -3
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +63 -44
- package/src/core/sources/remote.ts +18 -2
- package/src/core/sources/resolve.ts +52 -33
- package/src/core/sources/sanity.ts +1 -0
- package/src/core/sources/strapi-blocks.ts +9 -4
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +17 -5
- package/src/core/ui-packs/bg.ts +17 -5
- package/src/core/ui-packs/bn.ts +17 -5
- package/src/core/ui-packs/ca.ts +17 -5
- package/src/core/ui-packs/cs.ts +17 -5
- package/src/core/ui-packs/da.ts +17 -5
- package/src/core/ui-packs/de.ts +17 -5
- package/src/core/ui-packs/el.ts +17 -5
- package/src/core/ui-packs/es.ts +17 -5
- package/src/core/ui-packs/fa.ts +17 -5
- package/src/core/ui-packs/fi.ts +17 -5
- package/src/core/ui-packs/fr.ts +17 -5
- package/src/core/ui-packs/he.ts +17 -5
- package/src/core/ui-packs/hi.ts +17 -5
- package/src/core/ui-packs/hr.ts +17 -5
- package/src/core/ui-packs/hu.ts +17 -5
- package/src/core/ui-packs/id.ts +17 -5
- package/src/core/ui-packs/it.ts +17 -5
- package/src/core/ui-packs/ja.ts +17 -5
- package/src/core/ui-packs/ko.ts +17 -5
- package/src/core/ui-packs/nl.ts +17 -5
- package/src/core/ui-packs/no.ts +17 -5
- package/src/core/ui-packs/pl.ts +17 -5
- package/src/core/ui-packs/pt-br.ts +17 -5
- package/src/core/ui-packs/pt.ts +17 -5
- package/src/core/ui-packs/ro.ts +17 -5
- package/src/core/ui-packs/ru.ts +17 -5
- package/src/core/ui-packs/sk.ts +17 -5
- package/src/core/ui-packs/sr.ts +17 -5
- package/src/core/ui-packs/sv.ts +17 -5
- package/src/core/ui-packs/th.ts +17 -5
- package/src/core/ui-packs/tr.ts +17 -5
- package/src/core/ui-packs/uk.ts +17 -5
- package/src/core/ui-packs/vi.ts +17 -5
- package/src/core/ui-packs/zh-tw.ts +17 -5
- package/src/core/ui-packs/zh.ts +17 -5
- package/src/core/unrecognized-keys.ts +1 -1
- package/src/core/version-cut.ts +17 -2
- package/src/core/versions.ts +4 -1
- package/src/deploy/adapters/node.ts +5 -2
- package/src/deploy/adapters/registry.ts +2 -1
- package/src/deploy/adapters/types.ts +13 -1
- package/src/deploy/artifacts.ts +25 -5
- package/src/deploy/cloudflare-negotiation.ts +23 -4
- package/src/deploy/headers.ts +67 -51
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +1 -0
- package/src/deploy/platforms/netlify.ts +82 -5
- package/src/deploy/platforms/node.ts +7 -5
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +7 -0
- package/src/deploy/platforms/vercel.ts +9 -3
- package/src/deploy/redirects.ts +14 -3
- package/src/deploy/vercel-negotiation.ts +35 -3
- package/src/eval/agents.ts +10 -2
- package/src/eval/run.ts +25 -0
- package/src/markdown/base-links.ts +55 -8
- package/src/markdown/index.ts +6 -3
- package/src/markdown/relative-links.ts +3 -23
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +20 -4
- package/src/og/derive.ts +145 -4
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +77 -13
- package/src/openapi/render-mdx.ts +10 -1
- package/src/registry/eject.ts +135 -37
- package/src/search/documents.ts +24 -3
- package/src/search/orama-index.ts +1 -1
- package/src/search/sync/algolia.ts +36 -2
- package/src/sources/registry.ts +5 -0
- package/src/theme/entry.ts +11 -4
- package/src/translate/agents.ts +6 -1
- package/src/translate/ledger.ts +26 -3
- package/src/translate/meta.ts +11 -3
- package/src/translate/report.ts +1 -1
- package/src/translate/run.ts +11 -5
- package/src/translate/validate.ts +10 -1
- package/src/translate/work-list.ts +36 -3
- package/src/upgrade/upgrade.ts +37 -5
- package/dist/cli/chunk-1w8dp3qb.js.map +0 -10
- package/dist/cli/chunk-5a2z0198.js.map +0 -10
- package/dist/cli/chunk-6k8vp3ta.js.map +0 -19
- package/dist/cli/chunk-79njf86q.js.map +0 -11
- package/dist/cli/chunk-a9kptbw5.js.map +0 -14
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-bctazmbk.js.map +0 -10
- package/dist/cli/chunk-beat36xx.js.map +0 -10
- package/dist/cli/chunk-d1tadaw7.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-j8mw0za6.js.map +0 -35
- package/dist/cli/chunk-mnqj32sj.js.map +0 -12
- package/dist/cli/chunk-mwt1k8n7.js.map +0 -10
- package/dist/cli/chunk-nk3ts2xk.js +0 -51
- package/dist/cli/chunk-nk3ts2xk.js.map +0 -10
- package/dist/cli/chunk-sqn5t4q0.js.map +0 -10
- package/dist/cli/chunk-tzne8qfq.js.map +0 -10
- package/dist/cli/chunk-xaz13gwg.js.map +0 -182
- package/dist/cli/chunk-z01ze5c1.js.map +0 -10
- package/dist/cli/chunk-z1f5arsg.js.map +0 -36
- package/dist/cli/chunk-zg2gtj10.js.map +0 -35
- /package/dist/cli/{chunk-f2972sbt.js.map → chunk-00gs3wqs.js.map} +0 -0
- /package/dist/cli/{chunk-7ez8ny0t.js.map → chunk-bbnwccaz.js.map} +0 -0
- /package/dist/cli/{chunk-zxccj738.js.map → chunk-esh98wmb.js.map} +0 -0
- /package/dist/cli/{chunk-88cpgt6h.js.map → chunk-fsmrqk8a.js.map} +0 -0
- /package/dist/cli/{chunk-b5aj94ah.js.map → chunk-g698a744.js.map} +0 -0
- /package/dist/cli/{chunk-41za066z.js.map → chunk-h2ez8dzb.js.map} +0 -0
- /package/dist/cli/{chunk-by2290sx.js.map → chunk-h7k3nq3v.js.map} +0 -0
- /package/dist/cli/{chunk-y3e45rc8.js.map → chunk-n1yg3tj3.js.map} +0 -0
- /package/dist/cli/{chunk-f7t03s3g.js.map → chunk-wdrt2k2v.js.map} +0 -0
package/src/ai/ask.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { unrecognizedKeysMessage } from "../core/unrecognized-keys.ts";
|
|
|
9
9
|
* `reasoning` values minus `provider-default`, which is what omitting the
|
|
10
10
|
* option means.
|
|
11
11
|
*/
|
|
12
|
-
export const
|
|
12
|
+
export const assistantReasoningLevels = [
|
|
13
13
|
"none",
|
|
14
14
|
"minimal",
|
|
15
15
|
"low",
|
|
@@ -19,14 +19,17 @@ export const askReasoningLevels = [
|
|
|
19
19
|
] as const;
|
|
20
20
|
|
|
21
21
|
/** How much the model reasons before answering (an adapter's `reasoning`). */
|
|
22
|
-
export type
|
|
22
|
+
export type AssistantReasoning = (typeof assistantReasoningLevels)[number];
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* The AI SDK's `providerOptions` shape, forwarded to `streamText` verbatim:
|
|
26
26
|
* `{ [provider]: { [option]: value } }`. The escape hatch for model controls
|
|
27
27
|
* Blume doesn't name, so a new provider knob never needs a Blume field.
|
|
28
28
|
*/
|
|
29
|
-
export type
|
|
29
|
+
export type AssistantProviderOptions = Record<
|
|
30
|
+
string,
|
|
31
|
+
Record<string, JsonValue>
|
|
32
|
+
>;
|
|
30
33
|
|
|
31
34
|
/** The AI SDK provider package the OpenAI-compatible adapters install. */
|
|
32
35
|
const OPENAI_COMPATIBLE_DEP = "@ai-sdk/openai-compatible";
|
|
@@ -35,8 +38,8 @@ const OPENAI_COMPATIBLE_DEP = "@ai-sdk/openai-compatible";
|
|
|
35
38
|
// Shared options
|
|
36
39
|
// ---------------------------------------------------------------------------
|
|
37
40
|
|
|
38
|
-
/** The options every
|
|
39
|
-
export interface
|
|
41
|
+
/** The options every assistant adapter accepts. */
|
|
42
|
+
export interface AssistantAdapterOptions {
|
|
40
43
|
/**
|
|
41
44
|
* Name of the env var holding the provider's API key. Each adapter has its
|
|
42
45
|
* own default; set this only to point at a different variable.
|
|
@@ -53,7 +56,7 @@ export interface AskAdapterOptions {
|
|
|
53
56
|
* Options passed to `streamText` as its `providerOptions`, untouched, in the
|
|
54
57
|
* AI SDK's own shape (`{ openai: { textVerbosity: "low" } }`, say).
|
|
55
58
|
*/
|
|
56
|
-
providerOptions?:
|
|
59
|
+
providerOptions?: AssistantProviderOptions;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
/**
|
|
@@ -72,7 +75,7 @@ const sharedOptions = (apiKeyEnv: string) => ({
|
|
|
72
75
|
providerOptions: providerOptionsSchema.optional(),
|
|
73
76
|
});
|
|
74
77
|
|
|
75
|
-
const reasoningOption = z.enum(
|
|
78
|
+
const reasoningOption = z.enum(assistantReasoningLevels).optional();
|
|
76
79
|
|
|
77
80
|
// ---------------------------------------------------------------------------
|
|
78
81
|
// gateway()
|
|
@@ -83,7 +86,7 @@ const GATEWAY_API_KEY_ENV = "AI_GATEWAY_API_KEY";
|
|
|
83
86
|
const DEFAULT_GATEWAY_MODEL = "openai/gpt-5.5";
|
|
84
87
|
|
|
85
88
|
/** Options for {@link gateway}. */
|
|
86
|
-
export interface
|
|
89
|
+
export interface AssistantGatewayOptions extends AssistantAdapterOptions {
|
|
87
90
|
/** A `provider/model` id routed by the gateway. Defaults to `openai/gpt-5.5`. */
|
|
88
91
|
model?: string;
|
|
89
92
|
/**
|
|
@@ -92,7 +95,7 @@ export interface AskGatewayOptions extends AskAdapterOptions {
|
|
|
92
95
|
* control (OpenAI's `reasoning_effort`, for example); the model has to
|
|
93
96
|
* offer the level you pick. Omitted keeps the model's default.
|
|
94
97
|
*/
|
|
95
|
-
reasoning?:
|
|
98
|
+
reasoning?: AssistantReasoning;
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
const gatewayOptionsSchema = z.strictObject({
|
|
@@ -101,7 +104,10 @@ const gatewayOptionsSchema = z.strictObject({
|
|
|
101
104
|
reasoning: reasoningOption,
|
|
102
105
|
});
|
|
103
106
|
|
|
104
|
-
export type
|
|
107
|
+
export type AssistantGatewayAdapter = AdapterDescriptor<
|
|
108
|
+
"gateway",
|
|
109
|
+
AssistantGatewayOptions
|
|
110
|
+
>;
|
|
105
111
|
|
|
106
112
|
export const gatewayAdapterSchema = adapterDescriptorSchema(
|
|
107
113
|
"gateway",
|
|
@@ -109,14 +115,14 @@ export const gatewayAdapterSchema = adapterDescriptorSchema(
|
|
|
109
115
|
);
|
|
110
116
|
|
|
111
117
|
/**
|
|
112
|
-
* Route
|
|
118
|
+
* Route the assistant through the Vercel AI Gateway (the default). `model` is a
|
|
113
119
|
* `provider/model` string; the key is `AI_GATEWAY_API_KEY`, or Vercel's OIDC
|
|
114
120
|
* token when deployed there. Needs no provider SDK beyond the `ai` package
|
|
115
121
|
* Blume ships.
|
|
116
122
|
*/
|
|
117
123
|
export const gateway = (
|
|
118
|
-
options:
|
|
119
|
-
):
|
|
124
|
+
options: AssistantGatewayOptions = {}
|
|
125
|
+
): AssistantGatewayAdapter => ({
|
|
120
126
|
kind: "gateway",
|
|
121
127
|
options,
|
|
122
128
|
requiredSecrets: [options.apiKeyEnv ?? GATEWAY_API_KEY_ENV],
|
|
@@ -130,7 +136,7 @@ export const gateway = (
|
|
|
130
136
|
const OPENROUTER_API_KEY_ENV = "OPENROUTER_API_KEY";
|
|
131
137
|
|
|
132
138
|
/** Options for {@link openrouter}. */
|
|
133
|
-
export interface
|
|
139
|
+
export interface AssistantOpenRouterOptions extends AssistantAdapterOptions {
|
|
134
140
|
/** The OpenRouter model id (`anthropic/claude-sonnet-4-5`). */
|
|
135
141
|
model: string;
|
|
136
142
|
/**
|
|
@@ -138,7 +144,7 @@ export interface AskOpenRouterOptions extends AskAdapterOptions {
|
|
|
138
144
|
* OpenRouter's `reasoning.effort`, because its provider ignores the AI
|
|
139
145
|
* SDK's call-level option. Omitted keeps the model's default.
|
|
140
146
|
*/
|
|
141
|
-
reasoning?:
|
|
147
|
+
reasoning?: AssistantReasoning;
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
const openrouterOptionsSchema = z.strictObject({
|
|
@@ -147,9 +153,9 @@ const openrouterOptionsSchema = z.strictObject({
|
|
|
147
153
|
reasoning: reasoningOption,
|
|
148
154
|
});
|
|
149
155
|
|
|
150
|
-
export type
|
|
156
|
+
export type AssistantOpenRouterAdapter = AdapterDescriptor<
|
|
151
157
|
"openrouter",
|
|
152
|
-
|
|
158
|
+
AssistantOpenRouterOptions
|
|
153
159
|
>;
|
|
154
160
|
|
|
155
161
|
export const openrouterAdapterSchema = adapterDescriptorSchema(
|
|
@@ -158,12 +164,12 @@ export const openrouterAdapterSchema = adapterDescriptorSchema(
|
|
|
158
164
|
);
|
|
159
165
|
|
|
160
166
|
/**
|
|
161
|
-
* Route
|
|
167
|
+
* Route the assistant through OpenRouter. Reads `OPENROUTER_API_KEY` and needs
|
|
162
168
|
* `@openrouter/ai-sdk-provider` installed in the project.
|
|
163
169
|
*/
|
|
164
170
|
export const openrouter = (
|
|
165
|
-
options:
|
|
166
|
-
):
|
|
171
|
+
options: AssistantOpenRouterOptions
|
|
172
|
+
): AssistantOpenRouterAdapter => ({
|
|
167
173
|
kind: "openrouter",
|
|
168
174
|
options,
|
|
169
175
|
requiredSecrets: [options.apiKeyEnv ?? OPENROUTER_API_KEY_ENV],
|
|
@@ -177,7 +183,7 @@ export const openrouter = (
|
|
|
177
183
|
const LLMGATEWAY_API_KEY_ENV = "LLMGATEWAY_API_KEY";
|
|
178
184
|
|
|
179
185
|
/** Options for {@link llmgateway}. */
|
|
180
|
-
export interface
|
|
186
|
+
export interface AssistantLlmGatewayOptions extends AssistantAdapterOptions {
|
|
181
187
|
/** Overrides the preset endpoint (`https://api.llmgateway.io/v1`). */
|
|
182
188
|
baseUrl?: string;
|
|
183
189
|
/** The model id LLMGateway serves. */
|
|
@@ -186,7 +192,7 @@ export interface AskLlmGatewayOptions extends AskAdapterOptions {
|
|
|
186
192
|
* How much the model reasons before answering, sent in the request as
|
|
187
193
|
* `reasoning_effort`. Omitted keeps the model's default.
|
|
188
194
|
*/
|
|
189
|
-
reasoning?:
|
|
195
|
+
reasoning?: AssistantReasoning;
|
|
190
196
|
}
|
|
191
197
|
|
|
192
198
|
const llmgatewayOptionsSchema = z.strictObject({
|
|
@@ -196,9 +202,9 @@ const llmgatewayOptionsSchema = z.strictObject({
|
|
|
196
202
|
reasoning: reasoningOption,
|
|
197
203
|
});
|
|
198
204
|
|
|
199
|
-
export type
|
|
205
|
+
export type AssistantLlmGatewayAdapter = AdapterDescriptor<
|
|
200
206
|
"llmgateway",
|
|
201
|
-
|
|
207
|
+
AssistantLlmGatewayOptions
|
|
202
208
|
>;
|
|
203
209
|
|
|
204
210
|
export const llmgatewayAdapterSchema = adapterDescriptorSchema(
|
|
@@ -207,12 +213,12 @@ export const llmgatewayAdapterSchema = adapterDescriptorSchema(
|
|
|
207
213
|
);
|
|
208
214
|
|
|
209
215
|
/**
|
|
210
|
-
* Route
|
|
216
|
+
* Route the assistant through LLMGateway's OpenAI-compatible endpoint. Reads
|
|
211
217
|
* `LLMGATEWAY_API_KEY` and needs `@ai-sdk/openai-compatible` installed.
|
|
212
218
|
*/
|
|
213
219
|
export const llmgateway = (
|
|
214
|
-
options:
|
|
215
|
-
):
|
|
220
|
+
options: AssistantLlmGatewayOptions
|
|
221
|
+
): AssistantLlmGatewayAdapter => ({
|
|
216
222
|
kind: "llmgateway",
|
|
217
223
|
options,
|
|
218
224
|
requiredSecrets: [options.apiKeyEnv ?? LLMGATEWAY_API_KEY_ENV],
|
|
@@ -229,7 +235,7 @@ const INKEEP_API_KEY_ENV = "INKEEP_API_KEY";
|
|
|
229
235
|
* Options for {@link inkeep}. No `reasoning`: Inkeep runs its own QA pipeline
|
|
230
236
|
* behind an OpenAI-compatible endpoint with no reasoning control.
|
|
231
237
|
*/
|
|
232
|
-
export interface
|
|
238
|
+
export interface AssistantInkeepOptions extends AssistantAdapterOptions {
|
|
233
239
|
/** Overrides the preset endpoint (`https://api.inkeep.com/v1`). */
|
|
234
240
|
baseUrl?: string;
|
|
235
241
|
/** The Inkeep QA model id. */
|
|
@@ -242,7 +248,10 @@ const inkeepOptionsSchema = z.strictObject({
|
|
|
242
248
|
model: z.string().min(1),
|
|
243
249
|
});
|
|
244
250
|
|
|
245
|
-
export type
|
|
251
|
+
export type AssistantInkeepAdapter = AdapterDescriptor<
|
|
252
|
+
"inkeep",
|
|
253
|
+
AssistantInkeepOptions
|
|
254
|
+
>;
|
|
246
255
|
|
|
247
256
|
export const inkeepAdapterSchema = adapterDescriptorSchema(
|
|
248
257
|
"inkeep",
|
|
@@ -254,7 +263,9 @@ export const inkeepAdapterSchema = adapterDescriptorSchema(
|
|
|
254
263
|
* dashboard, so Blume leaves it ungrounded and it takes no `reasoning`.
|
|
255
264
|
* Reads `INKEEP_API_KEY` and needs `@ai-sdk/openai-compatible` installed.
|
|
256
265
|
*/
|
|
257
|
-
export const inkeep = (
|
|
266
|
+
export const inkeep = (
|
|
267
|
+
options: AssistantInkeepOptions
|
|
268
|
+
): AssistantInkeepAdapter => ({
|
|
258
269
|
kind: "inkeep",
|
|
259
270
|
options,
|
|
260
271
|
requiredSecrets: [options.apiKeyEnv ?? INKEEP_API_KEY_ENV],
|
|
@@ -266,7 +277,7 @@ export const inkeep = (options: AskInkeepOptions): AskInkeepAdapter => ({
|
|
|
266
277
|
// ---------------------------------------------------------------------------
|
|
267
278
|
|
|
268
279
|
/** Options for {@link openaiCompatible}. */
|
|
269
|
-
export interface
|
|
280
|
+
export interface AssistantOpenAICompatibleOptions extends AssistantAdapterOptions {
|
|
270
281
|
/** Name of the env var holding the endpoint's API key. */
|
|
271
282
|
apiKeyEnv: string;
|
|
272
283
|
/** The endpoint's base URL (`https://my-gateway.example.com/v1`). */
|
|
@@ -280,7 +291,7 @@ export interface AskOpenAICompatibleOptions extends AskAdapterOptions {
|
|
|
280
291
|
* `reasoning_effort`, so the endpoint has to accept that parameter.
|
|
281
292
|
* Omitted keeps the model's default.
|
|
282
293
|
*/
|
|
283
|
-
reasoning?:
|
|
294
|
+
reasoning?: AssistantReasoning;
|
|
284
295
|
}
|
|
285
296
|
|
|
286
297
|
const openaiCompatibleOptionsSchema = z.strictObject({
|
|
@@ -293,9 +304,9 @@ const openaiCompatibleOptionsSchema = z.strictObject({
|
|
|
293
304
|
reasoning: reasoningOption,
|
|
294
305
|
});
|
|
295
306
|
|
|
296
|
-
export type
|
|
307
|
+
export type AssistantOpenAICompatibleAdapter = AdapterDescriptor<
|
|
297
308
|
"openai-compatible",
|
|
298
|
-
|
|
309
|
+
AssistantOpenAICompatibleOptions
|
|
299
310
|
>;
|
|
300
311
|
|
|
301
312
|
export const openaiCompatibleAdapterSchema = adapterDescriptorSchema(
|
|
@@ -304,13 +315,13 @@ export const openaiCompatibleAdapterSchema = adapterDescriptorSchema(
|
|
|
304
315
|
);
|
|
305
316
|
|
|
306
317
|
/**
|
|
307
|
-
* Route
|
|
318
|
+
* Route the assistant through any OpenAI-compatible endpoint: supply its `baseUrl`,
|
|
308
319
|
* the `model` it serves, and the env var holding its key. Needs
|
|
309
320
|
* `@ai-sdk/openai-compatible` installed.
|
|
310
321
|
*/
|
|
311
322
|
export const openaiCompatible = (
|
|
312
|
-
options:
|
|
313
|
-
):
|
|
323
|
+
options: AssistantOpenAICompatibleOptions
|
|
324
|
+
): AssistantOpenAICompatibleAdapter => ({
|
|
314
325
|
kind: "openai-compatible",
|
|
315
326
|
options,
|
|
316
327
|
requiredSecrets: [options.apiKeyEnv],
|
|
@@ -318,16 +329,16 @@ export const openaiCompatible = (
|
|
|
318
329
|
});
|
|
319
330
|
|
|
320
331
|
// ---------------------------------------------------------------------------
|
|
321
|
-
// The `ai.
|
|
332
|
+
// The `ai.assistant.provider` schema
|
|
322
333
|
// ---------------------------------------------------------------------------
|
|
323
334
|
|
|
324
|
-
/** Which backend answers
|
|
325
|
-
export type
|
|
326
|
-
|
|
|
327
|
-
|
|
|
328
|
-
|
|
|
329
|
-
|
|
|
330
|
-
|
|
|
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;
|
|
331
342
|
|
|
332
343
|
// ---------------------------------------------------------------------------
|
|
333
344
|
// Blume 1 hints
|
|
@@ -354,29 +365,29 @@ const MOVED_TO_PROVIDER: ReadonlySet<string> = new Set([
|
|
|
354
365
|
"reasoning",
|
|
355
366
|
]);
|
|
356
367
|
|
|
357
|
-
/** The provider an `ai.
|
|
358
|
-
const
|
|
368
|
+
/** The provider an `ai.assistant` object names: a 1.x string or a descriptor's `kind`. */
|
|
369
|
+
const assistantProviderNameProbe = z.looseObject({
|
|
359
370
|
provider: z.union([
|
|
360
371
|
z.string(),
|
|
361
372
|
z.looseObject({ kind: z.string() }).transform(({ kind }) => kind),
|
|
362
373
|
]),
|
|
363
374
|
});
|
|
364
375
|
|
|
365
|
-
/** The factory a failing `ai.
|
|
376
|
+
/** The factory a failing `ai.assistant` object's provider names, or the gateway. */
|
|
366
377
|
const providerFactory = (issue: z.core.$ZodRawIssue): string => {
|
|
367
|
-
const probe =
|
|
378
|
+
const probe = assistantProviderNameProbe.safeParse(issue.input);
|
|
368
379
|
return (
|
|
369
380
|
(probe.success && FACTORY_BY_PROVIDER.get(probe.data.provider)) || "gateway"
|
|
370
381
|
);
|
|
371
382
|
};
|
|
372
383
|
|
|
373
384
|
/**
|
|
374
|
-
* Error params for `ai.
|
|
385
|
+
* Error params for `ai.assistant`: a 1.x flat provider field (`model`, `apiKeyEnv`,
|
|
375
386
|
* `baseUrl`, `headers`, `reasoning`) names the adapter call it moves into —
|
|
376
387
|
* the one the object's `provider` picks, 1.x string or descriptor — instead
|
|
377
388
|
* of Zod's bare "Unrecognized key"; any other unknown key keeps its wording.
|
|
378
389
|
*/
|
|
379
|
-
export const
|
|
390
|
+
export const assistantMovedFieldsHint = {
|
|
380
391
|
error: (issue: z.core.$ZodRawIssue): string | undefined => {
|
|
381
392
|
if (issue.code !== "unrecognized_keys") {
|
|
382
393
|
return;
|
|
@@ -385,7 +396,7 @@ export const askMovedFieldsHint = {
|
|
|
385
396
|
if (moved.length === 0) {
|
|
386
397
|
return;
|
|
387
398
|
}
|
|
388
|
-
const fields = moved.map((key) => `ai.
|
|
399
|
+
const fields = moved.map((key) => `ai.assistant.${key}`).join(", ");
|
|
389
400
|
const hint = `${fields} moved into the provider adapter: \`provider: ${providerFactory(issue)}({ ${moved.join(", ")} })\`, imported from "blume/ai".`;
|
|
390
401
|
const others = issue.keys.filter((key) => !MOVED_TO_PROVIDER.has(key));
|
|
391
402
|
return others.length > 0
|
|
@@ -394,27 +405,27 @@ export const askMovedFieldsHint = {
|
|
|
394
405
|
},
|
|
395
406
|
};
|
|
396
407
|
|
|
397
|
-
/** A value that is a 1.x provider name, for the `ai.
|
|
408
|
+
/** A value that is a 1.x provider name, for the `ai.assistant.provider` hint. */
|
|
398
409
|
const providerNameProbe = z.string();
|
|
399
410
|
|
|
400
411
|
/**
|
|
401
|
-
* The message for an `ai.
|
|
412
|
+
* The message for an `ai.assistant.provider` that isn't a descriptor: a 1.x
|
|
402
413
|
* provider name names the factory that replaced it; anything else lists them.
|
|
403
414
|
*/
|
|
404
415
|
const providerNotAdapterMessage = (issue: z.core.$ZodRawIssue): string => {
|
|
405
416
|
const name = providerNameProbe.safeParse(issue.input);
|
|
406
417
|
const factory = name.success ? FACTORY_BY_PROVIDER.get(name.data) : undefined;
|
|
407
418
|
return factory
|
|
408
|
-
? `ai.
|
|
409
|
-
: 'ai.
|
|
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().';
|
|
410
421
|
};
|
|
411
422
|
|
|
412
423
|
/**
|
|
413
|
-
* `ai.
|
|
424
|
+
* `ai.assistant.provider`: the descriptor an adapter factory returned, validated
|
|
414
425
|
* against that adapter's own option schema. A value that isn't a descriptor
|
|
415
426
|
* at all (a 1.x provider name) names the factory that replaced it.
|
|
416
427
|
*/
|
|
417
|
-
export const
|
|
428
|
+
export const assistantAdapterSchema = z.discriminatedUnion(
|
|
418
429
|
"kind",
|
|
419
430
|
[
|
|
420
431
|
gatewayAdapterSchema,
|
|
@@ -434,12 +445,12 @@ export const askAdapterSchema = z.discriminatedUnion(
|
|
|
434
445
|
}
|
|
435
446
|
);
|
|
436
447
|
|
|
437
|
-
/** A resolved (post-defaults) `ai.
|
|
438
|
-
export type
|
|
439
|
-
export type
|
|
448
|
+
/** A resolved (post-defaults) `ai.assistant.provider` descriptor. */
|
|
449
|
+
export type AssistantAdapterConfig = z.output<typeof assistantAdapterSchema>;
|
|
450
|
+
export type AssistantAdapterKind = AssistantAdapterConfig["kind"];
|
|
440
451
|
|
|
441
|
-
/** The provider when `ai.
|
|
442
|
-
export const
|
|
452
|
+
/** The provider when `ai.assistant.provider` is unset: the gateway with its defaults. */
|
|
453
|
+
export const DEFAULT_ASSISTANT_PROVIDER: AssistantAdapter = gateway();
|
|
443
454
|
|
|
444
455
|
// ---------------------------------------------------------------------------
|
|
445
456
|
// Resolved backend
|
|
@@ -474,7 +485,7 @@ export interface AskBackendTemplate {
|
|
|
474
485
|
export interface AskBackend {
|
|
475
486
|
/** Whether Blume grounds answers in the docs (Inkeep retrieves itself). */
|
|
476
487
|
grounded: boolean;
|
|
477
|
-
kind:
|
|
488
|
+
kind: AssistantAdapterKind;
|
|
478
489
|
/** Human-readable adapter name for diagnostics ("AI Gateway"). */
|
|
479
490
|
label: string;
|
|
480
491
|
/** Appended to the missing-secret warning (an alternative credential, say). */
|
|
@@ -499,7 +510,7 @@ const headersLine = (headers?: Record<string, string>): string =>
|
|
|
499
510
|
/** Refuse a request up front when the adapter's key env var is unset. */
|
|
500
511
|
const keyCheck = (env: string): string => ` if (!${secretExpr(env)}) {
|
|
501
512
|
return new Response(
|
|
502
|
-
${JSON.stringify(`
|
|
513
|
+
${JSON.stringify(`The assistant is not configured: set ${env}.`)},
|
|
503
514
|
{ status: 503 }
|
|
504
515
|
);
|
|
505
516
|
}`;
|
|
@@ -510,7 +521,7 @@ const keyCheck = (env: string): string => ` if (!${secretExpr(env)}) {
|
|
|
510
521
|
*/
|
|
511
522
|
const callFields = (options: {
|
|
512
523
|
providerOptions?: z.output<typeof providerOptionsSchema>;
|
|
513
|
-
reasoning?:
|
|
524
|
+
reasoning?: AssistantReasoning;
|
|
514
525
|
}): string[] => {
|
|
515
526
|
const fields: string[] = [];
|
|
516
527
|
if (options.reasoning) {
|
|
@@ -542,7 +553,7 @@ const gatewayBackend = (
|
|
|
542
553
|
keyCheck: ` // The AI Gateway authenticates with an API key or Vercel's OIDC token.
|
|
543
554
|
if (!(${secretExpr(options.apiKeyEnv)} || getSecret("VERCEL_OIDC_TOKEN"))) {
|
|
544
555
|
return new Response(
|
|
545
|
-
${JSON.stringify(`
|
|
556
|
+
${JSON.stringify(`The assistant is not configured: set ${options.apiKeyEnv} (or deploy on Vercel with OIDC).`)},
|
|
546
557
|
{ status: 503 }
|
|
547
558
|
);
|
|
548
559
|
}`,
|
|
@@ -587,7 +598,7 @@ const openrouterBackend = (
|
|
|
587
598
|
* option as `reasoning_effort`.
|
|
588
599
|
*/
|
|
589
600
|
const openaiCompatibleBackend = (
|
|
590
|
-
kind:
|
|
601
|
+
kind: AssistantAdapterKind,
|
|
591
602
|
label: string,
|
|
592
603
|
grounded: boolean,
|
|
593
604
|
options: {
|
|
@@ -597,7 +608,7 @@ const openaiCompatibleBackend = (
|
|
|
597
608
|
model: string;
|
|
598
609
|
name: string;
|
|
599
610
|
providerOptions?: z.output<typeof providerOptionsSchema>;
|
|
600
|
-
reasoning?:
|
|
611
|
+
reasoning?: AssistantReasoning;
|
|
601
612
|
}
|
|
602
613
|
): AskBackend => ({
|
|
603
614
|
grounded,
|
|
@@ -621,9 +632,11 @@ const openaiCompatibleBackend = (
|
|
|
621
632
|
},
|
|
622
633
|
});
|
|
623
634
|
|
|
624
|
-
/** Resolve a parsed `ai.
|
|
635
|
+
/** Resolve a parsed `ai.assistant.provider` descriptor into its backend. */
|
|
625
636
|
export const resolveAskBackend = (
|
|
626
|
-
provider:
|
|
637
|
+
provider: AssistantAdapterConfig = assistantAdapterSchema.parse(
|
|
638
|
+
DEFAULT_ASSISTANT_PROVIDER
|
|
639
|
+
)
|
|
627
640
|
): AskBackend => {
|
|
628
641
|
switch (provider.kind) {
|
|
629
642
|
case "gateway": {
|
|
@@ -4,6 +4,7 @@ import { mdxToMdast } from "satteri";
|
|
|
4
4
|
import { parseYouTubeId } from "../components/content/youtube.ts";
|
|
5
5
|
import type { ExampleLookup } from "../core/types.ts";
|
|
6
6
|
import { MDX_FEATURES } from "../markdown/features.ts";
|
|
7
|
+
import { readStaticExpression } from "./static-expression.ts";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Downlevel Blume's MDX components to plain Markdown for agent-facing output
|
|
@@ -44,11 +45,19 @@ interface MdxAttribute {
|
|
|
44
45
|
|
|
45
46
|
/** A single source replacement: `[start, end)` byte range → `text`. */
|
|
46
47
|
interface Splice {
|
|
48
|
+
/**
|
|
49
|
+
* The range is a flow (block-level) element, so the line after it must
|
|
50
|
+
* start a block of its own.
|
|
51
|
+
*/
|
|
52
|
+
block: boolean;
|
|
47
53
|
end: number;
|
|
48
54
|
start: number;
|
|
49
55
|
text: string;
|
|
50
56
|
}
|
|
51
57
|
|
|
58
|
+
/** Text that continues on the very next line, with no blank line between. */
|
|
59
|
+
const NEXT_LINE_TEXT = /^[\t ]*\n[\t ]*\S/u;
|
|
60
|
+
|
|
52
61
|
/**
|
|
53
62
|
* A statically-recovered data value. Parsed front matter and evaluated
|
|
54
63
|
* attribute literals are both plain data — scalars, dates, arrays, and
|
|
@@ -135,33 +144,13 @@ export type ComponentMarkdown = (
|
|
|
135
144
|
) => string | null;
|
|
136
145
|
|
|
137
146
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* other scope throw and report as not evaluable.
|
|
147
|
+
* Read an element's attributes into a plain props object. An expression
|
|
148
|
+
* attribute (`prop={...}`) is read as literal data and never executed (see
|
|
149
|
+
* `static-expression.ts`): the downleveler also runs over plain `.md` pages
|
|
150
|
+
* and remote content, which nothing else executes. `prop={frontmatter.status}`
|
|
151
|
+
* resolves against the page's front matter, as it does when Astro renders
|
|
152
|
+
* the page; anything else — a call, an import — marks the props lossy.
|
|
145
153
|
*/
|
|
146
|
-
const evaluateExpression = (
|
|
147
|
-
raw: string,
|
|
148
|
-
frontmatter: Record<string, EvaluatedValue> | undefined
|
|
149
|
-
) => {
|
|
150
|
-
try {
|
|
151
|
-
// Build-time eval of the author's own attribute literals; a throw falls
|
|
152
|
-
// back to leaving the JSX verbatim.
|
|
153
|
-
// oxlint-disable-next-line no-new-func
|
|
154
|
-
const value: EvaluatedValue = new Function(
|
|
155
|
-
"frontmatter",
|
|
156
|
-
`"use strict"; return (${raw});`
|
|
157
|
-
)(frontmatter);
|
|
158
|
-
return { ok: true, value };
|
|
159
|
-
} catch {
|
|
160
|
-
return { ok: false, value: undefined };
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
/** Evaluate an element's attributes into a plain props object. */
|
|
165
154
|
const readProps = (
|
|
166
155
|
node: MdastNode,
|
|
167
156
|
frontmatter: Record<string, EvaluatedValue> | undefined
|
|
@@ -180,7 +169,7 @@ const readProps = (
|
|
|
180
169
|
} else if (isString(attribute.value)) {
|
|
181
170
|
props[attribute.name] = attribute.value;
|
|
182
171
|
} else {
|
|
183
|
-
const result =
|
|
172
|
+
const result = readStaticExpression(attribute.value.value, frontmatter);
|
|
184
173
|
if (result.ok) {
|
|
185
174
|
props[attribute.name] = result.value;
|
|
186
175
|
} else {
|
|
@@ -208,14 +197,24 @@ const applySplices = (text: string, splices: Splice[]): string => {
|
|
|
208
197
|
const lineStart = result.lastIndexOf("\n", splice.start - 1) + 1;
|
|
209
198
|
const prefix = result.slice(lineStart, splice.start);
|
|
210
199
|
const indent = /^[\t ]+$/u.test(prefix) ? prefix : "";
|
|
200
|
+
// The JSX's closing tag ended its block; the Markdown standing in for it
|
|
201
|
+
// doesn't. Text on the very next line would read as a lazy continuation
|
|
202
|
+
// of a blockquote or list item (`> Body` then `Next.` joins the quote),
|
|
203
|
+
// so a blank line keeps it out.
|
|
204
|
+
const spliced =
|
|
205
|
+
splice.block &&
|
|
206
|
+
splice.text !== "" &&
|
|
207
|
+
NEXT_LINE_TEXT.test(result.slice(splice.end))
|
|
208
|
+
? `${splice.text}\n`
|
|
209
|
+
: splice.text;
|
|
211
210
|
const replacement = indent
|
|
212
|
-
?
|
|
211
|
+
? spliced
|
|
213
212
|
.split("\n")
|
|
214
213
|
.map((line, index) =>
|
|
215
214
|
index === 0 || line === "" ? line : `${indent}${line}`
|
|
216
215
|
)
|
|
217
216
|
.join("\n")
|
|
218
|
-
:
|
|
217
|
+
: spliced;
|
|
219
218
|
result =
|
|
220
219
|
result.slice(0, splice.start) + replacement + result.slice(splice.end);
|
|
221
220
|
}
|
|
@@ -888,15 +887,21 @@ const renderSlice = (
|
|
|
888
887
|
const splices: Splice[] = [];
|
|
889
888
|
// oxlint-disable-next-line no-use-before-define
|
|
890
889
|
collectSplices(walk, nodes, splices);
|
|
890
|
+
// Start the slice at its line's indent, so a component that opens the
|
|
891
|
+
// slice is indented like the lines after it once replaced (see
|
|
892
|
+
// `applySplices`) and dedents with them; the final trim drops that indent
|
|
893
|
+
// from the first line again.
|
|
894
|
+
const indent = indentAt(walk.source, start);
|
|
895
|
+
const from = start - (indent ?? 0);
|
|
891
896
|
const spliced = applySplices(
|
|
892
|
-
walk.source.slice(
|
|
897
|
+
walk.source.slice(from, end),
|
|
893
898
|
splices.map((splice) => ({
|
|
894
899
|
...splice,
|
|
895
|
-
end: splice.end -
|
|
896
|
-
start: splice.start -
|
|
900
|
+
end: splice.end - from,
|
|
901
|
+
start: splice.start - from,
|
|
897
902
|
}))
|
|
898
903
|
);
|
|
899
|
-
return dedent(spliced,
|
|
904
|
+
return dedent(spliced, indent).trim();
|
|
900
905
|
};
|
|
901
906
|
|
|
902
907
|
/** The element's body as Markdown: the slice covering all of its children. */
|
|
@@ -996,6 +1001,7 @@ const collectSplices = (
|
|
|
996
1001
|
const text = hasOffsets(node) ? downlevelComponentNode(node, walk) : null;
|
|
997
1002
|
if (text !== null && hasOffsets(node)) {
|
|
998
1003
|
out.push({
|
|
1004
|
+
block: node.type === "mdxJsxFlowElement",
|
|
999
1005
|
end: node.position.end.offset,
|
|
1000
1006
|
start: node.position.start.offset,
|
|
1001
1007
|
text,
|
|
@@ -1015,10 +1021,10 @@ const collectSplices = (
|
|
|
1015
1021
|
* over the built-ins: a same-name entry replaces the built-in serializer, and
|
|
1016
1022
|
* one that always returns `null` effectively opts that component out.
|
|
1017
1023
|
*
|
|
1018
|
-
* `frontmatter` is the page's parsed front-matter data.
|
|
1019
|
-
*
|
|
1020
|
-
*
|
|
1021
|
-
*
|
|
1024
|
+
* `frontmatter` is the page's parsed front-matter data. Attribute
|
|
1025
|
+
* expressions that reference it — `prop={frontmatter.status}` — resolve the
|
|
1026
|
+
* way they do when Astro renders the page, and it is handed to serializers on
|
|
1027
|
+
* their context. Expressions are read as literal data, never executed.
|
|
1022
1028
|
*/
|
|
1023
1029
|
export const downlevelComponents = (
|
|
1024
1030
|
source: string,
|
package/src/ai/cors.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CORS for the generated
|
|
2
|
+
* CORS for the assistant's generated route (`ai.assistant.cors`).
|
|
3
3
|
*
|
|
4
4
|
* A browser only lets a page on another origin read a response that names
|
|
5
5
|
* that origin, and a JSON `POST` preflights first. `preflightResponse` answers
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
* rather than stamping each `return`, keeps the next return site added to the
|
|
9
9
|
* handler from shipping an opaque failure for that one status.
|
|
10
10
|
*
|
|
11
|
-
* `allowed` is the `ai.
|
|
11
|
+
* `allowed` is the `ai.assistant.cors` list: origins already reduced to their
|
|
12
12
|
* `scheme://host[:port]` form by the config schema, or the single entry `"*"`
|
|
13
13
|
* to admit every origin.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
/** The `ai.
|
|
16
|
+
/** The `ai.assistant.cors` entry that admits every origin. */
|
|
17
17
|
export const ANY_ORIGIN = "*";
|
|
18
18
|
|
|
19
19
|
/** The headers a response carries for a cross-origin caller. */
|