.do

ai - AI Operations

Complete guide to AI operations in MCP.do - text generation, structured output, embeddings, and batch processing with support for multiple models including GPT-5, Claude Sonnet 4.5, Llama 4, Grok 4, and Gemini 2.5 Pro

ai - AI Operations

The ai primitive provides AI generation, embeddings, and batch processing capabilities through a unified interface. It supports multiple state-of-the-art models and enables both free-form text generation and structured output via JSON schemas.

Overview

The AI primitive is designed for:

  • Text Generation: Generate natural language content with precise control
  • Structured Output: Extract or generate data conforming to specific schemas
  • Embeddings: Create vector representations for semantic search
  • Batch Processing: Process multiple AI requests efficiently
  • Dynamic Methods: Type-safe generation using ai.generate${Noun}() pattern
  • Semantic Integration: Native support for Schema.org types via $

Architecture

graph TB AI[ai Primitive] RPC[RPC Client] WORKER[AI Worker] MODELS[Model Providers] AI -->|generate| RPC AI -->|embed| RPC AI -->|batch| RPC AI -->|generate${Noun}| RPC RPC -->|HTTP/RPC| WORKER WORKER -->|GPT-5| MODELS WORKER -->|Claude 4.5| MODELS WORKER -->|Llama 4| MODELS WORKER -->|Grok 4| MODELS WORKER -->|Gemini 2.5| MODELS

Type Signatures

interface AI {
  // Generate text
  generate(options: GenerateOptions): Promise<GenerateResult>

  // Generate structured output
  generate<T>(options: GenerateOptions & { schema: Record<string, unknown> }): Promise<GenerateResult & { data: T }>

  // Chat completion
  chat(options: ChatOptions): Promise<ChatResult>

  // Generate embeddings
  embed(text: string | string[], options?: EmbedOptions): Promise<number[][]>

  // Batch processing
  batch(requests: AIRequest[]): Promise<BatchResult>
}

// Enhanced AI with dynamic methods
type AIWithDynamicMethods = AI & {
  [key: `generate${string}`]: <T = unknown>(options: Omit<GenerateOptions, 'schema'>) => Promise<T>
}

interface GenerateOptions {
  prompt: string
  model?: string
  maxTokens?: number
  temperature?: number
  topP?: number
  frequencyPenalty?: number
  presencePenalty?: number
  stop?: string[]
  schema?: Record<string, unknown>
}

interface GenerateResult {
  text: string
  data?: unknown
  model: string
  usage: {
    promptTokens: number
    completionTokens: number
    totalTokens: number
  }
  finishReason: 'stop' | 'length' | 'content_filter' | 'tool_calls'
}

interface ChatOptions {
  messages: ChatMessage[]
  model?: string
  maxTokens?: number
  temperature?: number
  stream?: boolean
}

interface ChatMessage {
  role: 'system' | 'user' | 'assistant'
  content: string
}

interface EmbedOptions {
  model?: string
  dimensions?: number
}

interface AIRequest {
  type: 'generate' | 'chat' | 'embed'
  payload: GenerateOptions | ChatOptions | { text: string | string[]; options?: EmbedOptions }
  id?: string
}

interface BatchResult {
  results: Array<GenerateResult | ChatResult | { embeddings: number[][] }>
  errors: Array<{ id?: string; error: string }>
}

Supported Models

The AI worker provides access to the latest generation of AI models:

ModelIDBest ForContextNotes
GPT-5gpt-5General purpose, reasoning128KDefault model, best overall
Claude Sonnet 4.5claude-sonnet-4.5Writing, analysis, code200KExcellent for technical content
Llama 4llama-4Open source, privacy32KSelf-hosted option
Grok 4grok-4Real-time data, reasoning128KTwitter/X integration
Gemini 2.5 Progemini-2.5-proMultimodal, long context1MBest for large documents

Deprecated Models

The following models are deprecated and will be removed in a future release:

  • gpt-4* (use gpt-5)
  • claude-3.5* (use claude-sonnet-4.5)

Basic Text Generation

Simple Text Generation

Generate free-form text content:

const result = await ai.generate({
  prompt: 'Write a product description for a smart coffee maker',
  model: 'gpt-5',
})

console.log(result.text)
// "Introducing the SmartBrew 3000, a revolutionary coffee maker that..."

console.log(result.usage)
// { promptTokens: 12, completionTokens: 150, totalTokens: 162 }

With Generation Parameters

Control output characteristics:

