Patterns
Common patterns with @dotdo/types
Function Spectrum
Functions progress through capability tiers, from simple code execution to autonomous agents:
import type {
CodeFunction,
GenerativeFunction,
AgenticFunction,
HumanFunction
} from '@dotdo/types'
// Tier 1: Code - Pure TypeScript execution
const add: CodeFunction<number, { a: number; b: number }> = {
$type: 'CodeFunction',
name: 'add',
handler: ({ a, b }) => a + b,
}
// Tier 2: Generative - LLM-powered generation
const summarize: GenerativeFunction<string, { text: string }> = {
$type: 'GenerativeFunction',
name: 'summarize',
model: 'claude-3-5-sonnet',
prompt: 'Summarize the following text: {{text}}',
}
// Tier 3: Agentic - Multi-step reasoning with tools
const research: AgenticFunction<Report, { topic: string }> = {
$type: 'AgenticFunction',
name: 'research',
tools: ['web-search', 'read-page', 'summarize'],
maxSteps: 10,
}
// Tier 4: Human - Requires human approval
const approve: HumanFunction<boolean, { request: ApprovalRequest }> = {
$type: 'HumanFunction',
name: 'approve-expense',
assignTo: 'manager',
timeout: '7d',
}Promise Pipelining
Chain RPC calls without awaiting intermediate results. The platform batches them into a single round-trip:
import type { RpcPromise } from '@dotdo/types'
// CORRECT - single round trip to the server
const repos = await $.auth.verify(token).github.repos.list()
// The above is equivalent to but faster than:
const user = await $.auth.verify(token) // round trip 1
const github = await user.github // round trip 2
const repos = await github.repos.list() // round trip 3
// Complex pipelines work too
const avatar = await api.users
.get('123')
.profile
.avatar
.resize({ width: 100, height: 100 })Semantic Modeling
Build domain models from the six semantic primitives:
import type { Thing, Noun, Verb, Event, Action, Domain } from '@dotdo/types'
// Define a domain
const Commerce: Domain = {
$type: 'Domain',
$id: 'https://example.com.ai/domains/commerce',
name: 'Commerce',
description: 'E-commerce domain model',
}
// Define entities (Nouns)
const Customer: Noun = {
$type: 'Noun',
$id: 'https://example.com.ai/nouns/Customer',
name: 'Customer',
domain: 'https://example.com.ai/domains/commerce',
properties: {
email: { type: 'string', required: true },
name: { type: 'string' },
}
}
const Product: Noun = {
$type: 'Noun',
$id: 'https://example.com.ai/nouns/Product',
name: 'Product',
domain: 'https://example.com.ai/domains/commerce',
properties: {
sku: { type: 'string', required: true },
price: { type: 'number', required: true },
}
}
// Define operations (Verbs)
const Purchase: Verb = {
$type: 'Verb',
$id: 'https://example.com.ai/verbs/Purchase',
name: 'Purchase',
domain: 'https://example.com.ai/domains/commerce',
subject: 'Customer',
object: 'Product',
}
// Define state changes (Events)
const OrderPlaced: Event = {
$type: 'Event',
$id: 'https://example.com.ai/events/order.placed',
name: 'Order Placed',
domain: 'https://example.com.ai/domains/commerce',
data: {
orderId: { type: 'string' },
customerId: { type: 'string' },
total: { type: 'number' },
}
}Workflow Composition
Build complex workflows from simple steps:
import type { Workflow, WorkflowStep } from '@dotdo/types'
const orderWorkflow: Workflow = {
$type: 'Workflow',
name: 'process-order',
version: '1.0.0',
steps: [
// Sequential steps
{ name: 'validate', type: 'function', function: 'validateOrder' },
{ name: 'charge', type: 'function', function: 'chargePayment' },
// Parallel fan-out
{
name: 'notify',
type: 'parallel',
branches: [
[{ name: 'email', type: 'function', function: 'sendEmail' }],
[{ name: 'sms', type: 'function', function: 'sendSMS' }],
],
},
// Conditional branching
{
name: 'shipping',
type: 'condition',
condition: '$.steps.validate.output.expedited',
then: [{ name: 'express', type: 'function', function: 'shipExpress' }],
else: [{ name: 'standard', type: 'function', function: 'shipStandard' }],
},
],
triggers: [{ type: 'event', event: 'order.placed' }],
}Type Discriminators
All types include a $type discriminator for runtime type checking:
import type { BaseEvent, Workflow, Agent } from '@dotdo/types'
function handleMessage(msg: BaseEvent | Workflow | Agent) {
switch (msg.$type) {
case 'Event':
console.log('Event:', msg.type, msg.data)
break
case 'Workflow':
console.log('Workflow:', msg.name, msg.steps.length, 'steps')
break
case 'Agent':
console.log('Agent:', msg.name, 'with', msg.tools?.length, 'tools')
break
}
}Event-Driven Patterns
Use events for loose coupling between components:
import type { EventEmitter, EventBus, BaseEvent } from '@dotdo/types'
// Type-safe event emitter
interface OrderEvents {
'order.placed': { orderId: string; total: number }
'order.shipped': { orderId: string; trackingId: string }
'order.delivered': { orderId: string; signature: string }
}
const orders: EventEmitter<OrderEvents> = getEmitter()
// Subscribe with full type safety
orders.on('order.placed', async ({ orderId, total }) => {
await processOrder(orderId, total)
})
// Publish events
await orders.emit('order.placed', { orderId: 'ord_123', total: 99.99 })Agent Patterns
Configure agents with tools and policies:
import type { Agent, AgentConfig, AgentTool } from '@dotdo/types'
const researchAgent: Agent = {
$type: 'Agent',
name: 'research-assistant',
description: 'Researches topics and creates reports',
config: {
model: 'claude-3-5-sonnet',
temperature: 0.7,
maxTokens: 4096,
},
tools: [
{ name: 'web-search', description: 'Search the web' },
{ name: 'read-page', description: 'Read a web page' },
{ name: 'write-file', description: 'Write to a file' },
],
policy: {
maxSteps: 20,
maxCost: 1.00,
allowedDomains: ['*.wikipedia.org', '*.arxiv.org'],
},
}