Components

Add AI capabilities with gencow add — AI, speech, RAG, Memory, Tools, Guardrails, and more

The gencow add command installs pre-built AI components into your project. Each component adds files to gencow/ and installs required dependencies.

Usage

# Add a single component
npx gencow@latest add AI

# Add multiple at once
npx gencow@latest add AI RAG Reranker

# Dependencies auto-resolve (RAG requires AI → AI is added automatically)
npx gencow@latest add RAG   # → also installs AI

Available Components

# Component Description Requires
1 AI Vercel AI SDK wrapper (chat, embeddings, structured output, images, speech helpers; feature-flagged cloud text streaming)
2 Agent Durable workflow agent starter with injectable AI SDK model AI
3 Tools AI Tool Calling with ctx integration AI
4 RAG Document ingestion + semantic search with injectable embedding/answer models AI
5 Memory Agent memory (episodic/semantic/procedural) with injectable extraction/embedding models AI
6 Reranker Dedicated AI SDK reranking with GPT fallback AI
7 Guardrails Input/output safety filters (PII, topic blocking) with injectable model AI
8 Prompts Reusable prompt templates
9 Parsers PDF/HTML/CSV file parsing
10 Analytics LLM call tracking AI (coming soon)

Component Details

AI — Core Engine

npx gencow@latest add AI

Creates gencow/ai.ts (and related generated files). Import from gencow/ai.ts — see AI Engine for model catalog, billing, structured output, and the full runtime contract.

gencow/ai.ts exposes two APIs. Prefer the provider API for new code; the facade API is a narrower compatibility layer for simple handlers and other Gencow components.

Provider API (recommended):

import { embed, generateText } from "ai";
import { createGencowAI } from "./ai";

const gencow = createGencowAI();

await generateText({
    model: gencow.languageModel("gpt-5.4-mini"),
    messages: [{ role: "user", content: "Hello" }],
});

await embed({
    model: gencow.embeddingModel("text-embedding-3-small"),
    value: "Hello, world!",
});

pgvector schema match required: if you later store these embeddings in pgvector, the embedding model dimension must match the DB column size. The generated RAG and Memory starter schemas use vector(1536).

Facade API:

import { ai } from "./ai";

ai.chat({ system, messages, model })    // Non-streaming response
ai.stream({ system, messages, model })  // Text streaming when local direct mode or cloud streaming is enabled
ai.embed(text)                          // Generate embeddings
ai.image.generate({ prompt, model })    // Generate images with GPT Image
ai.vision.extractText({ image, mediaType }) // Extract text from image input
ai.speech.transcribe({ storageId, model })  // Start async STT from a private storage object
ai.speech.waitForTranscript(jobId)          // Poll until the STT job reaches a terminal state
ai.speech.synthesize({ input, voice })      // Generate private TTS audio output

Installed deps: ai, @ai-sdk/openai Env required: OPENAI_API_KEY (local only — auto in cloud)

Speech helpers are proxy-backed even in development because they need Gencow storage lookup, media preprocessing, async job state, and service-credit billing. For speech-to-text, upload audio or video to private app storage first and pass only the resulting storageId; do not send raw multipart audio to the AI proxy.


Generated AI Factories

Generated AI-dependent components now follow the same dual-surface pattern as gencow/ai.ts:

  • Provider API: call createX(...) and inject models from createGencowAI().
  • Facade API: import the generated singleton (rag, memory, guardrails, reranker, runAgent) for compatibility.

Use the factory when a handler needs explicit model selection, tests need mock models, or you are composing with AI SDK helpers directly. Existing singleton imports remain stable for generated starter code.


Agent — Workflow Agent

gencow add Agent

Creates gencow/agent.ts.

Provider API (recommended):

import { createGencowAI } from "./ai";
import { createWorkflowAgent } from "./agent";

const gencow = createGencowAI();

export const customRunAgent = createWorkflowAgent({
    model: gencow.languageModel("gpt-5.4-mini"),
});

Use the factory when you want explicit model selection or test doubles.

Facade API:

import { runAgent } from "./agent";

// Backward-compatible singleton workflow.
// Existing generated apps can keep exporting or starting runAgent directly.
export { runAgent };