const result = await ai.generate({
  prompt: 'Write a creative story about a time-traveling scientist',
  model: 'claude-sonnet-4.5',
  maxTokens: 1000,
  temperature: 0.9, // Higher = more creative
  topP: 0.95, // Nucleus sampling
  frequencyPenalty: 0.5, // Reduce repetition
  presencePenalty: 0.3, // Encourage topic diversity
  stop: ['THE END', '\n\n\n'], // Stop sequences
})

console.log(result.text)
console.log(`Finish reason: ${result.finishReason}`)

Model Selection Strategy

// For factual content - use GPT-5
const factual = await ai.generate({
  prompt: 'Explain quantum computing in simple terms',
  model: 'gpt-5',
  temperature: 0.3, // Lower temperature for accuracy
})

// For creative writing - use Claude
const creative = await ai.generate({
  prompt: 'Write a poem about artificial intelligence',
  model: 'claude-sonnet-4.5',
  temperature: 0.8, // Higher temperature for creativity
})

// For long documents - use Gemini
const longContext = await ai.generate({
  prompt: `Summarize this document: ${largeDocument}`,
  model: 'gemini-2.5-pro',
  maxTokens: 2000,
})

Structured Output

Basic Structured Generation

Generate data conforming to a schema:

import { z } from 'zod'

// Define schema
const ProductSchema = z.object({
  name: z.string(),
  price: z.number(),
  description: z.string(),
  features: z.array(z.string()),
  category: z.enum(['electronics', 'clothing', 'food', 'other']),
})

// Generate with schema
const result = await ai.generate({
  prompt: 'Generate a product for a wireless keyboard',
  schema: ProductSchema,
  model: 'gpt-5',
})

// Type-safe access to structured data
console.log(result.data.name) // Type: string
console.log(result.data.price) // Type: number
console.log(result.data.features) // Type: string[]

Complex Nested Schemas

Generate complex structured data:

import { z } from 'zod'

const CompanySchema = z.object({
  name: z.string(),
  industry: z.string(),
  employees: z.number(),
  founded: z.number(),
  headquarters: z.object({
    city: z.string(),
    country: z.string(),
    address: z.string(),
  }),
  products: z.array(
    z.object({
      name: z.string(),
      description: z.string(),
      price: z.number(),
      launched: z.number(),
    })
  ),
  leadership: z.array(
    z.object({
      name: z.string(),
      title: z.string(),
      bio: z.string(),
    })
  ),
})

const company = await ai.generate({
  prompt: 'Generate a fictional tech startup in the AI space',
  schema: CompanySchema,
  model: 'gpt-5',
})

console.log(company.data.name)
console.log(company.data.products[0].name)
console.log(company.data.leadership[0].title)

Data Extraction

Extract structured data from unstructured text:

const EmailSchema = z.object({
  from: z.string().email(),
  to: z.array(z.string().email()),
  subject: z.string(),
  date: z.string(),
  summary: z.string(),
  actionItems: z.array(
    z.object({
      task: z.string(),
      assignee: z.string().optional(),
      dueDate: z.string().optional(),
    })
  ),
  sentiment: z.enum(['positive', 'neutral', 'negative']),
})

const emailText = `
From: [email protected]
To: [email protected], [email protected]
Subject: Q4 Planning Meeting

Hi team,

Let's schedule our Q4 planning meeting for next Tuesday at 2pm.
Bob - can you prepare the budget analysis?
Carol - please review the market research data.

Looking forward to a productive session!
Alice
`

const extracted = await ai.generate({
  prompt: `Extract structured data from this email:\n\n${emailText}`,
  schema: EmailSchema,
  model: 'gpt-5',
})

console.log(extracted.data.actionItems)
// [
//   { task: 'Prepare budget analysis', assignee: 'Bob', dueDate: 'Next Tuesday' },
//   { task: 'Review market research data', assignee: 'Carol', dueDate: undefined }
// ]

Dynamic Generate Methods

Using Registered Schemas

The AI primitive supports dynamic generate${Noun}() methods for registered schemas:

import { registerSchema, ai } from 'sdk.do'
import { z } from 'zod'

// Register a schema
registerSchema(
  'Recipe',
  z.object({
    name: z.string(),
    ingredients: z.array(
      z.object({
        item: z.string(),
        amount: z.string(),
      })
    ),
    instructions: z.array(z.string()),
    cookTime: z.string(),
    servings: z.number(),
  })
)

