Primitives.org.ai

ai

Call AI like a function

Everything starts with ai.

import { ai } from 'ai-functions'

Three Ways to Call AI

Template Literal

The simplest form—just a string, get a string back:

const explanation = await ai`Explain ${topic} to a 5 year old`
// "Imagine your toys could talk to each other..."

Function Call

Same thing, with options:

const result = await ai('Analyze this data', {
  model: 'claude-opus-4-5',
  temperature: 0.7,
})

Dynamic Functions

The magic happens here. Call any method on ai and it figures out what you need:

// ai.doSomething() → calls define() → determines function type
const code = await ai.generateAuthMiddleware(requirements)
const analysis = await ai.analyzeMarketTrends(data)
const approved = await ai.getManagerApproval(proposal)

When you call ai.doSomething(), the system:

  1. Calls define('doSomething', ...) with inferred schema
  2. Classifies the function type based on what it needs to do
  3. Returns the appropriate result

Function Types

Every ai.doSomething() becomes one of four function types:

TypeWhat It DoesReturns
Code FunctionGenerates executable codeCode string
Generative FunctionCreates content/dataStructured data
Agentic FunctionTakes autonomous actionAction results
Human FunctionRequires human inputHuman response

The classification happens automatically based on the function name and context.

Promise Pipelining

Chain operations without await—dependencies resolve automatically:

const { score, qualified, reason } = ai`qualify ${lead}`

// Chain naturally
const email = ai`follow-up email based on: ${reason}`
const subject = ai`subject line for: ${email}`

// Only await when you need the value
if (await qualified) {
  await send({ subject: await subject, body: await email })
}

Destructuring

Get exactly what you need:

// Single values
const summary = await ai`summarize ${article}`

// Multiple values
const { title, tags, excerpt } = ai`metadata for: ${blogPost}`

// Named lists
const { pros, cons, risks } = ai`evaluate ${proposal}`

Batch Processing

Process arrays in a single call:

const leads = list`leads from ${campaign}`

const qualified = await leads.map(lead => ({
  lead,
  score: ai`score 1-100: ${lead}`,
  fit: ai`${lead} matches ${icp}?`,
}))

How It Works

Under the hood, ai.doSomething() is syntactic sugar for define:

// When you write:
const result = await ai.qualifyLead(lead)

// It's equivalent to:
const qualifyLead = define('qualifyLead', { /* inferred schema */ })
const result = await qualifyLead(lead)

The difference is that ai.doSomething() infers everything from the function name and arguments, while define lets you be explicit.

Was this page helpful?

On this page