Use useWorkflow(api.workflows.get, run.id) and workflows.signal to observe or resume durable agent runs.


Tools — AI Function Calling

gencow add Tools

Creates gencow/tools.ts with defineTools() — a thin wrapper around AI SDK's tool() that injects ctx into handlers.

Provider API (use AI SDK tool() directly):

import { generateText, tool } from "ai";
import { z } from "zod";
import { createGencowAI } from "./ai";

const gencow = createGencowAI();

const getWeather = tool({
    description: "Get weather for a city",
    parameters: z.object({ city: z.string() }),
    execute: async ({ city }) => `Weather in ${city}: 22°C, sunny`,
});

const result = await generateText({
    model: gencow.languageModel("gpt-5.4-mini"),
    messages: [{ role: "user", content: "What's the weather in Seoul?" }],
    tools: { getWeather },
});

Facade API (with defineTools + ai.chat()):

import { z } from "zod";
import { ai } from "./ai";
import { defineTools } from "./tools";

const tools = defineTools(ctx, {
    getWeather: {
        description: "Get weather for a city",
        parameters: z.object({ city: z.string() }),
        handler: async (ctx, { city }) => {
            return `Weather in ${city}: 22°C, sunny`;
        },
    },
});

const result = await ai.chat({
    messages: [{ role: "user", content: "What's the weather in Seoul?" }],
    tools,
});
console.log(result.text);

gencow add RAG

Creates gencow/rag.ts + gencow/schema-rag.ts.

Provider API (recommended):

import { createGencowAI } from "./ai";
import { createRag } from "./rag";

const gencow = createGencowAI();
const customRag = createRag({
    embeddingModel: gencow.embeddingModel("text-embedding-3-small"),
    answerModel: gencow.languageModel("gpt-5.4-mini"),
});

await customRag.ingest(ctx, "manual.md", "Document text content...");
const hits = await customRag.retrieve(ctx, "What is Gencow?");
// → [{ chunk, source, similarity, metadata }]

Use the factory when you want explicit embedding/answer model control.

The generated schema-rag.ts starter uses embedding: vector(1536), so if you change the embedding model to one with a different output dimension, update the schema and re-index stored vectors.

Facade API:

import { rag } from "./rag";

await rag.ingest(ctx, "manual.md", "Document text content...");
const answer = await rag.ask(ctx, "What is Gencow?");
const grounded = await rag.askGrounded(ctx, "What is Gencow?", {
    corpus: "default",
    visibility: "shared",
});

Important: Import schema-rag.ts in your main schema.ts to create the required DB tables.

rag.ingest() writes to the local rag_documents table. Grounded helpers such as rag.askGrounded() and reranker.answerGrounded() read canonical Phase 2 rag_* corpora populated through documents.ingest.*.


Memory — Agent Memory

gencow add Memory

Creates gencow/memory.ts + gencow/schema-memory.ts.

Provider API (recommended):

import { generateText } from "ai";
import { createGencowAI } from "./ai";
import { createMemory } from "./memory";

const gencow = createGencowAI();
const customMemory = createMemory({
    extractionModel: gencow.languageModel("gpt-5.4-mini"),
    embeddingModel: gencow.embeddingModel("text-embedding-3-small"),
});

const memCtx = await customMemory.buildContext(ctx, userId, sessionId, query);
const result = await generateText({
    model: gencow.languageModel("gpt-5.4-mini"),
    system: `You are a helpful assistant.

${memCtx.toSystemPrompt()}`,
    messages: [...memCtx.recentMessages, { role: "user", content: query }],
});

await customMemory.extract(ctx, userId, `User: ${query}
Assistant: ${result.text}`);

buildContext() returns recentMessages, longTermFacts, and toSystemPrompt().

The generated schema-memory.ts starter uses embedding: vector(1536), so any embedding model change must stay dimension-compatible or be paired with a schema change and vector migration/re-index.

Facade API:

import { ai } from "./ai";
import { memory } from "./memory";

const memCtx = await memory.buildContext(ctx, userId, sessionId, query);
const result = await ai.chat({
    system: `You are a helpful assistant.

${memCtx.toSystemPrompt()}`,
    messages: [...memCtx.recentMessages, { role: "user", content: query }],
});

