Dyrected
Model ContentConfiguration

Configuring AI

How to enable and configure schema-aware AI assistants, LLM providers, brand voice directives, and custom tools in dyrected.config.ts.

Dyrected includes a schema-aware AI engine that works directly with your collections, globals, and database records. Instead of writing separate prompt orchestration code or brittle parsing scripts, you declare your AI configuration in dyrected.config.ts. The assistant automatically understands your project's field types, relationship rules, and singleton structures.

By the end of this page, you will know how to choose an AI provider, set global brand voice directives, attach collection-specific instructions, and configure rate limits.

The mental model: schema-grounded intelligence

Most AI integrations require feeding extensive JSON schema dumps into every prompt. Dyrected takes a different approach:

  • Built-in Schema Awareness: The AI engine automatically generates a structured inventory of your collections, fields, and globals at initialization.
  • Human-in-the-Loop Mutations: The assistant never blindly updates records in the database. When asked to rewrite, generate, or modify content, it produces visual diff proposals that editors review and approve with one click.
  • Dual-Mode Communication: By default, the assistant speaks like a warm, practical editorial colleague. If a developer explicitly asks for technical details or schemas, it transitions into technical mode.

Enabling AI in your configuration

Add the ai key to your dyrected.config.ts. Here is a complete, runnable setup using AgentRouter:

// dyrected.config.ts
import { defineConfig, defineCollection, defineTextField, defineNumberField } from "@dyrected/core";
import { postgresAdapter } from "@dyrected/db-postgres";

export const Services = defineCollection({
  slug: "services",
  labels: { singular: "Service", plural: "Services" },
  ai: {
    prompt: "Highlight tangible business outcomes and client ROI in all service descriptions.",
  },
  fields: [
    defineTextField({ name: "name", label: "Service Name", required: true }),
    defineTextField({ name: "summary", label: "Brief Summary", required: true }),
    defineNumberField({ name: "price", label: "Base Price (NGN)", required: true }),
  ],
});

export default defineConfig({
  collections: [Services],
  db: postgresAdapter({
    url: process.env.DATABASE_URL || "postgres://localhost:5432/my_app",
  }),
  ai: {
    provider: "agentrouter",
    model: "deepseek-v4-flash",
    systemPrompt:
      "You are the operations assistant for Acme Growth Coaching. Write in a warm, encouraging, and non-technical editorial voice. When asked to rewrite or edit content, immediately propose clean updates.",
    rateLimit: {
      userMax: 60,
      projectMax: 600,
    },
  },
});

Once saved, the admin panel renders the floating Lip Trigger assistant drawer, and the @dyrected/core AIAgent service becomes available to your server routes.

Choosing your AI provider and environment variables

Dyrected is completely provider-agnostic. You can use whichever LLM provider fits your team's workflow, budget, or data residency requirements.

Automatic Provider Detection

If you don't want to specify a provider explicitly, Dyrected automatically detects your provider based on which API key is present in your environment:

If your .env containsDyrected automatically routes toDefault Fallback Model
OPENAI_API_KEYOpenAIgpt-4o-mini
GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEYGoogle Geminigemini-2.0-flash
OPENROUTER_API_KEYOpenRouteranthropic/claude-3-haiku
AGENTROUTER_API_KEYAgentRouterclaude-3-haiku-20240307

Explicit Provider Configuration

If you want to pin a specific model, change base URLs (e.g. for custom proxies, self-hosted models, or gateways), or specify custom API key names, configure the ai block in dyrected.config.ts:

// 1. Direct OpenAI
ai: {
  provider: "openai",
  model: "gpt-4o",
  apiKey: process.env.OPENAI_API_KEY,
}

// 2. Google Gemini
ai: {
  provider: "google",
  model: "gemini-2.5-flash",
  apiKey: process.env.GEMINI_API_KEY,
}

// 3. OpenRouter (Access OpenAI, Claude, Llama via one key)
ai: {
  provider: "openrouter",
  model: "openai/gpt-4o", // or "anthropic/claude-3.5-sonnet", "meta-llama/llama-3.3-70b-instruct"
  baseURL: "https://openrouter.ai/api/v1", // default
  apiKey: process.env.OPENROUTER_API_KEY,
}