// Now use the dynamic method
const recipe = await ai.generateRecipe({
  prompt: 'Generate a recipe for chocolate chip cookies',
})

// Returns just the data (no wrapper)
console.log(recipe.name) // Type: string
console.log(recipe.ingredients) // Type: Array<{item: string, amount: string}>
console.log(recipe.instructions) // Type: string[]

Built-in Schema.org Types

Several Schema.org types are pre-registered:

// Person
const person = await ai.generatePerson({
  prompt: 'Generate a fictional software engineer profile',
})
console.log(person.name)
console.log(person.email)
console.log(person.jobTitle)

// Organization
const org = await ai.generateOrganization({
  prompt: 'Generate a tech startup profile',
})
console.log(org.name)
console.log(org.description)
console.log(org.address)

// Product
const product = await ai.generateProduct({
  prompt: 'Generate a SaaS product',
})
console.log(product.name)
console.log(product.offers.price)

// Article
const article = await ai.generateArticle({
  prompt: 'Write an article about remote work',
})
console.log(article.headline)
console.log(article.author)
console.log(article.datePublished)

// Event
const event = await ai.generateEvent({
  prompt: 'Create a tech conference event',
})
console.log(event.name)
console.log(event.startDate)
console.log(event.location)

Custom Namespace Registration

Register multiple schemas at once:

import { registerNamespace } from 'sdk.do'
import { z } from 'zod'

registerNamespace('ecommerce', {
  Cart: z.object({
    items: z.array(
      z.object({
        productId: z.string(),
        quantity: z.number(),
        price: z.number(),
      })
    ),
    total: z.number(),
    customerId: z.string(),
  }),

  Order: z.object({
    orderId: z.string(),
    customerId: z.string(),
    items: z.array(z.any()),
    total: z.number(),
    status: z.enum(['pending', 'processing', 'shipped', 'delivered']),
    shippingAddress: z.object({
      street: z.string(),
      city: z.string(),
      state: z.string(),
      zip: z.string(),
    }),
  }),
})

// Use with both plain and namespaced names
const cart = await ai.generateCart({ prompt: '...' })
const cart2 = await ai.generateEcommerceCart({ prompt: '...' })

const order = await ai.generateOrder({ prompt: '...' })
const order2 = await ai.generateEcommerceOrder({ prompt: '...' })

Integration with $ (Semantic Types)

Using Semantic Schemas

Combine AI generation with semantic types:

import { $, ai, db } from 'sdk.do'

// Generate semantic entity
const business = await ai.generate({
  prompt: 'Generate a coffee shop business',
  schema: $.Business, // Use semantic schema
})

// Store in database
const saved = await db.create('Business', business.data)

// Create relationships
await db.relate({ type: 'Business', id: saved.id }, 'offers', { type: 'Product', id: product.id })

Event-Driven AI Generation

import { $, ai, on, send } from 'sdk.do'

// Generate content when orders are created
on($.Order.created, async (order) => {
  // Generate personalized thank you email
  const email = await ai.generate({
    prompt: `Write a thank you email for customer who ordered: ${order.items.map((i) => i.name).join(', ')}`,
    schema: $.Email,
  })

  // Send email
  await send($.Email.send, {
    to: order.customer.email,
    subject: email.data.subject,
    body: email.data.body,
  })
})

Embeddings

Basic Embeddings

Generate vector embeddings for semantic search:

// Single text
const embedding = await ai.embed('Hello world')
console.log(embedding)
// [[0.123, -0.456, 0.789, ...]]  // 1536 dimensions

// Multiple texts
const embeddings = await ai.embed(['First document', 'Second document', 'Third document'])
console.log(embeddings.length) // 3
console.log(embeddings[0].length) // 1536

Semantic Search Implementation

import { ai, db } from 'sdk.do'

// Index documents
async function indexDocuments(documents: Array<{ id: string; text: string }>) {
  // Generate embeddings
  const texts = documents.map((d) => d.text)
  const embeddings = await ai.embed(texts)

  // Store with embeddings
  for (let i = 0; i < documents.length; i++) {
    await db.create('Document', {
      id: documents[i].id,
      text: documents[i].text,
      embedding: embeddings[i],
    })
  }
}

// Search documents
async function searchDocuments(query: string, limit: number = 10) {
  // Generate query embedding
  const [queryEmbedding] = await ai.embed(query)

  // Find similar documents (using cosine similarity)
  const documents = await db.list('Document', { limit: 100 })

  const results = documents.map((doc) => ({
    ...doc,
    similarity: cosineSimilarity(queryEmbedding, doc.embedding),
  }))

  return results.sort((a, b) => b.similarity - a.similarity).slice(0, limit)
}

