Conditional Logic
PromptSmith provides conditional methods that allow you to build dynamic prompts based on runtime conditions, user permissions, feature flags, and environment configuration.Conditional Tools with withToolIf()
ThewithToolIf() method adds a tool only when a condition is true, enabling dynamic tool availability based on runtime state.
Basic Usage
import { createPromptBuilder } from 'promptsmith';
import { z } from 'zod';
const config = {
databaseEnabled: true,
externalApiEnabled: false,
premiumFeaturesEnabled: true
};
const agent = createPromptBuilder()
.withIdentity('You are a data analysis assistant')
// Database tool - only if database is enabled
.withToolIf(config.databaseEnabled, {
name: 'query_database',
description: 'Query the customer database',
schema: z.object({
query: z.string().describe('SQL query to execute')
}),
execute: async ({ query }) => {
// Execute query
return { rows: [], count: 0 };
}
})
// External API tool - only if API is enabled
.withToolIf(config.externalApiEnabled, {
name: 'fetch_external_data',
description: 'Fetch data from external API',
schema: z.object({
endpoint: z.string().describe('API endpoint')
}),
execute: async ({ endpoint }) => {
// Fetch from API
return {};
}
})
// Premium analytics - only for premium users
.withToolIf(config.premiumFeaturesEnabled, {
name: 'advanced_analytics',
description: 'Run advanced analytics on dataset',
schema: z.object({
datasetId: z.string().describe('Dataset ID')
})
});
const summary = agent.getSummary();
console.log(summary.toolsCount); // 2 (database + premium, API disabled)
Real-World Example: Permission-Based Tools
import { createPromptBuilder } from 'promptsmith';
import { z } from 'zod';
interface UserPermissions {
canReadCustomers: boolean;
canWriteCustomers: boolean;
canDeleteCustomers: boolean;
canAccessFinancials: boolean;
canExportData: boolean;
isAdmin: boolean;
}
function buildAgentForUser(permissions: UserPermissions) {
return createPromptBuilder()
.withIdentity('You are a business operations assistant')
.withCapabilities([
'Answer questions about business operations',
'Help with data analysis',
'Assist with reporting'
])
// Read-only customer tool
.withToolIf(permissions.canReadCustomers, {
name: 'get_customer',
description: 'Retrieve customer information',
schema: z.object({
customerId: z.string().describe('Customer ID')
}),
execute: async ({ customerId }) => {
return { id: customerId, name: 'John Doe' };
}
})
// Customer update tool - requires write permission
.withToolIf(permissions.canWriteCustomers, {
name: 'update_customer',
description: 'Update customer information',
schema: z.object({
customerId: z.string().describe('Customer ID'),
data: z.record(z.unknown()).describe('Updated fields')
}),
execute: async ({ customerId, data }) => {
return { success: true };
}
})
// Delete tool - requires delete permission
.withToolIf(permissions.canDeleteCustomers, {
name: 'delete_customer',
description: 'Delete a customer (use with caution)',
schema: z.object({
customerId: z.string().describe('Customer ID'),
reason: z.string().describe('Reason for deletion')
}),
execute: async ({ customerId, reason }) => {
return { deleted: true };
}
})
// Financial data - restricted access
.withToolIf(permissions.canAccessFinancials, {
name: 'get_revenue_data',
description: 'Retrieve revenue and financial metrics',
schema: z.object({
period: z.enum(['daily', 'weekly', 'monthly']).describe('Time period')
}),
execute: async ({ period }) => {
return { revenue: 0, expenses: 0 };
}
})
// Data export - compliance-sensitive
.withToolIf(permissions.canExportData, {
name: 'export_customer_data',
description: 'Export customer data to CSV',
schema: z.object({
filters: z.object({}).optional().describe('Filter criteria')
}),
execute: async ({ filters }) => {
return { downloadUrl: 'https://...' };
}
})
// Admin-only tools
.withToolIf(permissions.isAdmin, {
name: 'manage_users',
description: 'Manage user accounts and permissions',
schema: z.object({
action: z.enum(['create', 'update', 'delete']).describe('Action'),
userId: z.string().describe('User ID')
})
})
// Add constraints based on permissions
.withConstraintIf(
!permissions.canDeleteCustomers,
'must_not',
'Never suggest deleting customer records'
)
.withConstraintIf(
permissions.canAccessFinancials,
'must',
'Treat all financial data as highly confidential'
);
}
// Usage examples
const basicUser = buildAgentForUser({
canReadCustomers: true,
canWriteCustomers: false,
canDeleteCustomers: false,
canAccessFinancials: false,
canExportData: false,
isAdmin: false
});
console.log(basicUser.getSummary().toolsCount); // 1 (only read access)
const powerUser = buildAgentForUser({
canReadCustomers: true,
canWriteCustomers: true,
canDeleteCustomers: false,
canAccessFinancials: true,
canExportData: true,
isAdmin: false
});
console.log(powerUser.getSummary().toolsCount); // 4 (read, write, financials, export)
const adminUser = buildAgentForUser({
canReadCustomers: true,
canWriteCustomers: true,
canDeleteCustomers: true,
canAccessFinancials: true,
canExportData: true,
isAdmin: true
});
console.log(adminUser.getSummary().toolsCount); // 6 (all tools)
Conditional Constraints with withConstraintIf()
ThewithConstraintIf() method adds constraints based on conditions, enabling dynamic behavioral rules.
Environment-Based Constraints
import { createPromptBuilder } from 'promptsmith';
const env = process.env.NODE_ENV || 'development';
const isProd = env === 'production';
const isDev = env === 'development';
const agent = createPromptBuilder()
.withIdentity('You are a system monitoring assistant')
// Production-specific constraints
.withConstraintIf(
isProd,
'must',
'Log all errors and warnings to the monitoring system'
)
.withConstraintIf(
isProd,
'must',
'Never expose internal system details in error messages'
)
.withConstraintIf(
isProd,
'must_not',
'Never restart services without approval'
)
// Development-specific constraints
.withConstraintIf(
isDev,
'should',
'Provide verbose debugging information'
)
.withConstraintIf(
isDev,
'should',
'Include stack traces in error responses'
)
// Different tone based on environment
.withTone(
isProd
? 'Professional and cautious. Prioritize system stability.'
: 'Technical and detailed. Help debug issues quickly.'
);
Feature Flag Integration
Define feature flags
import { createPromptBuilder } from 'promptsmith';
import { z } from 'zod';
// Feature flags from your feature flag service
interface FeatureFlags {
enableAISearch: boolean;
enableImageGeneration: boolean;
enableVoiceInput: boolean;
enableMultiLanguage: boolean;
enableBetaFeatures: boolean;
enableAdvancedAnalytics: boolean;
}
// Fetch from feature flag service (LaunchDarkly, etc.)
async function getFeatureFlags(userId: string): Promise<FeatureFlags> {
// In real app, fetch from feature flag service
return {
enableAISearch: true,
enableImageGeneration: false,
enableVoiceInput: true,
enableMultiLanguage: false,
enableBetaFeatures: false,
enableAdvancedAnalytics: true
};
}
Build agent based on flags
async function buildAgentWithFeatures(
userId: string
): Promise<ReturnType<typeof createPromptBuilder>> {
const flags = await getFeatureFlags(userId);
const agent = createPromptBuilder()
.withIdentity('You are a multi-modal AI assistant')
.withCapabilities([
'Answer questions',
'Analyze documents',
'Provide recommendations'
])
// AI Search - feature flag controlled
.withToolIf(flags.enableAISearch, {
name: 'semantic_search',
description: 'Search documents using AI-powered semantic search',
schema: z.object({
query: z.string().describe('Natural language search query'),
limit: z.number().optional().describe('Max results')
}),
execute: async ({ query, limit }) => {
return { results: [] };
}
})
// Image generation - beta feature
.withToolIf(flags.enableImageGeneration, {
name: 'generate_image',
description: 'Generate images from text descriptions',
schema: z.object({
prompt: z.string().describe('Image description'),
style: z.enum(['realistic', 'artistic', 'cartoon']).optional()
})
})
// Voice input - requires special handling
.withToolIf(flags.enableVoiceInput, {
name: 'transcribe_audio',
description: 'Transcribe audio input to text',
schema: z.object({
audioUrl: z.string().describe('URL to audio file')
})
})
// Advanced analytics
.withToolIf(flags.enableAdvancedAnalytics, {
name: 'run_analytics',
description: 'Run advanced analytics on datasets',
schema: z.object({
analysisType: z.enum(['trend', 'forecast', 'anomaly']),
datasetId: z.string()
})
})
// Beta features disclaimer
.withConstraintIf(
flags.enableBetaFeatures,
'must',
'Inform users that beta features may have limited reliability'
)
// Multi-language support
.withConstraintIf(
flags.enableMultiLanguage,
'should',
'Detect user language and respond in the same language'
)
.withCapability(
flags.enableMultiLanguage ? 'Communicate in multiple languages' : ''
);
return agent;
}
// Usage
const userAgent = await buildAgentWithFeatures('user-123');
const prompt = userAgent.build();
Subscription Tier-Based Configuration
import { createPromptBuilder } from 'promptsmith';
import { z } from 'zod';
type SubscriptionTier = 'free' | 'pro' | 'enterprise';
interface SubscriptionLimits {
maxQueriesPerDay: number;
hasAdvancedTools: boolean;
hasPrioritySupport: boolean;
hasCustomBranding: boolean;
}
function getTierLimits(tier: SubscriptionTier): SubscriptionLimits {
switch (tier) {
case 'free':
return {
maxQueriesPerDay: 10,
hasAdvancedTools: false,
hasPrioritySupport: false,
hasCustomBranding: false
};
case 'pro':
return {
maxQueriesPerDay: 100,
hasAdvancedTools: true,
hasPrioritySupport: false,
hasCustomBranding: false
};
case 'enterprise':
return {
maxQueriesPerDay: Infinity,
hasAdvancedTools: true,
hasPrioritySupport: true,
hasCustomBranding: true
};
}
}
function buildAgentForTier(tier: SubscriptionTier, currentUsage: number) {
const limits = getTierLimits(tier);
const isNearLimit = currentUsage >= limits.maxQueriesPerDay * 0.8;
const hasReachedLimit = currentUsage >= limits.maxQueriesPerDay;
return createPromptBuilder()
.withIdentity('You are a business intelligence assistant')
.withCapabilities(['Analyze data', 'Generate reports', 'Answer questions'])
// Basic tools - available to all tiers
.withTool({
name: 'basic_query',
description: 'Run basic data queries',
schema: z.object({
query: z.string().describe('Query to run')
})
})
// Advanced tools - Pro and Enterprise only
.withToolIf(limits.hasAdvancedTools, {
name: 'advanced_analytics',
description: 'Run advanced analytics and forecasting',
schema: z.object({
analysisType: z.enum(['forecast', 'anomaly', 'clustering']),
dataset: z.string()
})
})
.withToolIf(limits.hasAdvancedTools, {
name: 'export_report',
description: 'Export reports in multiple formats',
schema: z.object({
format: z.enum(['pdf', 'excel', 'powerpoint']),
reportId: z.string()
})
})
// Enterprise-only features
.withToolIf(limits.hasCustomBranding, {
name: 'customize_branding',
description: 'Customize report branding and styling',
schema: z.object({
logo: z.string().optional(),
colors: z.object({}).optional()
})
})
// Usage limit warnings
.withConstraintIf(
isNearLimit && !hasReachedLimit,
'should',
`Inform user they are approaching their daily limit (${currentUsage}/${limits.maxQueriesPerDay} queries used)`
)
.withConstraintIf(
hasReachedLimit,
'must',
'Inform user they have reached their daily query limit and should upgrade'
)
// Priority support messaging
.withConstraintIf(
limits.hasPrioritySupport,
'should',
'Mention 24/7 priority support availability for complex issues'
)
.withConstraintIf(
!limits.hasPrioritySupport,
'should',
'Suggest upgrading to Pro/Enterprise for priority support'
)
// Tier-specific tone
.withTone(
tier === 'enterprise'
? 'Professional and white-glove service oriented'
: tier === 'pro'
? 'Helpful and proactive'
: 'Friendly and encouraging (mention upgrade benefits)'
);
}
// Usage
const freeUserAgent = buildAgentForTier('free', 8);
console.log(freeUserAgent.getSummary()); // 1 tool, warning about limit
const proUserAgent = buildAgentForTier('pro', 50);
console.log(proUserAgent.getSummary()); // 3 tools, advanced features
const enterpriseAgent = buildAgentForTier('enterprise', 500);
console.log(enterpriseAgent.getSummary()); // 4 tools, all features
Combining Multiple Conditions
Complex Permission Logic
import { createPromptBuilder } from 'promptsmith';
import { z } from 'zod';
interface UserContext {
role: 'viewer' | 'editor' | 'admin';
department: 'sales' | 'engineering' | 'hr' | 'finance';
isProd: boolean;
featureFlags: {
enableAudit: boolean;
enableExport: boolean;
};
}
function buildContextualAgent(ctx: UserContext) {
// Compute derived permissions
const canWrite = ctx.role === 'editor' || ctx.role === 'admin';
const canDelete = ctx.role === 'admin';
const canAccessFinancials = ctx.department === 'finance' || ctx.role === 'admin';
const canAccessHR = ctx.department === 'hr' || ctx.role === 'admin';
const canExport = ctx.featureFlags.enableExport && canWrite;
const canAudit = ctx.featureFlags.enableAudit && canDelete;
return createPromptBuilder()
.withIdentity(`You are a ${ctx.department} department assistant`)
// Read tools - available to everyone
.withTool({
name: 'view_documents',
description: 'View department documents',
schema: z.object({
documentId: z.string()
})
})
// Write tools - editors and admins
.withToolIf(canWrite, {
name: 'create_document',
description: 'Create a new document',
schema: z.object({
title: z.string(),
content: z.string()
})
})
.withToolIf(canWrite, {
name: 'update_document',
description: 'Update existing document',
schema: z.object({
documentId: z.string(),
changes: z.object({})
})
})
// Delete tools - admins only
.withToolIf(canDelete, {
name: 'delete_document',
description: 'Delete a document (use with caution)',
schema: z.object({
documentId: z.string(),
reason: z.string()
})
})
// Financial data - finance department or admins
.withToolIf(canAccessFinancials, {
name: 'view_financials',
description: 'View financial reports and data',
schema: z.object({
reportType: z.enum(['revenue', 'expenses', 'profit'])
})
})
// HR data - HR department or admins
.withToolIf(canAccessHR, {
name: 'view_employee_data',
description: 'View employee information',
schema: z.object({
employeeId: z.string()
})
})
// Export - requires feature flag AND write permission
.withToolIf(canExport, {
name: 'export_data',
description: 'Export data to various formats',
schema: z.object({
format: z.enum(['csv', 'json', 'excel'])
})
})
// Audit - requires feature flag AND admin permission
.withToolIf(canAudit, {
name: 'view_audit_log',
description: 'View system audit logs',
schema: z.object({
startDate: z.string(),
endDate: z.string()
})
})
// Constraints based on role
.withConstraintIf(
!canWrite,
'must_not',
'Never suggest modifying or creating documents'
)
.withConstraintIf(
!canDelete,
'must_not',
'Never suggest deleting any data'
)
.withConstraintIf(
ctx.isProd && canDelete,
'must',
'Always ask for confirmation before deleting anything in production'
)
// Department-specific constraints
.withConstraintIf(
ctx.department === 'finance',
'must',
'Handle all financial data with strict confidentiality'
)
.withConstraintIf(
ctx.department === 'hr',
'must',
'Comply with employee privacy regulations (GDPR, etc.)'
)
// Production safety
.withConstraintIf(
ctx.isProd,
'must',
'Exercise extreme caution with any data modifications'
)
.withConstraintIf(
!ctx.isProd,
'should',
'Feel free to experiment and test features'
);
}
// Usage examples
const viewerAgent = buildContextualAgent({
role: 'viewer',
department: 'sales',
isProd: true,
featureFlags: { enableAudit: false, enableExport: false }
});
console.log(viewerAgent.getSummary().toolsCount); // 1 (view only)
const editorAgent = buildContextualAgent({
role: 'editor',
department: 'engineering',
isProd: false,
featureFlags: { enableAudit: false, enableExport: true }
});
console.log(editorAgent.getSummary().toolsCount); // 4 (view, create, update, export)
const adminAgent = buildContextualAgent({
role: 'admin',
department: 'finance',
isProd: true,
featureFlags: { enableAudit: true, enableExport: true }
});
console.log(adminAgent.getSummary().toolsCount); // 8 (all tools)
Best Practices
Security Consideration: Always validate conditions server-side. Never trust client-provided permission flags - fetch them from your authorization system.
// ❌ DON'T: Trust client-provided permissions
function buildAgent(clientPermissions: any) {
return createPromptBuilder()
.withToolIf(clientPermissions.isAdmin, adminTool); // Unsafe!
}
// ✅ DO: Fetch permissions from server
async function buildAgent(userId: string) {
const permissions = await fetchUserPermissions(userId); // Server-side
return createPromptBuilder()
.withToolIf(permissions.isAdmin, adminTool); // Safe
}
Performance: Condition evaluation happens at build time, not at AI inference time. Feel free to use complex logic without worrying about runtime performance.
Use for permissions
Conditionally enable tools and constraints based on user roles and permissions
Use for feature flags
Gradually roll out new capabilities using feature flags
Use for tiers
Provide different capabilities based on subscription tiers
Use for environments
Adjust behavior based on dev/staging/prod environment