// 4. Custom OpenAI-compatible Gateway (Ollama, vLLM, Groq, Together)
ai: {
  provider: "custom",
  baseURL: "http://localhost:11434/v1", // or https://api.groq.com/openai/v1
  apiKey: process.env.CUSTOM_AI_API_KEY || "dummy-key",
  model: "llama3.2",
}

Setting brand voice directives

The ai.systemPrompt property sets high-level instructions that apply across your entire project. This prompt is injected into the assistant's system instructions under BRAND VOICE & DIRECTIVES:

ai: {
  provider: "agentrouter",
  model: "deepseek-v4-flash",
  systemPrompt: `
  You are the Lead Editorial Assistant for Future You Coaching.
  - Tone: Warm, authoritative, actionable, and conversational.
  - Audience: Mid-career professionals and executives seeking leadership clarity.
  - Rule: Never show raw HTML code blocks or database IDs in chat messages.
  `,
}

Collection-level editorial prompts

When an assistant works on a specific collection, general instructions may not be enough. You can attach targeted guidelines to individual collections using collection.ai.prompt:

export const BlogArticles = defineCollection({
  slug: "blog-articles",
  ai: {
    prompt: `
    When writing or editing blog articles:
    - Keep intros under 3 sentences with a compelling hook.
    - Break long sections into concise subheadings with bulleted takeaways.
    - Write excerpts optimized for LinkedIn and newsletter sharing.
    `,
  },
  fields: [
    defineTextField({ name: "title", label: "Article Title", required: true }),
    defineTextField({ name: "excerpt", label: "Social Excerpt", required: true }),
    defineTextField({ name: "body", label: "Article Body", required: true }),
  ],
});

When an editor asks the assistant to work on blog posts, Dyrected merges your global ai.systemPrompt with the collection's specific prompt.

Rate limiting and safety controls

To protect your API budget and prevent abuse, configure rate limiting directly in config.ai.rateLimit:

ai: {
  provider: "agentrouter",
  model: "deepseek-v4-flash",
  rateLimit: {
    userMax: 30,       // Max requests per user per minute
    projectMax: 300,   // Max requests project-wide per minute
  },
}

If a user or project exceeds these limits, Dyrected returns a polite 429 Too Many Requests error with the retry interval.

Customer privacy and PII protection

Dyrected protects customer data by default before sending any records to an AI model:

  • Credentials (password, salt, hash, token, secret) are permanently stripped.
  • Emails and phone numbers are automatically masked (e.g. a***@example.com, ***-***-5678) unless explicitly permitted via ai: { allowRaw: true }.
  • Custom redaction: You can declare ai: { exclude: true } on sensitive fields, attach collection-level sanitizeDoc pseudonymization hooks, or enable the global free-text PII scrubber.

For complete guidance and configuration examples, see AI Privacy & Data Redaction.

Using AI with the SDK (@dyrected/sdk)

Frontend apps and custom scripts can interact directly with Dyrected's AI assistant through the typed client.ai module on DyrectedClient.

1. Creating threads and messaging

import { DyrectedClient } from "@dyrected/sdk";

const client = new DyrectedClient({
  baseUrl: "http://localhost:3000",
  apiKey: process.env.DYRECTED_API_KEY,
});

// Create a thread
const thread = await client.ai.createThread({ title: "Product Copy Generation" });

// Post a message
const reply = await client.ai.postMessage(thread.id, {
  role: "user",
  content: "Draft a 50-word product description for the Silk Scarf",
});

// List or get threads
const threads = await client.ai.listThreads();
const currentThread = await client.ai.getThread(thread.id);

2. Human-in-the-Loop action confirmation

When an AI model proposes a sensitive action (like creating or deleting records), Dyrected creates a pending action that requires explicit approval:

// Inspect pending action details
const action = await client.ai.getAction("act_abc123");
console.log(action.summary, action.proposedData);

// Approve and execute the proposed change
await client.ai.executeAction("act_abc123");

// Or reject with an optional reason
await client.ai.rejectAction("act_abc123", {
  reason: "Price cannot be zero",
});

Query indexed content using cosine similarity embeddings:

const results = await client.ai.searchRAG({
  query: "How do return shipping refunds work?",
  collection: "kb_articles",
  limit: 5,
});

for (const match of results) {
  console.log(`${match.title} (Score: ${match.score}): ${match.text}`);
}

On this page

Dyrected| Cloud

Get your backend ready in minutes

Use a managed database, storage, APIs, and admin dashboard without setting up the infrastructure yourself.

Set Up My Backend