await memory.extract(ctx, userId, `User: ${query}
Assistant: ${result.text}`);
await memory.saveSession(ctx, sessionId, userId, [
    ...memCtx.recentMessages,
    { role: "user", content: query },
    { role: "assistant", content: result.text },
]);
Type Purpose Example
Episodic Conversation history "Last time we discussed…"
Semantic Facts and knowledge "User prefers dark mode"
Procedural Learned procedures "When user asks X, do Y"

Reranker — Result Quality

gencow add Reranker

Creates gencow/reranker.ts.

Provider API (recommended):

import { rerank } from "ai";
import { createGencowAI } from "./ai";
import { createReranker } from "./reranker";

const gencow = createGencowAI();

const ranked = await rerank({
    model: gencow.rerankingModel("Cohere-rerank-v4.0-fast"),
    query,
    documents: searchResults.map((item) => item.chunk),
    topN: 5,
});

const customReranker = createReranker({
    rerankingModel: gencow.rerankingModel("Cohere-rerank-v4.0-fast"),
    fallbackModel: gencow.languageModel("gpt-5.4-mini"),
});

Use direct AI SDK rerank() for the primitive, or createReranker() when you want the generated compatibility helpers.

Facade API:

import { rag } from "./rag";
import { reranker } from "./reranker";

const reranked = await reranker.rerank(query, searchResults, { topK: 5 });
const results = await reranker.searchAndRerank(ctx, rag, query);
const grounded = await reranker.answerGrounded(ctx, query, {
    corpus: "default",
    visibility: "shared",
});

gencow.rerankingModel(...) is proxy-backed. In local direct mode without the Gencow AI proxy, pure reranking should fail fast. The generated reranker starter can still use its explicit fallback-model path for compatibility.


Guardrails — Safety Filters

gencow add Guardrails

Creates gencow/guardrails.ts.

Provider API (recommended):

import { createGencowAI } from "./ai";
import { createGuardrails } from "./guardrails";

const gencow = createGencowAI();
const customGuardrails = createGuardrails({
    model: gencow.languageModel("gpt-5.4-mini"),
});

const safe = await customGuardrails.validateInput(userText, {
    maskPII: true,
    blockTopics: ["politics"],
});

const checked = await customGuardrails.validateOutput(aiResponse, {
    maxLength: 2000,
    bannedPatterns: [/api[_-]?key/i],
});

Facade API:

import { guardrails } from "./guardrails";

const safe = await guardrails.validateInput(userText, {
    maskPII: true,
    blockTopics: ["politics"],
});

const wrapped = await guardrails.wrap(
    async (sanitized) => myFunction(sanitized),
    userText,
    { maskPII: true },
    { maxLength: 2000 },
);

Prompts — Reusable Templates

gencow add Prompts

Creates gencow/prompts.ts. Pre-built prompt templates:

import { ragQAPrompt, summarizePrompt, classifyPrompt } from "./prompts";

// RAG Q&A
const prompt = ragQAPrompt({
    question: "What is Gencow?",
    context: "Retrieved context here...",
});

// Summarization
const prompt = summarizePrompt({ text: "Long text to summarize..." });

// Classification
const prompt = classifyPrompt({
    text: "I love this product!",
    categories: ["positive", "negative", "neutral"],
});

Parsers — File Parsing

gencow add Parsers

Creates gencow/parsers.ts. Parse various file formats:

// PDF
const text = await parsers.pdf(buffer);

// HTML
const text = await parsers.html(htmlString);

// CSV
const rows = await parsers.csv(csvString);

// Auto-detect by filename
const text = await parsers.auto("document.pdf", buffer);

// RAG integration
await rag.ingest(ctx, "manual.pdf", await parsers.pdf(buffer));

Installed deps: pdf-parse

Dependency Resolution

Components automatically install their dependencies:

gencow add RAG
# → Also installs AI (because RAG requires AI)
gencow add RAG Reranker Memory
# → Installs AI first, then RAG, Reranker, Memory

After Installation

# README is auto-updated with new component docs
gencow dev

Each component's usage is added to the auto-generated gencow/README.md.

Next Steps

  • AI Engine — Provider vs facade APIs, models, billing, structured output
  • RAG & Memory — Deep dive into document search and agent memory
  • CLI Reference — All CLI commands