mirror of
https://github.com/jakejarvis/stanza.git
synced 2026-07-16 18:05:58 -04:00
feat: add ai category with vercel-ai-sdk and tanstack-ai modules
- Register a new `ai` category in `CATEGORIES` (cardinality `one`, home `packages/ai/`) so both modules land under the same single-choice slot
- Add `ai-vercel-ai-sdk`: installs `ai` + `@ai-sdk/openai`, emits a `model.ts` configured for `gpt-4o-mini`, a shared package entry-point, and a streaming `/api/chat` route for Next.js (`StreamingTextResponse`) and TanStack Start (`EventStream`); peers on `framework`
- Add `ai-tanstack-ai`: installs `@tanstack/ai` + `@tanstack/ai-openai`, emits an `adapter.ts` wrapping `openaiText("gpt-4o-mini")`, a shared entry-point, and a streaming `/api/chat` route for both frameworks via `toServerSentEventsResponse`; peers on `framework`
- Both modules declare `OPENAI_API_KEY` in `env` and ship provider-swap instructions in `readme.md`
- Update `registry.mdx` AI table: mark both modules 🟢 Available with short capability notes
This commit is contained in:
@@ -53,10 +53,10 @@ Single-choice, constraint-bearing. An optional layer between the framework and t
|
||||
|
||||
Single-choice, constraint-bearing, installs into `packages/ai/`.
|
||||
|
||||
| Module | Status | Notes |
|
||||
| --------------- | --------------- | ------------------------------------ |
|
||||
| `vercel-ai-sdk` | 🟨 Planned | `ai` package + provider sub-recipes. |
|
||||
| `tanstack-ai` | 🟨 Planned | TanStack AI. |
|
||||
| Module | Status | Notes |
|
||||
| --------------- | ----------------- | ----------------------------------------------------------------------------------- |
|
||||
| `vercel-ai-sdk` | 🟢 Available | `ai` + `@ai-sdk/openai` with a streaming `/api/chat` route. Peers on `framework`. |
|
||||
| `tanstack-ai` | 🟢 Available | `@tanstack/ai` + `@tanstack/ai-openai` with a streaming `/api/chat` route over SSE. |
|
||||
|
||||
## Authentication
|
||||
|
||||
|
||||
@@ -87,6 +87,13 @@ export const CATEGORIES = [
|
||||
cardinality: "one",
|
||||
home: { kind: "package", dir: "email" },
|
||||
},
|
||||
{
|
||||
id: "ai",
|
||||
label: "AI",
|
||||
description: "AI SDK + provider wiring.",
|
||||
cardinality: "one",
|
||||
home: { kind: "package", dir: "ai" },
|
||||
},
|
||||
{
|
||||
id: "tooling",
|
||||
label: "Tooling",
|
||||
|
||||
Generated
+72
@@ -310,6 +310,24 @@ importers:
|
||||
specifier: npm:@voidzero-dev/vite-plus-test@^0.1.22
|
||||
version: '@voidzero-dev/vite-plus-test@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))'
|
||||
|
||||
registry/modules/ai-tanstack-ai:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/codemods
|
||||
'@stanza/registry':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/ai-vercel-ai-sdk:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/codemods
|
||||
'@stanza/registry':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/auth-better-auth:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
@@ -374,6 +392,15 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/monorepo-turbo:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/codemods
|
||||
'@stanza/registry':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/orm-drizzle:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
@@ -404,6 +431,51 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/testing-playwright:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/codemods
|
||||
'@stanza/registry':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/testing-vitest:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/codemods
|
||||
'@stanza/registry':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/tooling-biome:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/codemods
|
||||
'@stanza/registry':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/tooling-eslint-prettier:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/codemods
|
||||
'@stanza/registry':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/tooling-oxlint-oxfmt:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/codemods
|
||||
'@stanza/registry':
|
||||
specifier: workspace:*
|
||||
version: link:../../../packages/registry
|
||||
|
||||
registry/modules/ui-shadcn-base:
|
||||
dependencies:
|
||||
'@stanza/codemods':
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.6 KiB |
@@ -0,0 +1,55 @@
|
||||
import { defineModule } from "@stanza/registry";
|
||||
|
||||
export default defineModule({
|
||||
id: "tanstack-ai",
|
||||
category: "ai",
|
||||
label: "TanStack AI",
|
||||
description: "Composable AI primitives across providers.",
|
||||
version: "0.1.0",
|
||||
peers: {
|
||||
framework: ["next", "tanstack-start"],
|
||||
},
|
||||
homepage: "https://tanstack.com/ai",
|
||||
dependencies: {
|
||||
"@tanstack/ai": "^0.22.0",
|
||||
"@tanstack/ai-openai": "^0.10.2",
|
||||
},
|
||||
env: [
|
||||
{
|
||||
name: "OPENAI_API_KEY",
|
||||
example: "sk-...",
|
||||
required: true,
|
||||
description: "OpenAI API key for the chat completion adapter.",
|
||||
},
|
||||
],
|
||||
adapters: [
|
||||
{
|
||||
key: "next",
|
||||
match: { framework: "next" },
|
||||
templates: [
|
||||
{ src: "shared/index.ts", dest: "src/index.ts", scope: "package" },
|
||||
{ src: "shared/adapter.ts", dest: "src/adapter.ts", scope: "package" },
|
||||
{
|
||||
src: "next/route.ts",
|
||||
dest: "app/api/chat/route.ts",
|
||||
scope: "app",
|
||||
template: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "tanstack-start",
|
||||
match: { framework: "tanstack-start" },
|
||||
templates: [
|
||||
{ src: "shared/index.ts", dest: "src/index.ts", scope: "package" },
|
||||
{ src: "shared/adapter.ts", dest: "src/adapter.ts", scope: "package" },
|
||||
{
|
||||
src: "tanstack/route.ts",
|
||||
dest: "src/routes/api/chat.ts",
|
||||
scope: "app",
|
||||
template: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@stanza-modules/ai-tanstack-ai",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "./module.ts",
|
||||
"dependencies": {
|
||||
"@stanza/codemods": "workspace:*",
|
||||
"@stanza/registry": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Set `OPENAI_API_KEY` in `.env` and POST to `/api/chat` with an `{ messages }` body to stream a response over Server-Sent Events. The configured adapter is exported from `{{package.name}}` — edit `src/adapter.ts` to swap providers (`@tanstack/ai-anthropic`, `@tanstack/ai-google`, …) or models.
|
||||
@@ -0,0 +1,11 @@
|
||||
import { chat, toServerSentEventsResponse } from "@tanstack/ai";
|
||||
|
||||
import { adapter } from "{{package.name}}";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const { messages } = await request.json();
|
||||
|
||||
const stream = chat({ adapter, messages });
|
||||
|
||||
return toServerSentEventsResponse(stream);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { openaiText } from "@tanstack/ai-openai";
|
||||
|
||||
export const adapter = openaiText("gpt-4o-mini");
|
||||
@@ -0,0 +1 @@
|
||||
export { adapter } from "./adapter.ts";
|
||||
@@ -0,0 +1,18 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { chat, toServerSentEventsResponse } from "@tanstack/ai";
|
||||
|
||||
import { adapter } from "{{package.name}}";
|
||||
|
||||
export const Route = createFileRoute("/api/chat")({
|
||||
server: {
|
||||
handlers: {
|
||||
POST: async ({ request }) => {
|
||||
const { messages } = await request.json();
|
||||
|
||||
const stream = chat({ adapter, messages });
|
||||
|
||||
return toServerSentEventsResponse(stream);
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["module.ts"],
|
||||
"exclude": ["templates"]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 256 222" width="256" height="222" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><path fill="#fff" d="m128 0 128 221.705H0z"/></svg>
|
||||
|
After Width: | Height: | Size: 169 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 256 222" width="256" height="222" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><path fill="#000" d="m128 0 128 221.705H0z"/></svg>
|
||||
|
After Width: | Height: | Size: 169 B |
@@ -0,0 +1,55 @@
|
||||
import { defineModule } from "@stanza/registry";
|
||||
|
||||
export default defineModule({
|
||||
id: "vercel-ai-sdk",
|
||||
category: "ai",
|
||||
label: "Vercel AI SDK",
|
||||
description: "Streaming AI SDK with tools, structured output, and React hooks.",
|
||||
version: "0.1.0",
|
||||
peers: {
|
||||
framework: ["next", "tanstack-start"],
|
||||
},
|
||||
homepage: "https://ai-sdk.dev",
|
||||
dependencies: {
|
||||
ai: "^6.0.191",
|
||||
"@ai-sdk/openai": "^3.0.65",
|
||||
},
|
||||
env: [
|
||||
{
|
||||
name: "OPENAI_API_KEY",
|
||||
example: "sk-...",
|
||||
required: true,
|
||||
description: "OpenAI API key for the chat completion provider.",
|
||||
},
|
||||
],
|
||||
adapters: [
|
||||
{
|
||||
key: "next",
|
||||
match: { framework: "next" },
|
||||
templates: [
|
||||
{ src: "shared/index.ts", dest: "src/index.ts", scope: "package" },
|
||||
{ src: "shared/model.ts", dest: "src/model.ts", scope: "package" },
|
||||
{
|
||||
src: "next/route.ts",
|
||||
dest: "app/api/chat/route.ts",
|
||||
scope: "app",
|
||||
template: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "tanstack-start",
|
||||
match: { framework: "tanstack-start" },
|
||||
templates: [
|
||||
{ src: "shared/index.ts", dest: "src/index.ts", scope: "package" },
|
||||
{ src: "shared/model.ts", dest: "src/model.ts", scope: "package" },
|
||||
{
|
||||
src: "tanstack/route.ts",
|
||||
dest: "src/routes/api/chat.ts",
|
||||
scope: "app",
|
||||
template: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@stanza-modules/ai-vercel-ai-sdk",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "./module.ts",
|
||||
"dependencies": {
|
||||
"@stanza/codemods": "workspace:*",
|
||||
"@stanza/registry": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Set `OPENAI_API_KEY` in `.env` and POST to `/api/chat` with an `{ messages }` body to stream a response. The configured model is exported from `{{package.name}}` — edit `src/model.ts` to swap providers or models.
|
||||
@@ -0,0 +1,14 @@
|
||||
import { convertToModelMessages, streamText, type UIMessage } from "ai";
|
||||
|
||||
import { model } from "{{package.name}}";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { messages }: { messages: UIMessage[] } = await req.json();
|
||||
|
||||
const result = streamText({
|
||||
model,
|
||||
messages: await convertToModelMessages(messages),
|
||||
});
|
||||
|
||||
return result.toUIMessageStreamResponse();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { model } from "./model.ts";
|
||||
@@ -0,0 +1,3 @@
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
|
||||
export const model = openai("gpt-4o-mini");
|
||||
@@ -0,0 +1,21 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { convertToModelMessages, streamText, type UIMessage } from "ai";
|
||||
|
||||
import { model } from "{{package.name}}";
|
||||
|
||||
export const Route = createFileRoute("/api/chat")({
|
||||
server: {
|
||||
handlers: {
|
||||
POST: async ({ request }) => {
|
||||
const { messages }: { messages: UIMessage[] } = await request.json();
|
||||
|
||||
const result = streamText({
|
||||
model,
|
||||
messages: await convertToModelMessages(messages),
|
||||
});
|
||||
|
||||
return result.toUIMessageStreamResponse();
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["module.ts"],
|
||||
"exclude": ["templates"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@stanza-modules/monorepo-turbo",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "./module.ts",
|
||||
"dependencies": {
|
||||
"@stanza/codemods": "workspace:*",
|
||||
"@stanza/registry": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["module.ts"],
|
||||
"exclude": ["templates"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@stanza-modules/testing-playwright",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "./module.ts",
|
||||
"dependencies": {
|
||||
"@stanza/codemods": "workspace:*",
|
||||
"@stanza/registry": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["module.ts"],
|
||||
"exclude": ["templates"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@stanza-modules/testing-vitest",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "./module.ts",
|
||||
"dependencies": {
|
||||
"@stanza/codemods": "workspace:*",
|
||||
"@stanza/registry": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["module.ts"],
|
||||
"exclude": ["templates"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@stanza-modules/tooling-biome",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "./module.ts",
|
||||
"dependencies": {
|
||||
"@stanza/codemods": "workspace:*",
|
||||
"@stanza/registry": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["module.ts"],
|
||||
"exclude": ["templates"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@stanza-modules/tooling-eslint-prettier",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "./module.ts",
|
||||
"dependencies": {
|
||||
"@stanza/codemods": "workspace:*",
|
||||
"@stanza/registry": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["module.ts"],
|
||||
"exclude": ["templates"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@stanza-modules/tooling-oxlint-oxfmt",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "./module.ts",
|
||||
"dependencies": {
|
||||
"@stanza/codemods": "workspace:*",
|
||||
"@stanza/registry": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["module.ts"],
|
||||
"exclude": ["templates"]
|
||||
}
|
||||
Reference in New Issue
Block a user