UNPKG

@candoa/workflows

Version:

Type-safe workflow SDK for Candoa with Copilot-friendly syntax. Define chat workflows with triggers, actions, and type safety.

530 lines (417 loc) • 13.6 kB
# @candoa/workflows Self-contained, type-safe workflow SDK for Candoa with Copilot-friendly syntax. Define chat workflows with triggers, actions, and full TypeScript support - no external dependencies required. ## šŸš€ Features - **Copilot-friendly syntax** - Optimized for GitHub Copilot autocompletion - **Type-safe** - Full TypeScript support with parameter validation - **Builder pattern** - Fluent API with method chaining - **Template variables** - Dynamic value substitution with `{{variableName}}` - **Pre-built actions** - Common workflow actions ready to use - **Self-contained** - No external dependencies, all types included - **Database integration** - Seamless integration with Candoa CRM - **Sync command** - Deploy workflows to database with `pnpm run sync-workflows` ## šŸ“¦ Installation ```bash npm install @candoa/workflows # or pnpm add @candoa/workflows ``` ## šŸ”„ Quick Start ```typescript import { workflow, collectFirstName, saveToContact } from '@candoa/workflows' export default workflow('welcome-new-user', { description: "Collects the user's first name when they start a chat", }) .on('chat.started') .use( collectFirstName({ prompt: "Hi! What's your first name?" }), saveToContact({ field: 'firstName', value: '{{firstName}}' }), ) ``` ## 🧠 Core Concepts ### Workflow Definition A workflow consists of: 1. **Name** - Unique identifier for the workflow 2. **Description** - Optional documentation 3. **Trigger** - Event that starts the workflow 4. **Actions** - Sequence of operations to execute ### Template Variables Use template variables to pass data between actions: ```typescript workflow('collect-contact-info') .on('chat.started') .use( collectFirstName({ prompt: "What's your first name?" }), collectEmail({ prompt: "What's your email address?" }), saveToContact({ field: 'firstName', value: '{{firstName}}' }), saveToContact({ field: 'email', value: '{{email}}' }), sendMessage({ message: "Thanks {{firstName}}! I've saved your information.", }), ) ``` ## šŸŽÆ Triggers Available trigger types with full TypeScript autocompletion: - `chat.started` - When a new chat session begins - `chat.ended` - When a chat session ends - `message.received` - When user sends a message - `intent.detected` - When AI detects specific intent - `sentiment.negative` - When negative sentiment is detected - `payment.failed` - When a payment fails - `user.signup` - When a user signs up - `custom.event` - For custom events ## ⚔ Actions ### Data Collection ```typescript // Collect user information collectFirstName({ prompt: "What's your first name?" }) collectLastName({ prompt: "What's your last name?" }) collectEmail({ prompt: "What's your email address?" }) // Save to contact record saveToContact({ field: 'firstName', value: '{{firstName}}' }) saveToContact({ field: 'email', value: '{{email}}' }) ``` ### Communication ```typescript // Send messages sendMessage({ message: 'Hello {{firstName}}!' }) sendMessage({ message: 'Please wait...', delay: 2000 }) // Send emails sendEmail({ to: '{{email}}', subject: 'Welcome to our platform!', body: 'Hi {{firstName}}, welcome aboard!', }) ``` ### Workflow Control ```typescript // Wait for a period wait({ duration: 5, unit: 'seconds' }) // Conditional logic conditional({ condition: "{{sentiment}} == 'negative'", trueAction: handoffToHuman({ reason: 'Negative sentiment detected' }), falseAction: sendMessage({ message: 'How else can I help you?' }), }) // Hand off to human agent handoffToHuman({ reason: 'Complex issue requiring human assistance', }) ``` ### Task Management ```typescript // Create tasks createTask({ title: 'Follow up with {{firstName}}', description: 'User expressed interest in premium features', }) // Add tags addTags({ tags: ['new-user', 'interested'], target: 'contact', }) ``` ## šŸ—„ļø Database Integration ### Workflow Storage Workflows are stored in your `workflows` table: ```sql CREATE TABLE "workflow" ( "id" text PRIMARY KEY, "projectId" text NOT NULL REFERENCES "project"("id"), "name" text NOT NULL, "workflowData" json NOT NULL, -- SDK data stored here "createdAt" timestamp DEFAULT now(), "updatedAt" timestamp DEFAULT now() ); ``` ### Manual Database Integration ```typescript import { prepareWorkflowForDatabase, validateWorkflowCompatibility, } from '@candoa/workflows' // 1. Define your workflow const welcomeWorkflow = workflow('welcome-new-user', { description: "Collects the user's first name when they start a chat", }) .on('chat.started') .use( collectFirstName({ prompt: "Hi! What's your first name?" }), saveToContact({ field: 'firstName', value: '{{firstName}}' }), ) // 2. Validate workflow const validation = validateWorkflowCompatibility(welcomeWorkflow) if (!validation.isValid) { console.error('Validation errors:', validation.errors) return } // 3. Prepare for database const dbData = prepareWorkflowForDatabase(welcomeWorkflow, projectId) // 4. Insert into database await db.insert(workflows).values({ id: crypto.randomUUID(), name: dbData.name, projectId: dbData.projectId, workflowData: dbData.workflowData, }) ``` ## šŸ”„ Workflow Sync System ### Quick Sync Create workflows in files and sync them to your database: ```bash # Sync all workflows to your project pnpm run sync-workflows --project-id=your-project-uuid # Preview changes without applying them pnpm run sync-workflows --project-id=your-project-uuid --dry-run # Force overwrite existing workflows pnpm run sync-workflows --project-id=your-project-uuid --force ``` ### Directory Structure The sync script discovers workflows in these locations: ``` packages/workflows/ ā”œā”€ā”€ examples/ # šŸ“ Example workflows (use as templates) │ ā”œā”€ā”€ welcome.ts │ ā”œā”€ā”€ candoa-integration.ts │ └── advanced-workflows.ts └── scripts/ └── sync-workflows.ts # šŸ”§ Sync script ``` ### Workflow File Format Export workflows from your files: ```typescript // workflows/my-workflows.ts import { workflow, sendMessage, collectFirstName } from '@candoa/workflows' // āœ… Default export export default workflow('welcome', { description: 'Welcome new users', }) .on('chat.started') .use( sendMessage({ message: 'Welcome!' }), collectFirstName({ prompt: "What's your name?" }), ) // āœ… Named exports export const supportFlow = workflow('support-flow', { description: 'Handle support requests', }) .on('intent.detected') .use(sendMessage({ message: 'I can help with that!' })) ``` ### Sync Output ``` šŸ”„ Candoa Workflow Sync ======================== šŸ“ Project ID: 0e8b8d5e-cade-4bf5-9e9f-c9e55a5d5ca0 šŸ“‹ Found 1 workflow file: - /examples/welcome.ts šŸ” Processing: /examples/welcome.ts šŸ“ Syncing workflow: new-user-onboarding āœ… Created: new-user-onboarding šŸ“ Syncing workflow: frustration-escalation āœ… Created: frustration-escalation šŸ“Š Sync Summary =============== āœ… Created: 2 šŸ”„ Updated: 0 ā­ļø Skipped: 1 āŒ Errors: 0 šŸŽ‰ Successfully synced 2 workflows! ``` ## šŸŽØ Integration with Candoa Systems ### Contact Management Works with your existing contact schema: ```typescript const contactWorkflow = workflow('contact-creation', { description: 'Create comprehensive contact records', }) .on('chat.started') .use( collectFirstName({ prompt: "What's your first name?" }), collectEmail({ prompt: "What's your email?" }), saveToContact({ field: 'firstName', value: '{{firstName}}' }), saveToContact({ field: 'email', value: '{{email}}' }), addTags({ tags: ['new-contact'], target: 'contact' }), ) ``` ### Automated Handoff Integration Enhances your existing handoff system: ```typescript const smartHandoff = workflow('smart-handoff', { description: 'Intelligent handoff with data collection', }) .on('sentiment.negative') .use( sendMessage({ message: 'Let me connect you with a human agent.', }), collectFirstName({ prompt: "What's your name?" }), saveToContact({ field: 'firstName', value: '{{firstName}}' }), handoffToHuman({ reason: 'Negative sentiment with contact data', }), ) ``` ### Execution Context Build context from your database: ```typescript import { buildWorkflowContext } from '@candoa/workflows' const context = buildWorkflowContext({ conversationId: conversation.id, contactData: { id: contact.id, firstName: contact.name?.split(' ')[0], email: contact.email, phoneNumber: contact.phoneNumber, }, messageHistory: messages.map((msg) => ({ role: msg.role, content: msg.content, createdAt: msg.createdAt, })), triggerData: { sentiment: 'negative', intent: 'billing_question', }, }) ``` ## šŸ“– Advanced Examples ### Customer Onboarding Flow ```typescript export const customerOnboarding = workflow('customer-onboarding', { description: 'Complete customer onboarding process', }) .on('user.signup') .use( sendMessage({ message: "Welcome! Let's get you set up in just a few steps.", }), collectFirstName({ prompt: "First, what's your first name?" }), collectEmail({ prompt: "What's your email address?" }), saveToContact({ field: 'firstName', value: '{{firstName}}' }), saveToContact({ field: 'email', value: '{{email}}' }), sendMessage({ message: 'Perfect! Welcome aboard {{firstName}} šŸŽ‰' }), addTags({ tags: ['onboarded'], target: 'contact' }), createTask({ title: 'Send welcome materials to {{firstName}}', assignee: 'onboarding-team', }), ) ``` ### Support Escalation ```typescript export const supportEscalation = workflow('support-escalation', { description: 'Escalate negative sentiment to human agents', }) .on('sentiment.negative') .use( sendMessage({ message: 'I sense you might be frustrated. Let me get you connected with a human agent.', }), handoffToHuman({ reason: 'Negative sentiment detected', }), createTask({ title: 'Urgent: Frustrated customer needs assistance', }), addTags({ tags: ['escalated', 'urgent'], target: 'conversation' }), ) ``` ### Payment Recovery ```typescript export const paymentRecovery = workflow('payment-recovery', { description: 'Handle failed payment with automated retry', }) .on('payment.failed') .use( sendMessage({ message: 'It looks like there was an issue with your payment. Let me help you resolve this.', }), wait({ duration: 1, unit: 'hours' }), sendEmail({ to: '{{email}}', subject: 'Payment Issue - Action Required', body: 'Hi {{firstName}}, we had trouble processing your payment. Please update your payment method.', }), createTask({ title: 'Follow up on failed payment for {{firstName}}', description: 'Payment failed, email sent, needs follow-up', }), ) ``` ## šŸ“Š Analytics & Monitoring ### Workflow Performance Tracking ```typescript import { extractWorkflowMetrics, updateWorkflowStats } from '@candoa/workflows' // After workflow execution const metrics = extractWorkflowMetrics(workflowDef, { success: true, executionTime: 1250, // milliseconds actionsCompleted: 5, }) // Update workflow stats in database const updatedWorkflowData = updateWorkflowStats( existingWorkflow.workflowData, true, // was successful ) await db .update(workflows) .set({ workflowData: updatedWorkflowData }) .where(eq(workflows.id, workflowId)) ``` ## šŸ› ļø Best Practices ### Organization - Keep production workflows in `workflows/` directory - Use `examples/` for testing and documentation - Group related workflows in the same file - Use descriptive workflow names and descriptions ### Naming Conventions - Use kebab-case for workflow names: `new-user-onboarding` - Include purpose in name: `support-ticket-creation` - Avoid conflicts with existing workflows ### Development Workflow 1. **Develop** workflows locally using the SDK 2. **Test** with `--dry-run` flag first 3. **Sync** to staging environment 4. **Validate** in CRM interface 5. **Deploy** to production ### Version Control - Commit workflow files to your repository - Tag releases for workflow deployments - Document changes in workflow descriptions - Use branches for workflow development ## šŸ› Troubleshooting ### Common Sync Issues **Project ID required:** ```bash # āŒ Missing project ID pnpm run sync-workflows # āœ… Provide project ID pnpm run sync-workflows --project-id=your-uuid ``` **Workflow already exists:** ```bash # āŒ Workflow exists, won't overwrite pnpm run sync-workflows --project-id=your-uuid # āœ… Use force flag to overwrite pnpm run sync-workflows --project-id=your-uuid --force ``` **Validation errors:** - Check workflow structure matches SDK format - Ensure all required fields are present - Verify action parameters are valid - Review error details in sync output ### Getting Help - Review workflow examples in `examples/` directory - Check sync output for detailed error messages - Use `--dry-run` to preview changes without applying - Validate workflows before syncing ## šŸŽØ IDE Support This SDK is optimized for modern IDEs and GitHub Copilot: - **Auto-completion** for trigger types, action parameters, and template variables - **Type checking** for all parameters and return types - **IntelliSense** documentation for all functions - **Error highlighting** for invalid configurations ## šŸ“„ License MIT License - see LICENSE file for details