function cosineSimilarity(a: number[], b: number[]): number {
  const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0)
  const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0))
  const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0))
  return dotProduct / (magnitudeA * magnitudeB)
}

Custom Embedding Dimensions

// Smaller embeddings for performance
const smallEmbedding = await ai.embed('Hello world', {
  dimensions: 256, // vs default 1536
})

// Use smaller model
const embedding = await ai.embed('Hello world', {
  model: 'text-embedding-3-small',
})

Chat Completions

Multi-Turn Conversations

const result = await ai.chat({
  messages: [
    { role: 'system', content: 'You are a helpful coding assistant' },
    { role: 'user', content: 'How do I sort an array in JavaScript?' },
    { role: 'assistant', content: 'You can use the .sort() method...' },
    { role: 'user', content: 'What about sorting objects by a property?' },
  ],
  model: 'gpt-5',
})

console.log(result.message.content)
console.log(result.usage)

Building Conversational Agents

class ChatAgent {
  private history: ChatMessage[] = []

  constructor(systemPrompt: string) {
    this.history.push({
      role: 'system',
      content: systemPrompt,
    })
  }

  async chat(userMessage: string): Promise<string> {
    // Add user message
    this.history.push({
      role: 'user',
      content: userMessage,
    })

    // Get response
    const result = await ai.chat({
      messages: this.history,
      model: 'claude-sonnet-4.5',
      maxTokens: 500,
    })

    // Add assistant response to history
    this.history.push(result.message)

    return result.message.content
  }

  reset() {
    this.history = this.history.slice(0, 1) // Keep system prompt
  }
}

// Usage
const agent = new ChatAgent('You are a helpful business advisor')
const response1 = await agent.chat('How do I start a business?')
const response2 = await agent.chat('What about funding?')

Batch Processing

Parallel AI Requests

Process multiple AI requests efficiently:

const results = await ai.batch([
  {
    type: 'generate',
    payload: {
      prompt: 'Write a product slogan',
      maxTokens: 50,
    },
    id: 'slogan',
  },
  {
    type: 'generate',
    payload: {
      prompt: 'Write a product tagline',
      maxTokens: 30,
    },
    id: 'tagline',
  },
  {
    type: 'embed',
    payload: {
      text: 'Product description text',
    },
    id: 'embedding',
  },
])

console.log(results.results[0]) // Slogan result
console.log(results.results[1]) // Tagline result
console.log(results.results[2]) // Embedding result

// Check for errors
if (results.errors.length > 0) {
  console.error('Failed requests:', results.errors)
}

Bulk Content Generation

import { ai } from 'sdk.do'

async function generateProductDescriptions(products: Array<{ name: string; features: string[] }>) {
  const requests = products.map((product, index) => ({
    type: 'generate' as const,
    payload: {
      prompt: `Write a compelling product description for ${product.name} with features: ${product.features.join(', ')}`,
      maxTokens: 200,
    },
    id: `product-${index}`,
  }))

  const results = await ai.batch(requests)

  return results.results.map((result, index) => ({
    productName: products[index].name,
    description: (result as GenerateResult).text,
  }))
}

const descriptions = await generateProductDescriptions([
  { name: 'Smart Watch', features: ['Heart rate monitor', 'GPS', 'Waterproof'] },
  { name: 'Wireless Earbuds', features: ['Noise canceling', '20hr battery', 'Touch controls'] },
  { name: 'Fitness Tracker', features: ['Sleep tracking', 'Step counter', '7-day battery'] },
])

Mixed Request Types

// Generate and embed in one batch
const batch = await ai.batch([
  {
    type: 'generate',
    payload: {
      prompt: 'Summarize quarterly earnings',
      maxTokens: 200,
      schema: { summary: 'string', keyPoints: 'array' },
    },
  },
  {
    type: 'embed',
    payload: {
      text: ['Document 1 text', 'Document 2 text', 'Document 3 text'],
    },
  },
  {
    type: 'chat',
    payload: {
      messages: [{ role: 'user', content: 'What is the capital of France?' }],
    },
  },
])

Readonly vs Authenticated Mode

Readonly Mode (Anonymous)

AI generation requires authentication due to computational costs:

