lukasa1993/tanstack-skills-extracted/tanstack-ai-core-adapter-configuration

Claude Code and agent skill by lukasa1993/tanstack-skills-extracted

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Provider adapter selection and configuration: openaiText, anthropicText, geminiText, ollamaText, grokText, groqText, openRouterText, bedrockText, byteplusText, openaiCompatible. Per-model type safety with modelOptions, reasoning/thinking configuration, runtime adapter switching, extendAdapter() for custom models, createModel(). Generic OpenAI-compatible providers (DeepSeek, Together, Fireworks, etc.) via openaiCompatible({ baseURL, apiKey, models }) from @tanstack/ai-openai/compatible. API key env vars: OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY/GEMINI_API_KEY, XAI_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY, OLLAMA_HOST, BEDROCK_API_KEY (or AWS_BEARER_TOKEN_BEDROCK). BytePlus needs TWO keys: ARK_API_KEY (ModelArk — chat/video/image) and BYTEPLUS_VOICE_API_KEY (Seed Speech — TTS/transcription); neither is a fallback for the other.

Install

npx vskill@latest install lukasa1993/tanstack-skills-extracted/tanstack-ai-core-adapter-configuration

SKILL.md

Adapter Configuration

Dependency: This skill builds on ai-core. Read it first for critical rules.
Before implementing: Ask the user which provider and model they want.
Then fetch the latest available models from the provider's source code
(check the adapter's model metadata file, e.g. packages/ai-openai/src/model-meta.ts)
or from the provider's API/docs to recommend the most current model.
The model lists in this skill and its reference files may be outdated.
Always verify against the source before recommending a specific model.

Setup

Create an adapter and use it with chat():

typescript
import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
export async function POST(request: Request) {
const { messages, threadId } = await request.json()
const stream = chat({
adapter: openaiText('gpt-5.2'),
messages,
threadId,
modelOptions: {
temperature: 0.7,
max_output_tokens: 1000,
},
})
return toServerSentEventsResponse(stream)
}

The adapter factory function takes the model name as a string literal and an optional config object (API key, base URL, etc.). The model name is passed into the factory, not into chat().

Sampling options (temperature, token limits, top_p/topP, etc.) live inside modelOptions using each provider's native key — they are not top-level options on chat(). See the per-provider table in Configuring Sampling below.

Core Patterns

1. Adapter Selection

Each provider has a dedicated package with tree-shakeable adapter factories. The text adapter is the primary one for chat/completions:

ProviderPackageFactoryEnv Var
OpenAI@tanstack/ai-openaiopenaiTextOPENAI_API_KEY
Anthropic@tanstack/ai-anthropicanthropicTextANTHROPIC_API_KEY
Gemini@tanstack/ai-geminigeminiTextGOOGLE_API_KEY or GEMINI_API_KEY
Grok (xAI)@tanstack/ai-grokgrokTextXAI_API_KEY
Groq@tanstack/ai-groqgroqTextGROQ_API_KEY
OpenRouter@tanstack/ai-openrouteropenRouterTextOPENROUTER_API_KEY
Ollama@tanstack/ai-ollamaollamaTextOLLAMA_HOST (default: http://localhost:11434)
Bedrock@tanstack/ai-bedrockbedrockTextBEDROCK_API_KEY or AWS_BEARER_TOKEN_BEDROCK
BytePlus@tanstack/ai-byteplusbyteplusTextARK_API_KEY (falls back to BYTEPLUS_API_KEY)
OpenAI-compatible@tanstack/ai-openai/compatibleopenaiCompatible / openaiCompatibleTextprovider-specific (passed via apiKey)
Cloudflare@tanstack/ai-cloudflarecloudflareTextCLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN, or { binding: env.AI } in a Worker
Neon AI Gateway@tanstack/ai-neonneonTextNEON_AI_GATEWAY_TOKEN + NEON_AI_GATEWAY_BASE_URL (branch host)
BytePlus uses two keys. byteplusText / byteplusVideo /
byteplusImage read ARK_API_KEY (ModelArk, Authorization: Bearer), but
byteplusSpeech / byteplusTranscription are a separate product and read
`BYTEPLUS_VOICE_API_KEY` (Seed Speech, X-Api-Key). Ark keys are also
region-isolated — the default base URL is the ap-southeast endpoint.
typescript
// Each factory takes model as first arg, optional config as second
import { openaiText, createOpenaiChat } from '@tanstack/ai-openai'
import { anthropicText } from '@tanstack/ai-anthropic'
import { geminiText } from '@tanstack/ai-gemini'
import { grokText } from '@tanstack/ai-grok'
import { groqText } from '@tanstack/ai-groq'
import { openRouterText } from '@tanstack/ai-openrouter'
import { ollamaText } from '@tanstack/ai-ollama'
import { bedrockText } from '@tanstack/ai-bedrock'
import { byteplusText } from '@tanstack/ai-byteplus'
// Model string is passed to the factory, NOT to chat()
const adapter = openaiText('gpt-5.2')
const adapter2 = anthropicText('claude-sonnet-4-6')
const adapter3 = geminiText('gemini-2.5-pro')
const adapter4 = grokText('grok-4.6')
const adapter5 = groqText('openai/gpt-oss-120b')
const adapter6 = openRouterText('anthropic/claude-sonnet-5.5')
const adapter7 = ollamaText('llama3.3:latest')
const adapter8 = bedrockText('us.anthropic.claude-3-7-sonnet-20250219-v1:0')
const adapter9 = byteplusText('seed-2-0-lite-260428')
// Optional: pass an explicit API key via the create* sibling
// (the plain factory reads it from the environment)
const adapterWithKey = createOpenaiChat('gpt-5.2', 'sk-...')

@tanstack/ai-bedrock (Amazon Bedrock) branches on config.api:

  • bedrockText(model) or bedrockText(model, { api: 'converse' }) (the default) — Bedrock's native Converse API via @aws-sdk/client-bedrock-runtime (adapter name bedrock-converse). Reaches the broad catalog: Claude, Nova, Llama, Mistral, DeepSeek, and more.
  • bedrockText(model, { api: 'chat' }) — OpenAI-compatible Chat Completions endpoint (adapter name bedrock). Open-weight models only (gpt-oss, DeepSeek V3.x, Gemma, Qwen, etc.). Does NOT reach Claude, Nova, or Llama.
  • bedrockText(model, { api: 'responses' }) — OpenAI-compatible Responses API, mantle-only (adapter name bedrock-responses). Currently gpt-oss and Gemma 4.

Use createBedrockText(model, apiKey, config?) to pass the key explicitly. Auth resolves from BEDROCK_API_KEY / AWS_BEARER_TOKEN_BEDROCK, or SigV4 via the standard AWS credential chain (no extra packages needed — handled by @aws-sdk/client-bedrock-runtime).

2. Runtime Adapter Switching

Use an adapter factory map to switch providers dynamically based on user input or configuration:

typescript
import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import type { ModelMessage } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { anthropicText } from '@tanstack/ai-anthropic'
import { geminiText } from '@tanstack/ai-gemini'
// Define a map of provider+model to adapter factory calls
const adapters = {
'openai/gpt-5.2': () => openaiText('gpt-5.2'),
'anthropic/claude-sonnet-4-6': () => anthropicText('claude-sonnet-4-6'),
'gemini/gemini-2.5-pro': () => geminiText('gemini-2.5-pro'),
}
function isKnownProviderModel(key: string): key is keyof typeof adapters {
return key in adapters
}
export function handleChat(
providerModel: string,
messages: Array<ModelMessage>,
// The conversation id from the request. Never share one across users.
threadId: string,
) {
if (!isKnownProviderModel(providerModel)) {
throw new Error(`Unknown provider/model: ${providerModel}`)
}
const stream = chat({
adapter: adapters[providerModel](),
messages,
threadId,
})
return toServerSentEventsResponse(stream)
}
3. Configuring Reasoning / Thinking

Set reasoning/thinking with the reasoning option on chat(). It is the same on every provider, and the types take only the levels of the selected model:

typescript
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { anthropicText } from '@tanstack/ai-anthropic'
import { geminiText } from '@tanstack/ai-gemini'
const messages = [
{ role: 'user' as const, content: 'Plan a database migration.' },
]
// OpenAI: the level goes out as reasoning.effort, with a summary
const openaiStream = chat({
adapter: openaiText('gpt-5.2'),
messages,
threadId: 'thread-1',
reasoning: { level: 'high', summary: true },
})
// Anthropic: extended thinking with a token budget
const anthropicStream = chat({
adapter: anthropicText('claude-sonnet-4-6'),
messages,
threadId: 'thread-1',
modelOptions: { max_tokens: 16000 },
reasoning: { level: 'high', budgetTokens: 8000 },
})
// Anthropic: adaptive thinking (Sonnet 5, Fable 5, Opus 4.7+) — the level
// goes out as output_config.effort
const adaptiveStream = chat({
adapter: anthropicText('claude-sonnet-5'),
messages,
threadId: 'thread-1',
modelOptions: { max_tokens: 16000 },
reasoning: 'high', // 'low' | 'medium' | 'high' | 'xhigh' | 'max'
})
// Gemini: a thinking budget on Gemini 2.5, a thinking level on Gemini 3
const geminiStream = chat({
adapter: geminiText('gemini-2.5-pro'),
messages,
threadId: 'thread-1',
reasoning: { level: 'high', budgetTokens: 4096 },
})
4. Extending Adapters with Custom Models

Use extendAdapter() and createModel() to add custom or fine-tuned models while preserving type safety for the original models:

typescript
import { extendAdapter, createModel } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
// Define custom models
const customModels = [
createModel('ft:gpt-5.2:my-org:custom-model:abc123', ['text', 'image']),
createModel('my-local-proxy-model', ['text']),
] as const
// Create extended factory - original models still fully typed
const myOpenai = extendAdapter(openaiText, customModels)
// Use original models - full type inference preserved
const gpt5 = myOpenai('gpt-5.2')
// Use custom models - accepted by the type system
const custom = myOpenai('ft:gpt-5.2:my-org:custom-model:abc123')
// Type error: 'nonexistent-model' is not a valid model
// myOpenai('nonexistent-model')

At runtime, extendAdapter simply passes through to the original factory. The _customModels parameter is only used for type inference.

5. Configuring Sampling

Sampling controls (temperature, token limits, nucleus sampling) are passed inside modelOptions using each provider's native key. They are not top-level fields on chat()/ai()/generate().

typescript
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { anthropicText } from '@tanstack/ai-anthropic'
import { geminiText } from '@tanstack/ai-gemini'
import { ollamaText } from '@tanstack/ai-ollama'
const messages = [{ role: 'user' as const, content: 'Hello' }]
// OpenAI — native keys
chat({
adapter: openaiText('gpt-5.2'),
messages,
threadId: 'thread-1',
modelOptions: { temperature: 0.7, top_p: 0.9, max_output_tokens: 1000 },
})
// Anthropic
chat({
adapter: anthropicText('claude-sonnet-4-6'),
messages,
threadId: 'thread-1',
modelOptions: { temperature: 0.7, top_p: 0.9, max_tokens: 1000 },
})
// Gemini — camelCase
chat({
adapter: geminiText('gemini-2.5-pro'),
messages,
threadId: 'thread-1',
modelOptions: { temperature: 0.7, topP: 0.9, maxOutputTokens: 1000 },
})

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/lukasa1993/tanstack-skills-extracted/tanstack-ai-core-adapter-configuration/badge)](https://verified-skill.com/skills/lukasa1993/tanstack-skills-extracted/tanstack-ai-core-adapter-configuration)

Something wrong with this skill or its page? Tell us.