# Cencori - LLM.txt Documentation > One API for every AI provider with built-in security, observability, and cost control. > Use this document to quickly integrate Cencori into your project. ## What is Cencori? Cencori is the unified AI infrastructure for production applications. Instead of integrating with OpenAI, Anthropic, and Google separately, you integrate once with Cencori and get: - **One SDK** for all providers (OpenAI, Anthropic, Google) - **Automatic security** - PII detection, prompt injection protection, content filtering - **Complete observability** - audit logs, analytics, cost tracking - **Multi-provider flexibility** - switch models with one parameter ## Quick Start ### 1. Install the SDK **JavaScript/TypeScript:** ```bash npm install cencori # or: yarn add cencori # or: pnpm add cencori ``` **Python:** ```bash pip install cencori ``` ### 2. Set Environment Variables ```bash # .env CENCORI_API_KEY=csk_your_secret_key_here # Server-side (csk_ prefix) ``` ### 3. Initialize the Client ```typescript // lib/cencori.ts import { Cencori } from "cencori"; export const cencori = new Cencori({ apiKey: process.env.CENCORI_API_KEY!, }); ``` ### 4. Make Your First Request ```typescript // app/api/chat/route.ts import { cencori } from "@/lib/cencori"; export async function POST(req: Request) { const { messages } = await req.json(); const response = await cencori.ai.chat({ model: "gpt-4o", // or "claude-3-opus", "gemini-2.5-flash" messages: messages, temperature: 0.7, maxTokens: 1000, }); return Response.json({ content: response.content, usage: response.usage, }); } ``` ## Vercel AI SDK Integration Using Vercel AI SDK? Install `@cencori/ai-sdk` for drop-in compatibility: ```bash npm install @cencori/ai-sdk ai ``` ```typescript // app/api/chat/route.ts import { cencori } from "@cencori/ai-sdk"; import { streamText } from "ai"; export async function POST(req: Request) { const { messages } = await req.json(); const result = await streamText({ model: cencori("gemini-2.5-flash"), messages, }); return result.toUIMessageStreamResponse(); } ``` Works with `streamText()`, `generateText()`, `useChat()`, and all Vercel AI SDK features. ## TanStack AI Integration Using TanStack AI? Install `@cencori/ai-sdk` with the TanStack subpath: ```bash npm install @cencori/ai-sdk @tanstack/ai ``` ```typescript import { cencori } from "@cencori/ai-sdk/tanstack"; const adapter = cencori("gpt-4o"); // Streaming for await (const chunk of adapter.chatStream({ messages: [{ role: "user", content: "Hello!" }] })) { if (chunk.type === "content") { console.log(chunk.delta); } } ``` Works with `chatStream()`, structured output, and all TanStack AI features. ## Tool Calling / Function Calling Cencori supports tool calling across all providers with a unified interface. ### Vercel AI SDK Tool Calling ```typescript import { cencori } from "@cencori/ai-sdk"; import { generateText, tool } from "ai"; import { z } from "zod"; const result = await generateText({ model: cencori("gpt-4o"), prompt: "What is the weather in San Francisco?", tools: { getWeather: tool({ description: "Get the current weather for a location", parameters: z.object({ location: z.string().describe("The city name"), }), execute: async ({ location }) => { return { temperature: 72, condition: "sunny" }; }, }), }, }); // Access tool calls for (const toolCall of result.toolCalls) { console.log(`Called ${toolCall.toolName} with args:`, toolCall.args); } ``` ### TanStack AI Tool Calling ```typescript import { cencori } from "@cencori/ai-sdk/tanstack"; const adapter = cencori("gpt-4o"); for await (const chunk of adapter.chatStream({ messages: [{ role: "user", content: "Get weather for NYC" }], tools: { getWeather: { name: "getWeather", description: "Get weather for a location", inputSchema: { type: "object", properties: { location: { type: "string" } } }, }, }, })) { if (chunk.type === "tool_call") { console.log("Tool call:", chunk.toolCall); // { id: "call_123", type: "function", function: { name: "getWeather", arguments: '{"location":"NYC"}' } } } } ## Chat API Reference ### Basic Usage ```typescript const response = await cencori.ai.chat({ model: "gpt-4o", messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: "Hello!" } ], temperature: 0.7, maxTokens: 1000, }); console.log(response.content); ``` **Python:** ```python from cencori import Cencori cencori = Cencori(api_key="your-api-key") response = cencori.ai.chat( messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"} ], model="gpt-4o", temperature=0.7, max_tokens=1000, ) print(response.content) ``` ### Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `model` | string | No | AI model (default: gemini-2.5-flash) | | `messages` | array | Yes | Conversation history with role and content | | `temperature` | number | No | Randomness (0-1) | | `maxTokens` | number | No | Max response tokens | | `userId` | string | No | User ID for rate limiting | ### Response Format ```typescript { content: "Hello! How can I help?", model: "gpt-4o", provider: "openai", usage: { prompt_tokens: 13, completion_tokens: 7, total_tokens: 20 }, cost_usd: 0.0003, finish_reason: "stop" } ``` ## Streaming Stream responses for better UX using `chatStream()`: ```typescript // Server route import { Cencori } from "cencori"; export async function POST(req: Request) { const { messages } = await req.json(); const cencori = new Cencori({ apiKey: process.env.CENCORI_API_KEY!, }); const stream = cencori.ai.chatStream({ model: "gpt-4o", messages, }); const encoder = new TextEncoder(); const readableStream = new ReadableStream({ async start(controller) { for await (const chunk of stream) { // chunk.delta contains the streamed text controller.enqueue(encoder.encode(chunk.delta)); } controller.close(); }, }); return new Response(readableStream, { headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", }, }); } ``` ### Stream Chunk Format ```typescript { delta: "Hello", // The text chunk finish_reason?: "stop", // Only on last chunk: 'stop' | 'length' | 'content_filter' | 'error' error?: "Rate limit exceeded" // Error message if stream failed } ``` ### Handling Stream Errors ```typescript for await (const chunk of stream) { // Check for errors in stream if (chunk.error) { console.error('Stream error:', chunk.error); break; } controller.enqueue(encoder.encode(chunk.delta)); } ``` Client-side streaming: ```typescript const res = await fetch('/api/chat', { method: 'POST', body: JSON.stringify({ messages }), }); const reader = res.body.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value); setResponse(prev => prev + chunk); } ``` ## Supported Models (14+ Providers) ### OpenAI | Model | Context | Description | |-------|---------|-------------| | `gpt-5` | 256K | Latest flagship model | | `gpt-4o` | 128K | Omni-modal model | | `gpt-4o-mini` | 128K | Fast and cost-effective | | `o3` | 200K | Most advanced reasoning | | `o1` | 128K | Advanced reasoning model | ### Anthropic | Model | Context | Description | |-------|---------|-------------| | `claude-opus-4` | 200K | Most capable Claude | | `claude-sonnet-4` | 200K | Balanced speed & capability | | `claude-3-5-sonnet` | 200K | Balance of speed and capability | | `claude-3-5-haiku` | 200K | Fast and efficient | ### Google Gemini | Model | Context | Description | |-------|---------|-------------| | `gemini-3-pro` | 2M | Most powerful Gemini | | `gemini-2.5-flash` | 1M | Thinking capabilities | | `gemini-2.0-flash` | 1M | Fast model | ### xAI (Grok) | Model | Context | Description | |-------|---------|-------------| | `grok-4` | 256K | Enhanced reasoning | | `grok-4.1` | 256K | Improved multimodal | | `grok-3` | 128K | DeepSearch, Big Brain Mode | ### Additional Providers - **Mistral**: mistral-large-3, codestral, devstral - **DeepSeek**: deepseek-v3.2, deepseek-reasoner - **Meta (Llama)**: llama-4-maverick, llama-3.3-70b - **Groq**: Fast inference for Llama models - **Cohere**: command-a, command-r+ - **Perplexity**: sonar-pro, sonar-reasoning-pro - **Together AI**: Access to 100+ open models - **OpenRouter**: Meta-provider for all models ### Model Selection Guide - **Chat/General**: `gemini-2.5-flash` (fast, cheap, good quality) - **Code**: `gpt-4o` or `codestral` (best coding) - **Reasoning**: `o3` or `deepseek-reasoner` - **Documents**: `claude-opus-4` (200K context, strong reasoning) - **Search**: `sonar-pro` (web-connected) ## Multi-Provider Switching Switch providers with one parameter: ```typescript // OpenAI await cencori.ai.chat({ model: "gpt-4o", messages }); // Anthropic await cencori.ai.chat({ model: "claude-3-opus", messages }); // Google await cencori.ai.chat({ model: "gemini-2.5-flash", messages }); ``` All responses have the same format regardless of provider! ## Agent Frameworks Cencori works with any OpenAI-compatible agent framework. Just point your `base_url` to Cencori: **Prerequisite:** Add your provider API keys (OpenAI, Anthropic, Google) in your Cencori project settings first. Cencori routes requests to providers using your keys. ### CrewAI ```bash export OPENAI_API_KEY=your_cencori_api_key export OPENAI_API_BASE=https://api.cencori.com/v1 ``` ```python from crewai import Agent, Task, Crew researcher = Agent(role='Research Analyst', goal='Find insights') crew = Crew(agents=[researcher], tasks=[...]) result = crew.kickoff() # Every LLM call logged in Cencori! ``` ### AutoGen ```python config_list = [{ "model": "gpt-4o", "api_key": "your_cencori_api_key", "base_url": "https://api.cencori.com/v1" }] assistant = AssistantAgent(name="assistant", llm_config={"config_list": config_list}) ``` ### LangChain ```python from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="gpt-4o", api_key="your_cencori_api_key", base_url="https://api.cencori.com/v1" ) ``` ### OpenAI SDK (Direct) ```python from openai import OpenAI client = OpenAI( api_key="your_cencori_api_key", base_url="https://api.cencori.com/v1" ) ``` **Benefits:** Full observability, automatic failover, rate limiting, security scanning for all agent calls. ## Provider Failover Cencori automatically handles provider failures: ### How It Works 1. Request fails → Retries with exponential backoff (up to 3 times) 2. Still failing → Routes to fallback provider (e.g., OpenAI → Anthropic) 3. Model mapping → GPT-5 → Claude Opus 4 (automatic equivalent) ### Circuit Breaker After 5 consecutive failures, provider is skipped entirely for 60 seconds. ### Fallback Response When fallback is used, response includes: ```typescript { content: "Hello!", model: "claude-opus-4", // Actual model used provider: "anthropic", // Actual provider fallback_used: true, // Indicates fallback was triggered original_model: "gpt-5", // What you requested original_provider: "openai" // Original provider } ``` ### Configuration Configure in Settings → Infrastructure: - **Enable fallback**: On/Off - **Fallback provider**: Preferred backup (e.g., Anthropic) - **Max retries**: Attempts before failover (default: 3) ## Error Handling ```typescript import { Cencori, SafetyError, RateLimitError, AuthenticationError } from "cencori"; try { const response = await cencori.ai.chat({ model: "gpt-4o", messages, }); return response; } catch (error) { if (error instanceof SafetyError) { // Request blocked (prompt injection, PII, harmful content) return { error: "Content blocked", reasons: error.reasons }; } if (error instanceof RateLimitError) { return { error: "Too many requests" }; } if (error instanceof AuthenticationError) { return { error: "Invalid API key" }; } throw error; } ``` ## Security Features Cencori automatically protects against: ### Prompt Injection Detects and blocks malicious inputs like: - "Ignore all previous instructions..." - "What is your system prompt?" - Jailbreak attempts ### PII Detection Scans for and filters: - Social Security Numbers - Credit card numbers - Email addresses - Phone numbers ### Content Filtering Blocks harmful content before it reaches AI providers. All security violations throw `SafetyError` with `reasons` array. ## Best Practices 1. **Set maxTokens** - Prevent unexpectedly long responses 2. **Include userId** - Enable per-user rate limiting 3. **Handle errors gracefully** - Use typed error classes 4. **Use chatStream() for chat UIs** - Better user experience 5. **Monitor token usage** - Check dashboard for costs 6. **Store API keys in env vars** - Never commit to version control 7. **Use system role for instructions** - Never concatenate with user input 8. **Use secret keys for servers** - Never expose `csk_` keys in client code 9. **Use publishable keys for browsers** - Use `cpk_` keys with domain whitelisting ## API Key Types Cencori supports two types of API keys: ### Secret Keys (`csk_`) - For **server-side use only** - Full access to all features - Never expose in browser or client code - Example: `csk_abc123...` ### Publishable Keys (`cpk_`) - Safe for **browser/client-side use** - Requires domain whitelisting - Only works from allowed domains - Example: `cpk_xyz789...` ### Legacy Keys (`cen_`) - Existing keys created before key types - Treated as secret keys - Still fully functional ## Dashboard After integration, visit your Cencori dashboard to see: - Request logs with full prompts and responses - Security incidents (blocked attacks) - Usage analytics and costs - Rate limit status ## Links - Dashboard: https://cencori.com - Full Docs: https://cencori.com/docs - Pricing: https://cencori.com/pricing