// ❌ Will fail - requires authentication
const result = await ai.generate({
  prompt: 'Hello world',
})
// Error: AuthenticationError - AI generation requires authentication

Embeddings Are Readonly

Embeddings are available to anonymous users:

// ✅ Works without authentication
const embedding = await ai.embed('Search query text')

Authenticated Mode

import { configure, ai } from 'sdk.do'

// Configure with API key
configure({
  apiKey: process.env.API_KEY,
})

// ✅ Now works
const result = await ai.generate({
  prompt: 'Write a story',
})

Cost Optimization Strategies

Choose Appropriate Models

// Expensive: GPT-5 for simple task
const expensive = await ai.generate({
  prompt: 'Capitalize this: hello world',
  model: 'gpt-5', // Overkill
})

// Optimized: Smaller model
const optimized = await ai.generate({
  prompt: 'Capitalize this: hello world',
  model: 'gpt-3.5-turbo', // Sufficient
})

Limit Token Usage

// Set appropriate maxTokens
const result = await ai.generate({
  prompt: 'Write a one-sentence summary of quantum computing',
  maxTokens: 50, // Prevent over-generation
  temperature: 0.3, // More focused output
})
// Inefficient: Multiple separate calls
const slogan = await ai.generate({ prompt: 'Write a slogan' })
const tagline = await ai.generate({ prompt: 'Write a tagline' })
const description = await ai.generate({ prompt: 'Write a description' })

// Efficient: Single batch call
const results = await ai.batch([
  { type: 'generate', payload: { prompt: 'Write a slogan' } },
  { type: 'generate', payload: { prompt: 'Write a tagline' } },
  { type: 'generate', payload: { prompt: 'Write a description' } },
])

Cache Embeddings

import { ai, db } from 'sdk.do'

async function getOrCreateEmbedding(text: string): Promise<number[]> {
  // Check cache
  const cached = await db.get('Embedding', text)
  if (cached) {
    return cached.vector
  }

  // Generate and cache
  const [vector] = await ai.embed(text)
  await db.create('Embedding', {
    id: text,
    vector,
    createdAt: new Date(),
  })

  return vector
}

Performance Considerations

Parallel Generation

// Sequential: Slow
const result1 = await ai.generate({ prompt: 'Task 1' })
const result2 = await ai.generate({ prompt: 'Task 2' })
const result3 = await ai.generate({ prompt: 'Task 3' })

// Parallel: Fast (use batch or Promise.all)
const [result1, result2, result3] = await Promise.all([ai.generate({ prompt: 'Task 1' }), ai.generate({ prompt: 'Task 2' }), ai.generate({ prompt: 'Task 3' })])

// Batch: Even better
const results = await ai.batch([
  { type: 'generate', payload: { prompt: 'Task 1' } },
  { type: 'generate', payload: { prompt: 'Task 2' } },
  { type: 'generate', payload: { prompt: 'Task 3' } },
])

Streaming for UX

// Non-streaming: Wait for complete response
const result = await ai.generate({
  prompt: 'Write a long article',
  maxTokens: 2000,
})
// User waits 20-30 seconds

// Streaming: Progressive updates
const result = await ai.chat({
  messages: [{ role: 'user', content: 'Write a long article' }],
  stream: true,
})
// User sees text appear progressively

Timeout Handling

import { ai, isSDKError } from 'sdk.do'

try {
  const result = await ai.generate({
    prompt: 'Write a very long document',
    maxTokens: 4000,
    model: 'gpt-5',
  })
} catch (error) {
  if (isSDKError(error) && error.code === 'NetworkError') {
    console.error('Request timeout - try smaller maxTokens or different model')
  }
  throw error
}

Common Pitfalls

Schema Mismatch

// ❌ Wrong: Schema doesn't match expected output
const result = await ai.generate({
  prompt: 'Generate a person',
  schema: z.object({
    name: z.number(), // Wrong type!
    age: z.string(), // Wrong type!
  }),
})
// May fail or return unexpected results

// ✅ Correct: Schema matches semantic meaning
const result = await ai.generate({
  prompt: 'Generate a person',
  schema: z.object({
    name: z.string(),
    age: z.number(),
  }),
})

Overly Restrictive Schemas

// ❌ Too restrictive: Enum limits creativity
const result = await ai.generate({
  prompt: 'Generate creative business ideas',
  schema: z.object({
    category: z.enum(['tech', 'retail']), // Only 2 options!
  }),
})

// ✅ Better: Open string with validation
const result = await ai.generate({
  prompt: 'Generate creative business ideas',
  schema: z.object({
    category: z.string().min(1),
  }),
})

Prompt Engineering Issues

// ❌ Vague prompt
const result = await ai.generate({
  prompt: 'Write something',
})

// ✅ Specific prompt
const result = await ai.generate({
  prompt: 'Write a 100-word product description for a wireless keyboard targeting software developers, emphasizing productivity features',
})

Token Limit Errors

// ❌ Prompt + response exceeds model context
const result = await ai.generate({
  prompt: veryLongDocument, // 100K tokens
  maxTokens: 4000, // Total: 104K tokens
  model: 'gpt-5', // Context: 128K tokens - OK
})

// But with smaller model:
const result = await ai.generate({
  prompt: veryLongDocument, // 100K tokens
  maxTokens: 4000,
  model: 'llama-4', // Context: 32K tokens - FAILS!
})

// ✅ Use model with sufficient context

Not Handling Errors

// ❌ No error handling
const result = await ai.generate({ prompt: 'Hello' })

// ✅ Proper error handling
try {
  const result = await ai.generate({ prompt: 'Hello' })
} catch (error) {
  if (isSDKError(error)) {
    if (error.code === 'RateLimitError') {
      // Wait and retry
    } else if (error.code === 'AuthenticationError') {
      // Check API key
    }
  }
  throw error
}

Advanced Examples

Multi-Step AI Workflow

import { ai, db } from 'sdk.do'

async function analyzeCompetitor(url: string) {
  // Step 1: Fetch website content
  const content = await fetch(url).then((r) => r.text())

  // Step 2: Extract company info
  const company = await ai.generate({
    prompt: `Extract company information from this website:\n${content}`,
    schema: z.object({
      name: z.string(),
      description: z.string(),
      products: z.array(z.string()),
      targetMarket: z.string(),
    }),
  })

  // Step 3: Generate competitive analysis
  const analysis = await ai.generate({
    prompt: `Analyze this competitor:\n${JSON.stringify(company.data, null, 2)}`,
    schema: z.object({
      strengths: z.array(z.string()),
      weaknesses: z.array(z.string()),
      opportunities: z.array(z.string()),
      threats: z.array(z.string()),
    }),
  })

  // Step 4: Generate strategic recommendations
  const strategy = await ai.generate({
    prompt: `Based on this competitive analysis, suggest strategies:\n${JSON.stringify(analysis.data, null, 2)}`,
    schema: z.object({
      recommendations: z.array(
        z.object({
          title: z.string(),
          description: z.string(),
          priority: z.enum(['high', 'medium', 'low']),
          timeframe: z.string(),
        })
      ),
    }),
  })

  // Step 5: Store results
  return await db.create('CompetitiveAnalysis', {
    url,
    company: company.data,
    analysis: analysis.data,
    strategy: strategy.data,
    analyzedAt: new Date(),
  })
}

Content Moderation Pipeline

async function moderateContent(text: string) {
  const moderation = await ai.generate({
    prompt: `Analyze this content for safety:\n\n${text}`,
    schema: z.object({
      safe: z.boolean(),
      categories: z.object({
        hate: z.number().min(0).max(1),
        violence: z.number().min(0).max(1),
        sexual: z.number().min(0).max(1),
        harassment: z.number().min(0).max(1),
      }),
      reasoning: z.string(),
    }),
    temperature: 0.1, // Low temperature for consistency
  })

  return moderation.data
}

RAG (Retrieval Augmented Generation)

import { ai, db } from 'sdk.do'

async function answerQuestion(question: string) {
  // Generate question embedding
  const [questionEmbedding] = await ai.embed(question)

  // Find relevant documents
  const documents = await db.list('Document', { limit: 100 })
  const relevant = documents
    .map((doc) => ({
      ...doc,
      similarity: cosineSimilarity(questionEmbedding, doc.embedding),
    }))
    .sort((a, b) => b.similarity - a.similarity)
    .slice(0, 5)

  // Generate answer with context
  const context = relevant.map((d) => d.text).join('\n\n')
  const answer = await ai.generate({
    prompt: `Answer this question based on the context:

Context:
${context}

Question: ${question}

Answer:`,
    model: 'gpt-5',
    temperature: 0.3,
  })

  return {
    answer: answer.text,
    sources: relevant.map((d) => ({ id: d.id, title: d.title })),
  }
}

Cross-References

See Also