From 54a3d4644db8f70d26ccca42142778932edd65ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Valverde?= Date: Thu, 31 Jul 2025 17:42:50 +0200 Subject: [PATCH 01/14] Implementation of Whatsapp adapter --- .../community-whatsapp/ARCHITECTURE.md | 315 ++++++++ .../integrations/community-whatsapp/README.md | 199 +++++ .../community-whatsapp/jest.config.js | 8 + .../community-whatsapp/package.json | 36 + .../src/agents/enhanced-whatsapp-agent.ts | 129 +++ .../src/agents/whatsapp-agent.ts | 178 +++++ .../src/examples/ai-integration.ts | 194 +++++ .../src/examples/basic-usage.ts | 88 +++ .../src/examples/express-server.ts | 82 ++ .../community-whatsapp/src/index.ts | 12 + .../src/providers/anthropic-provider.ts | 34 + .../community-whatsapp/src/providers/index.ts | 2 + .../src/providers/openai-provider.ts | 34 + .../community-whatsapp/src/tests/ai-test.ts | 81 ++ .../src/tests/simple-test.ts | 75 ++ .../src/tests/whatsapp-agent.test.ts | 217 ++++++ .../community-whatsapp/src/types/index.ts | 180 +++++ .../community-whatsapp/src/utils/index.ts | 2 + .../src/utils/message-converter.ts | 61 ++ .../community-whatsapp/src/utils/webhook.ts | 30 + .../community-whatsapp/tsconfig.json | 26 + .../community-whatsapp/tsup.config.ts | 10 + typescript-sdk/pnpm-lock.yaml | 736 ++++++------------ 23 files changed, 2233 insertions(+), 496 deletions(-) create mode 100644 typescript-sdk/integrations/community-whatsapp/ARCHITECTURE.md create mode 100644 typescript-sdk/integrations/community-whatsapp/README.md create mode 100644 typescript-sdk/integrations/community-whatsapp/jest.config.js create mode 100644 typescript-sdk/integrations/community-whatsapp/package.json create mode 100644 typescript-sdk/integrations/community-whatsapp/src/agents/enhanced-whatsapp-agent.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/agents/whatsapp-agent.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/examples/ai-integration.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/examples/basic-usage.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/examples/express-server.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/index.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/providers/anthropic-provider.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/providers/index.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/providers/openai-provider.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/tests/ai-test.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/tests/simple-test.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/tests/whatsapp-agent.test.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/types/index.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/utils/index.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/utils/message-converter.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/src/utils/webhook.ts create mode 100644 typescript-sdk/integrations/community-whatsapp/tsconfig.json create mode 100644 typescript-sdk/integrations/community-whatsapp/tsup.config.ts diff --git a/typescript-sdk/integrations/community-whatsapp/ARCHITECTURE.md b/typescript-sdk/integrations/community-whatsapp/ARCHITECTURE.md new file mode 100644 index 000000000..9926f56c8 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/ARCHITECTURE.md @@ -0,0 +1,315 @@ +# WhatsApp Integration Architecture + +This document provides a comprehensive overview of the WhatsApp integration for AG-UI, explaining the architecture, components, and design decisions. + +## ๐Ÿ—๏ธ Architecture Overview + +The WhatsApp integration follows a modular, layered architecture designed for extensibility and maintainability: + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Public API Layer โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ WhatsAppAgent โ”‚ โ”‚EnhancedWhatsApp โ”‚ โ”‚ Utils โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ Agent โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Business Logic Layer โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Message Handler โ”‚ โ”‚ Webhook Proc. โ”‚ โ”‚ AI Provider โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Interface โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Data Layer โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ WhatsApp API โ”‚ โ”‚ Message Conv. โ”‚ โ”‚ Type Defs โ”‚ โ”‚ +โ”‚ โ”‚ Client โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +## ๐Ÿ“ Directory Structure + +``` +src/ +โ”œโ”€โ”€ agents/ # Core agent implementations +โ”‚ โ”œโ”€โ”€ whatsapp-agent.ts # Basic WhatsApp agent +โ”‚ โ””โ”€โ”€ enhanced-whatsapp-agent.ts # AI-powered agent +โ”œโ”€โ”€ providers/ # AI provider implementations +โ”‚ โ”œโ”€โ”€ openai-provider.ts # OpenAI integration +โ”‚ โ”œโ”€โ”€ anthropic-provider.ts # Anthropic integration +โ”‚ โ””โ”€โ”€ index.ts # Provider exports +โ”œโ”€โ”€ types/ # TypeScript type definitions +โ”‚ โ””โ”€โ”€ index.ts # All interfaces and types +โ”œโ”€โ”€ utils/ # Utility functions +โ”‚ โ”œโ”€โ”€ webhook.ts # Webhook processing utilities +โ”‚ โ”œโ”€โ”€ message-converter.ts # Message format conversion +โ”‚ โ””โ”€โ”€ index.ts # Utility exports +โ”œโ”€โ”€ examples/ # Usage examples +โ”‚ โ”œโ”€โ”€ basic-usage.ts # Basic WhatsApp usage +โ”‚ โ”œโ”€โ”€ ai-integration.ts # AI integration examples +โ”‚ โ””โ”€โ”€ express-server.ts # Express.js server example +โ”œโ”€โ”€ tests/ # Test files +โ”‚ โ”œโ”€โ”€ simple-test.ts # Basic functionality tests +โ”‚ โ”œโ”€โ”€ ai-test.ts # AI functionality tests +โ”‚ โ””โ”€โ”€ whatsapp-agent.test.ts # Unit tests +โ””โ”€โ”€ index.ts # Main exports +``` + +## ๐Ÿงฉ Core Components + +### 1. WhatsAppAgent (Base Agent) + +**Purpose**: Provides basic WhatsApp Business API integration without AI capabilities. + +**Key Features**: +- Webhook signature verification +- Message sending and receiving +- Message format conversion +- AG-UI event system integration + +**Core Methods**: +```typescript +class WhatsAppAgent extends AbstractAgent { + verifyWebhookSignature(body: string, signature: string): boolean + processWebhook(body: WhatsAppWebhookEntry): WhatsAppMessage[] + sendTextMessage(to: string, text: string): Promise + convertWhatsAppMessageToAGUI(whatsappMessage: WhatsAppMessage): Message + handleWebhook(body: string, signature: string): Promise +} +``` + +### 2. EnhancedWhatsAppAgent (AI-Powered Agent) + +**Purpose**: Extends the base agent with AI capabilities for intelligent responses. + +**Key Features**: +- All features from WhatsAppAgent +- AI provider integration +- Configurable system prompts +- Dynamic AI parameter adjustment + +**Core Methods**: +```typescript +class EnhancedWhatsAppAgent extends WhatsAppAgent { + setAIProvider(provider: AIProvider | undefined): void + setSystemPrompt(prompt: string): void + setAIParameters(maxTokens: number, temperature: number): void + handleWebhookWithAI(body: string, signature: string): Promise +} +``` + +### 3. AI Providers + +**Purpose**: Abstract AI service integrations for generating intelligent responses. + +**Available Providers**: +- `OpenAIProvider`: Integration with OpenAI GPT models +- `AnthropicProvider`: Integration with Anthropic Claude models + +**Interface**: +```typescript +interface AIProvider { + generateResponse(messages: any[], context?: any): Promise +} +``` + +### 4. Utilities + +**Purpose**: Reusable functions for common operations. + +**Webhook Utilities** (`utils/webhook.ts`): +- `verifyWebhookSignature()`: Verify WhatsApp webhook authenticity +- `processWebhook()`: Extract messages from webhook payload + +**Message Conversion** (`utils/message-converter.ts`): +- `convertWhatsAppMessageToAGUI()`: Convert WhatsApp โ†’ AG-UI format +- `convertAGUIMessageToWhatsApp()`: Convert AG-UI โ†’ WhatsApp format + +## ๐Ÿ”„ Data Flow + +### 1. Incoming Message Flow + +``` +WhatsApp Webhook โ†’ verifyWebhookSignature() โ†’ processWebhook() โ†’ +convertWhatsAppMessageToAGUI() โ†’ AG-UI Message โ†’ Agent Processing +``` + +### 2. Outgoing Message Flow + +``` +AG-UI Response โ†’ convertAGUIMessageToWhatsApp() โ†’ +WhatsApp API โ†’ Message Delivered +``` + +### 3. AI-Enhanced Flow + +``` +Incoming Message โ†’ AI Provider โ†’ generateResponse() โ†’ +Enhanced Response โ†’ WhatsApp API โ†’ Message Delivered +``` + +## ๐Ÿ›ก๏ธ Security Features + +### Webhook Signature Verification + +The integration implements HMAC-SHA256 signature verification to ensure webhook authenticity: + +```typescript +function verifyWebhookSignature(body: string, signature: string, webhookSecret: string): boolean { + const expectedSignature = createHmac("sha256", webhookSecret) + .update(body) + .digest("hex"); + + return signature === `sha256=${expectedSignature}`; +} +``` + +### Configuration Security + +- Access tokens are stored securely +- Webhook secrets are used for verification +- API credentials are validated before use + +## ๐Ÿ”ง Message Type Support + +The integration supports all major WhatsApp message types: + +| WhatsApp Type | AG-UI Conversion | Description | +|---------------|------------------|-------------| +| `text` | Direct content | Plain text messages | +| `image` | `[Image]: caption` | Images with optional captions | +| `audio` | `[Audio message]` | Voice messages | +| `document` | `[Document: filename]` | File attachments | +| `video` | `[Video]: caption` | Video messages | +| `location` | `[Location: name at lat,lng]` | Location sharing | +| `contact` | `[Contact: name]` | Contact sharing | + +## ๐ŸŽฏ Design Principles + +### 1. Separation of Concerns +- **Agents**: Handle business logic and state management +- **Providers**: Abstract AI service integrations +- **Utils**: Provide reusable utility functions +- **Types**: Define clear interfaces and contracts + +### 2. Extensibility +- Easy to add new AI providers +- Modular message type support +- Pluggable webhook handlers +- Configurable agent behavior + +### 3. Type Safety +- Full TypeScript support +- Strict type checking +- Clear interface definitions +- Runtime type validation + +### 4. Error Handling +- Graceful error recovery +- Detailed error messages +- Fallback mechanisms +- Logging and monitoring + +## ๐Ÿš€ Extension Points + +### Adding New AI Providers + +1. Implement the `AIProvider` interface: +```typescript +class CustomAIProvider implements AIProvider { + async generateResponse(messages: any[], context?: any): Promise { + // Your AI integration logic + } +} +``` + +2. Export from providers: +```typescript +// src/providers/custom-provider.ts +export class CustomAIProvider implements AIProvider { ... } + +// src/providers/index.ts +export * from "./custom-provider"; +``` + +### Adding New Message Types + +1. Extend the `WhatsAppMessage` interface +2. Update the conversion utilities +3. Add type-specific handling logic + +### Custom Webhook Handlers + +1. Extend the base agent class +2. Override webhook processing methods +3. Add custom business logic + +## ๐Ÿ“Š Performance Considerations + +### Memory Management +- Efficient message conversion +- Minimal object allocation +- Proper cleanup of resources + +### API Rate Limiting +- Respect WhatsApp API limits +- Implement retry logic +- Handle rate limit errors gracefully + +### Caching Strategy +- Cache AI responses when appropriate +- Store conversation context +- Optimize repeated operations + +## ๐Ÿ” Testing Strategy + +### Unit Tests +- Individual component testing +- Mock external dependencies +- Validate type safety + +### Integration Tests +- End-to-end webhook testing +- AI provider integration +- Message flow validation + +### Performance Tests +- Load testing webhook handling +- AI response time measurement +- Memory usage monitoring + +## ๐Ÿ“ˆ Monitoring and Observability + +### Key Metrics +- Webhook processing time +- Message delivery success rate +- AI response generation time +- Error rates and types + +### Logging +- Structured logging for debugging +- Error tracking and alerting +- Performance monitoring +- Security event logging + +## ๐Ÿ”ฎ Future Enhancements + +### Planned Features +- Media message handling +- Message templates +- Typing indicators +- Message status tracking +- Multi-language support + +### Potential Integrations +- Additional AI providers +- Analytics platforms +- CRM integrations +- Custom business logic hooks + +--- + +This architecture provides a solid foundation for WhatsApp integration while maintaining flexibility for future enhancements and customizations. \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/README.md b/typescript-sdk/integrations/community-whatsapp/README.md new file mode 100644 index 000000000..479023730 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/README.md @@ -0,0 +1,199 @@ +# WhatsApp Integration for AG-UI + +This integration allows you to use AG-UI with WhatsApp Business API to create conversational AI agents that can interact with users through WhatsApp. + +## ๐Ÿ“š Tutorial: Getting Started with WhatsApp Business API + +Before using this integration, you need to set up WhatsApp Business API. Follow these steps: + +### Step 1: Create a Meta Developer Account + +1. Go to [Meta for Developers](https://developers.facebook.com/) +2. Create a new app or use an existing one +3. Add the **WhatsApp** product to your app + +### Step 2: Set Up WhatsApp Business API + +1. **Navigate to WhatsApp** in your Meta app dashboard +2. **Get Started** with WhatsApp Business API +3. **Add a Phone Number**: + - Click "Add phone number" + - Enter your business phone number + - Verify the number via SMS/call + - Note down the **Phone Number ID** (you'll need this) + +### Step 3: Generate Access Token + +1. Go to **System Users** in your Meta app +2. Create a new system user or use existing one +3. **Generate Access Token**: + - Select your system user + - Click "Generate Token" + - Choose "WhatsApp Business API" permissions + - Copy the **Access Token** (keep it secure!) + +### Step 4: Configure Webhook + +1. **Set up your webhook endpoint** (e.g., `https://your-domain.com/webhook`) +2. **Configure webhook in Meta**: + - Go to WhatsApp โ†’ Configuration + - Add your webhook URL + - Set **Webhook Secret** (create a strong secret) + - Subscribe to these fields: + - `messages` + - `message_status` + - `message_template_status` + +### Step 5: Test Your Setup + +Use the [WhatsApp Business API Testing Guide](https://developers.facebook.com/docs/whatsapp/cloud-api/get-started) to verify your configuration. + +### ๐Ÿ”— Helpful Resources + +- [WhatsApp Business API Documentation](https://developers.facebook.com/docs/whatsapp) +- [Webhook Setup Guide](https://developers.facebook.com/docs/whatsapp/webhook) +- [Message Templates](https://developers.facebook.com/docs/whatsapp/message-templates) +- [API Reference](https://developers.facebook.com/docs/whatsapp/cloud-api/reference) + +## ๐Ÿš€ Installation + +```bash +npm install @ag-ui/community-whatsapp +``` + +## ๐Ÿ’ก Basic Usage + +```typescript +import { WhatsAppAgent } from "@ag-ui/community-whatsapp"; + +const agent = new WhatsAppAgent({ + phoneNumberId: "your-phone-number-id", // From Step 2 + accessToken: "your-access-token", // From Step 3 + webhookSecret: "your-webhook-secret", // From Step 4 + threadId: "conversation-id", +}); + +// Handle incoming webhook +await agent.handleWebhook(webhookBody, signature); + +// Send a message +await agent.sendMessageToNumber("1234567890", "Hello from AG-UI!"); +``` + +## ๐Ÿค– Enhanced Usage with AI Integration + +```typescript +import { EnhancedWhatsAppAgent, OpenAIProvider } from "@ag-ui/community-whatsapp"; + +// Create AI provider +const openAIProvider = new OpenAIProvider("your-openai-api-key"); + +// Create enhanced agent +const agent = new EnhancedWhatsAppAgent({ + phoneNumberId: "your-phone-number-id", + accessToken: "your-access-token", + webhookSecret: "your-webhook-secret", + aiProvider: openAIProvider, + systemPrompt: "You are a helpful customer service assistant.", + maxTokens: 200, + temperature: 0.7, +}); + +// Handle webhook with AI responses +await agent.handleWebhookWithAI(webhookBody, signature); +``` + +## โš™๏ธ Configuration + +### Basic Configuration +- `phoneNumberId`: Your WhatsApp Business API phone number ID (from Step 2) +- `accessToken`: Your WhatsApp Business API access token (from Step 3) +- `webhookSecret`: Secret for verifying webhook requests (from Step 4) +- `apiVersion`: WhatsApp API version (default: "v18.0") + +### Enhanced Configuration +- `aiProvider`: AI service provider (OpenAI, Anthropic, etc.) +- `systemPrompt`: System prompt for AI responses +- `maxTokens`: Maximum tokens for AI responses +- `temperature`: AI response creativity (0.0-1.0) + +## โœจ Features + +### Core Features +- โœ… Send and receive WhatsApp messages +- โœ… Handle media messages (images, audio, documents) +- โœ… Webhook verification with HMAC-SHA256 +- โœ… Message status tracking +- โœ… Typing indicators +- โœ… Message templates + +### AI Integration Features +- โœ… OpenAI GPT integration +- โœ… Anthropic Claude integration +- โœ… Custom AI provider support +- โœ… Dynamic AI provider switching +- โœ… Configurable system prompts +- โœ… Adjustable AI parameters + +## ๐Ÿ“– Examples + +### Express.js Server +```typescript +import { createExpressServer } from "@ag-ui/community-whatsapp"; + +const app = createExpressServer(); +app.listen(3000, () => { + console.log("WhatsApp server running on port 3000"); +}); +``` + +### Environment-based Configuration +```typescript +import { createAgentFromEnv } from "@ag-ui/community-whatsapp"; + +const agent = createAgentFromEnv(); +``` + +## ๐Ÿค– AI Providers + +### OpenAI +```typescript +import { OpenAIProvider } from "@ag-ui/community-whatsapp"; + +const openAIProvider = new OpenAIProvider("your-api-key", "gpt-4"); +``` + +### Anthropic Claude +```typescript +import { AnthropicProvider } from "@ag-ui/community-whatsapp"; + +const anthropicProvider = new AnthropicProvider("your-api-key", "claude-3-sonnet-20240229"); +``` + +## ๐Ÿ”ง Quick Test + +Test your setup with our simple test: + +```bash +npx tsx src/tests/simple-test.ts +``` + +## ๐Ÿ“š Documentation + +- [Architecture Documentation](./ARCHITECTURE.md) - Detailed technical overview +- [API Reference](https://developers.facebook.com/docs/whatsapp/cloud-api/reference) +- [Webhook Guide](https://developers.facebook.com/docs/whatsapp/webhook) + +## ๐Ÿค Contributing + +This is a community integration. Contributions are welcome! + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Add tests +5. Submit a pull request + +## ๐Ÿ“„ License + +MIT diff --git a/typescript-sdk/integrations/community-whatsapp/jest.config.js b/typescript-sdk/integrations/community-whatsapp/jest.config.js new file mode 100644 index 000000000..b83ca8420 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + testMatch: ["**/__tests__/**/*.test.ts"], + moduleNameMapping: { + "^@/(.*)$": "/src/$1", + }, +}; \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/package.json b/typescript-sdk/integrations/community-whatsapp/package.json new file mode 100644 index 000000000..5d6aea4b1 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/package.json @@ -0,0 +1,36 @@ +{ + "name": "@ag-ui/community-whatsapp", + "author": "Community Contributor", + "version": "0.0.1", + "description": "WhatsApp integration for AG-UI", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "sideEffects": false, + "files": [ + "dist/**" + ], + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "clean": "rm -rf dist .turbo node_modules", + "typecheck": "tsc --noEmit", + "test": "jest", + "link:global": "pnpm link --global", + "unlink:global": "pnpm unlink --global" + }, + "dependencies": { + "@ag-ui/client": "workspace:*" + }, + "peerDependencies": { + "rxjs": "7.8.1" + }, + "devDependencies": { + "@types/jest": "^29.5.14", + "@types/node": "^20.11.19", + "jest": "^29.7.0", + "ts-jest": "^29.1.2", + "tsup": "^8.0.2", + "typescript": "^5.3.3" + } +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/agents/enhanced-whatsapp-agent.ts b/typescript-sdk/integrations/community-whatsapp/src/agents/enhanced-whatsapp-agent.ts new file mode 100644 index 000000000..ec6124111 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/agents/enhanced-whatsapp-agent.ts @@ -0,0 +1,129 @@ +import { WhatsAppAgent } from "./whatsapp-agent"; +import { WhatsAppAgentConfig, AIProvider } from "../types"; + +export interface EnhancedWhatsAppAgentConfig extends WhatsAppAgentConfig { + aiProvider?: AIProvider; + systemPrompt?: string; + maxTokens?: number; + temperature?: number; +} + +export class EnhancedWhatsAppAgent extends WhatsAppAgent { + private aiProvider?: AIProvider; + private systemPrompt: string; + private maxTokens: number; + private temperature: number; + + constructor(config: EnhancedWhatsAppAgentConfig) { + super(config); + this.aiProvider = config.aiProvider; + this.systemPrompt = config.systemPrompt || "You are a helpful WhatsApp assistant. Respond naturally and concisely."; + this.maxTokens = config.maxTokens || 150; + this.temperature = config.temperature || 0.7; + } + + /** + * Generate AI response using the configured AI provider + */ + private async generateAIResponse(messages: any[]): Promise { + if (!this.aiProvider) { + // Fallback to simple echo response + const lastMessage = messages[messages.length - 1]; + return `I received your message: "${lastMessage.content}". This is a demo response.`; + } + + try { + const response = await this.aiProvider.generateResponse(messages, { + systemPrompt: this.systemPrompt, + maxTokens: this.maxTokens, + temperature: this.temperature, + }); + + return response; + } catch (error) { + console.error("Error generating AI response:", error); + return "I'm sorry, I'm having trouble processing your request right now. Please try again later."; + } + } + + /** + * Override the run method to use AI for generating responses + */ + protected async runWithAI(input: any): Promise { + // Convert messages to AI format + const aiMessages = input.messages.map((msg: any) => ({ + role: msg.role, + content: msg.content, + })); + + // Add system message + aiMessages.unshift({ + role: "system", + content: this.systemPrompt, + }); + + // Generate AI response + const aiResponse = await this.generateAIResponse(aiMessages); + + return { + messages: [ + { + role: "assistant", + content: aiResponse, + }, + ], + }; + } + + /** + * Enhanced webhook handler with AI integration + */ + async handleWebhookWithAI(body: string, signature: string): Promise { + // Verify webhook signature + if (!this.verifyWebhookSignature(body, signature)) { + throw new Error("Invalid webhook signature"); + } + + const webhookData = JSON.parse(body); + const messages = this.processWebhook(webhookData); + + // Process each message + for (const whatsappMessage of messages) { + const aguiMessage = this.convertWhatsAppMessageToAGUI(whatsappMessage); + this.addMessage(aguiMessage); + + // Generate AI response + const aiResult = await this.runWithAI({ + messages: (this as any).messages, + }); + + // Send the AI-generated response back to WhatsApp + if (aiResult.messages && aiResult.messages.length > 0) { + const responseMessage = aiResult.messages[0]; + await this.sendTextMessage(whatsappMessage.from, responseMessage.content); + } + } + } + + /** + * Set AI provider + */ + setAIProvider(provider: AIProvider | undefined): void { + this.aiProvider = provider; + } + + /** + * Update system prompt + */ + setSystemPrompt(prompt: string): void { + this.systemPrompt = prompt; + } + + /** + * Update AI parameters + */ + setAIParameters(maxTokens: number, temperature: number): void { + this.maxTokens = maxTokens; + this.temperature = temperature; + } +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/agents/whatsapp-agent.ts b/typescript-sdk/integrations/community-whatsapp/src/agents/whatsapp-agent.ts new file mode 100644 index 000000000..af66dc855 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/agents/whatsapp-agent.ts @@ -0,0 +1,178 @@ +import { AbstractAgent, BaseEvent, EventType, Message, RunAgentInput, TextMessageChunkEvent, RunStartedEvent, RunFinishedEvent } from "@ag-ui/client"; +import { Observable } from "rxjs"; +import { WhatsAppAgentConfig, WhatsAppMessage, WhatsAppSendMessageRequest, WhatsAppSendMessageResponse, WhatsAppWebhookEntry } from "../types"; +import { verifyWebhookSignature, processWebhook, convertWhatsAppMessageToAGUI, convertAGUIMessageToWhatsApp } from "../utils"; + +export class WhatsAppAgent extends AbstractAgent { + public phoneNumberId: string; + private accessToken: string; + private webhookSecret: string; + private apiVersion: string; + private baseUrl: string; + + constructor(config: WhatsAppAgentConfig) { + super(config); + this.phoneNumberId = config.phoneNumberId; + this.accessToken = config.accessToken; + this.webhookSecret = config.webhookSecret; + this.apiVersion = config.apiVersion || "v18.0"; + this.baseUrl = config.baseUrl || `https://graph.facebook.com/${this.apiVersion}`; + } + + /** + * Verify webhook signature from WhatsApp + */ + verifyWebhookSignature(body: string, signature: string): boolean { + return verifyWebhookSignature(body, signature, this.webhookSecret); + } + + /** + * Process incoming webhook from WhatsApp + */ + processWebhook(body: WhatsAppWebhookEntry): WhatsAppMessage[] { + return processWebhook(body); + } + + /** + * Send a message to WhatsApp + */ + async sendMessage(to: string, message: WhatsAppSendMessageRequest): Promise { + const url = `${this.baseUrl}/${this.phoneNumberId}/messages`; + + const response = await fetch(url, { + method: "POST", + headers: { + "Authorization": `Bearer ${this.accessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + ...message, + messaging_product: "whatsapp", + recipient_type: "individual", + to, + }), + }); + + if (!response.ok) { + const error = await response.json(); + throw new Error(`WhatsApp API error: ${error.error?.message || response.statusText}`); + } + + return response.json(); + } + + /** + * Send a text message + */ + async sendTextMessage(to: string, text: string): Promise { + return this.sendMessage(to, { + messaging_product: "whatsapp", + recipient_type: "individual", + to, + type: "text", + text: { + body: text, + }, + }); + } + + /** + * Convert WhatsApp message to AG-UI message format + */ + public convertWhatsAppMessageToAGUI(whatsappMessage: WhatsAppMessage): Message { + return convertWhatsAppMessageToAGUI(whatsappMessage); + } + + /** + * Convert AG-UI message to WhatsApp message format + */ + private convertAGUIMessageToWhatsApp(message: Message): WhatsAppSendMessageRequest { + return convertAGUIMessageToWhatsApp(message); + } + + /** + * Main run method that processes messages and generates responses + */ + protected run(input: RunAgentInput): Observable { + return new Observable((subscriber) => { + const run = async () => { + try { + // Emit run started event + const runStartedEvent: RunStartedEvent = { + type: EventType.RUN_STARTED, + threadId: input.threadId, + runId: input.runId, + }; + subscriber.next(runStartedEvent); + + // Process incoming messages + for (const message of input.messages) { + if (message.role === "user") { + // For now, we'll simulate a response + // In a real implementation, you would integrate with an AI service + const responseText = `Received: ${message.content}`; + + // Emit text chunks + const textChunkEvent: TextMessageChunkEvent = { + type: EventType.TEXT_MESSAGE_CHUNK, + role: "assistant", + messageId: message.id, + delta: responseText, + }; + subscriber.next(textChunkEvent); + } + } + + // Emit run finished event + const runFinishedEvent: RunFinishedEvent = { + type: EventType.RUN_FINISHED, + threadId: input.threadId, + runId: input.runId, + }; + subscriber.next(runFinishedEvent); + + subscriber.complete(); + } catch (error) { + subscriber.error(error); + } + }; + + run(); + }); + } + + /** + * Handle incoming webhook and process messages + */ + async handleWebhook(body: string, signature: string): Promise { + // Verify webhook signature + if (!this.verifyWebhookSignature(body, signature)) { + throw new Error("Invalid webhook signature"); + } + + const webhookData: WhatsAppWebhookEntry = JSON.parse(body); + const messages = this.processWebhook(webhookData); + + // Process each message + for (const whatsappMessage of messages) { + const aguiMessage = this.convertWhatsAppMessageToAGUI(whatsappMessage); + this.addMessage(aguiMessage); + + // Run the agent to generate a response + const result = await this.runAgent(); + + // Send the response back to WhatsApp + if (result.newMessages.length > 0) { + const responseMessage = result.newMessages[0]; + await this.sendTextMessage(whatsappMessage.from, responseMessage.content || ""); + } + } + } + + /** + * Send a message to a specific WhatsApp number + */ + async sendMessageToNumber(phoneNumber: string, content: string): Promise { + return this.sendTextMessage(phoneNumber, content); + } +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/examples/ai-integration.ts b/typescript-sdk/integrations/community-whatsapp/src/examples/ai-integration.ts new file mode 100644 index 000000000..a7297aaf1 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/examples/ai-integration.ts @@ -0,0 +1,194 @@ +import { EnhancedWhatsAppAgent } from "../agents/enhanced-whatsapp-agent"; +import { OpenAIProvider, AnthropicProvider } from "../providers"; + +// Example: Using WhatsApp agent with OpenAI +export async function openAIExample() { + // Create OpenAI provider + const openAIProvider = new OpenAIProvider("your-openai-api-key", "gpt-4"); + + // Create enhanced WhatsApp agent + const agent = new EnhancedWhatsAppAgent({ + phoneNumberId: "your-phone-number-id", + accessToken: "your-access-token", + webhookSecret: "your-webhook-secret", + threadId: "whatsapp-ai-conversation", + aiProvider: openAIProvider, + systemPrompt: "You are a helpful customer service assistant for a tech company. Be friendly, professional, and concise.", + maxTokens: 200, + temperature: 0.7, + }); + + // Example webhook handler + const webhookHandler = async (req: any, res: any) => { + try { + const signature = req.headers["x-hub-signature-256"]; + const body = JSON.stringify(req.body); + + await agent.handleWebhookWithAI(body, signature); + + res.status(200).json({ status: "ok" }); + } catch (error) { + console.error("Webhook error:", error); + res.status(400).json({ error: "Invalid webhook" }); + } + }; + + return { agent, webhookHandler }; +} + +// Example: Using WhatsApp agent with Anthropic Claude +export async function anthropicExample() { + // Create Anthropic provider + const anthropicProvider = new AnthropicProvider("your-anthropic-api-key", "claude-3-sonnet-20240229"); + + // Create enhanced WhatsApp agent + const agent = new EnhancedWhatsAppAgent({ + phoneNumberId: "your-phone-number-id", + accessToken: "your-access-token", + webhookSecret: "your-webhook-secret", + threadId: "whatsapp-claude-conversation", + aiProvider: anthropicProvider, + systemPrompt: "You are Claude, an AI assistant helping users via WhatsApp. Be helpful, accurate, and conversational.", + maxTokens: 300, + temperature: 0.8, + }); + + return agent; +} + +// Example: Dynamic AI provider switching +export async function dynamicAIExample() { + const agent = new EnhancedWhatsAppAgent({ + phoneNumberId: "your-phone-number-id", + accessToken: "your-access-token", + webhookSecret: "your-webhook-secret", + threadId: "whatsapp-dynamic-conversation", + }); + + // Switch between AI providers based on user preference or availability + const switchToOpenAI = () => { + const openAIProvider = new OpenAIProvider("your-openai-api-key"); + agent.setAIProvider(openAIProvider); + agent.setSystemPrompt("You are an OpenAI-powered assistant."); + }; + + const switchToClaude = () => { + const anthropicProvider = new AnthropicProvider("your-anthropic-api-key"); + agent.setAIProvider(anthropicProvider); + agent.setSystemPrompt("You are Claude, an AI assistant."); + }; + + const disableAI = () => { + agent.setAIProvider(undefined); + }; + + return { agent, switchToOpenAI, switchToClaude, disableAI }; +} + +// Example: Express.js server with WhatsApp integration +export function createExpressServer() { + const express = require("express"); + const app = express(); + + // Create agent + const openAIProvider = new OpenAIProvider("your-openai-api-key"); + const agent = new EnhancedWhatsAppAgent({ + phoneNumberId: "your-phone-number-id", + accessToken: "your-access-token", + webhookSecret: "your-webhook-secret", + threadId: "whatsapp-express-conversation", + aiProvider: openAIProvider, + }); + + // Middleware + app.use(express.json()); + + // Webhook endpoint + app.post("/webhook", async (req: any, res: any) => { + try { + const signature = req.headers["x-hub-signature-256"]; + const body = JSON.stringify(req.body); + + await agent.handleWebhookWithAI(body, signature); + + res.status(200).json({ status: "ok" }); + } catch (error) { + console.error("Webhook error:", error); + res.status(400).json({ error: "Invalid webhook" }); + } + }); + + // Health check endpoint + app.get("/health", (req: any, res: any) => { + res.json({ status: "healthy", agent: "Express WhatsApp Assistant" }); + }); + + // Send message endpoint + app.post("/send", async (req: any, res: any) => { + try { + const { phoneNumber, message } = req.body; + + if (!phoneNumber || !message) { + return res.status(400).json({ error: "phoneNumber and message are required" }); + } + + const response = await agent.sendMessageToNumber(phoneNumber, message); + res.json(response); + } catch (error) { + console.error("Send message error:", error); + res.status(500).json({ error: "Failed to send message" }); + } + }); + + // Update AI settings endpoint + app.post("/ai-settings", (req: any, res: any) => { + try { + const { systemPrompt, maxTokens, temperature } = req.body; + + if (systemPrompt) { + agent.setSystemPrompt(systemPrompt); + } + + if (maxTokens && temperature) { + agent.setAIParameters(maxTokens, temperature); + } + + res.json({ status: "settings updated" }); + } catch (error) { + console.error("Settings update error:", error); + res.status(500).json({ error: "Failed to update settings" }); + } + }); + + return app; +} + +// Example: Environment-based configuration +export function createAgentFromEnv() { + const config = { + phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID!, + accessToken: process.env.WHATSAPP_ACCESS_TOKEN!, + webhookSecret: process.env.WHATSAPP_WEBHOOK_SECRET!, + threadId: process.env.THREAD_ID || "whatsapp-env-conversation", + }; + + // Add AI provider based on environment + if (process.env.OPENAI_API_KEY) { + const openAIProvider = new OpenAIProvider(process.env.OPENAI_API_KEY); + return new EnhancedWhatsAppAgent({ + ...config, + aiProvider: openAIProvider, + systemPrompt: process.env.SYSTEM_PROMPT || "You are a helpful assistant.", + }); + } else if (process.env.ANTHROPIC_API_KEY) { + const anthropicProvider = new AnthropicProvider(process.env.ANTHROPIC_API_KEY); + return new EnhancedWhatsAppAgent({ + ...config, + aiProvider: anthropicProvider, + systemPrompt: process.env.SYSTEM_PROMPT || "You are Claude, an AI assistant.", + }); + } else { + // No AI provider configured + return new EnhancedWhatsAppAgent(config); + } +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/examples/basic-usage.ts b/typescript-sdk/integrations/community-whatsapp/src/examples/basic-usage.ts new file mode 100644 index 000000000..f9983e26a --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/examples/basic-usage.ts @@ -0,0 +1,88 @@ +import { WhatsAppAgent } from "../agents/whatsapp-agent"; + +// Example usage of the WhatsApp agent +export async function exampleUsage() { + // Create a WhatsApp agent instance + const agent = new WhatsAppAgent({ + phoneNumberId: "your-phone-number-id", + accessToken: "your-access-token", + webhookSecret: "your-webhook-secret", + threadId: "whatsapp-conversation-1", + }); + + // Example: Handle incoming webhook + const webhookBody = `{ + "object": "whatsapp_business_account", + "entry": [ + { + "id": "123456789", + "changes": [ + { + "value": { + "messaging_product": "whatsapp", + "metadata": { + "display_phone_number": "+1234567890", + "phone_number_id": "your-phone-number-id" + }, + "contacts": [ + { + "profile": { + "name": "John Doe" + }, + "wa_id": "1234567890" + } + ], + "messages": [ + { + "from": "1234567890", + "id": "wamid.123456789", + "timestamp": "1234567890", + "type": "text", + "text": { + "body": "Hello, how are you?" + } + } + ] + }, + "field": "messages" + } + ] + } + ] + }`; + + const signature = "sha256=your-signature-here"; + + try { + // Handle the webhook + await agent.handleWebhook(webhookBody, signature); + console.log("Webhook processed successfully"); + } catch (error) { + console.error("Error processing webhook:", error); + } + + // Example: Send a message directly + try { + const response = await agent.sendMessageToNumber("1234567890", "Hello from AG-UI!"); + console.log("Message sent:", response); + } catch (error) { + console.error("Error sending message:", error); + } +} + +// Example Express.js webhook handler +export function createWebhookHandler(agent: WhatsAppAgent) { + return async (req: any, res: any) => { + try { + const signature = req.headers["x-hub-signature-256"]; + const body = JSON.stringify(req.body); + + await agent.handleWebhook(body, signature); + + res.status(200).json({ status: "ok" }); + } catch (error) { + console.error("Webhook error:", error); + res.status(400).json({ error: "Invalid webhook" }); + } + }; +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/examples/express-server.ts b/typescript-sdk/integrations/community-whatsapp/src/examples/express-server.ts new file mode 100644 index 000000000..2d37bbade --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/examples/express-server.ts @@ -0,0 +1,82 @@ +import { EnhancedWhatsAppAgent } from "../agents/enhanced-whatsapp-agent"; +import { OpenAIProvider } from "../providers"; + +/** + * Example Express.js server with WhatsApp integration + */ +export function createExpressServer() { + const express = require("express"); + const app = express(); + + // Create agent + const openAIProvider = new OpenAIProvider("your-openai-api-key"); + const agent = new EnhancedWhatsAppAgent({ + phoneNumberId: "your-phone-number-id", + accessToken: "your-access-token", + webhookSecret: "your-webhook-secret", + threadId: "whatsapp-express-conversation", + aiProvider: openAIProvider, + }); + + // Middleware + app.use(express.json()); + + // Webhook endpoint + app.post("/webhook", async (req: any, res: any) => { + try { + const signature = req.headers["x-hub-signature-256"]; + const body = JSON.stringify(req.body); + + await agent.handleWebhookWithAI(body, signature); + + res.status(200).json({ status: "ok" }); + } catch (error) { + console.error("Webhook error:", error); + res.status(400).json({ error: "Invalid webhook" }); + } + }); + + // Health check endpoint + app.get("/health", (req: any, res: any) => { + res.json({ status: "healthy", agent: "Express WhatsApp Assistant" }); + }); + + // Send message endpoint + app.post("/send", async (req: any, res: any) => { + try { + const { phoneNumber, message } = req.body; + + if (!phoneNumber || !message) { + return res.status(400).json({ error: "phoneNumber and message are required" }); + } + + const response = await agent.sendMessageToNumber(phoneNumber, message); + res.json(response); + } catch (error) { + console.error("Send message error:", error); + res.status(500).json({ error: "Failed to send message" }); + } + }); + + // Update AI settings endpoint + app.post("/ai-settings", (req: any, res: any) => { + try { + const { systemPrompt, maxTokens, temperature } = req.body; + + if (systemPrompt) { + agent.setSystemPrompt(systemPrompt); + } + + if (maxTokens && temperature) { + agent.setAIParameters(maxTokens, temperature); + } + + res.json({ status: "settings updated" }); + } catch (error) { + console.error("Settings update error:", error); + res.status(500).json({ error: "Failed to update settings" }); + } + }); + + return app; +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/index.ts b/typescript-sdk/integrations/community-whatsapp/src/index.ts new file mode 100644 index 000000000..67a00a904 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/index.ts @@ -0,0 +1,12 @@ +// Core agents +export * from "./agents/whatsapp-agent"; +export * from "./agents/enhanced-whatsapp-agent"; + +// AI providers +export * from "./providers"; + +// Types +export * from "./types"; + +// Utilities +export * from "./utils"; \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/providers/anthropic-provider.ts b/typescript-sdk/integrations/community-whatsapp/src/providers/anthropic-provider.ts new file mode 100644 index 000000000..0674ad0dd --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/providers/anthropic-provider.ts @@ -0,0 +1,34 @@ +import { AIProvider } from "../types"; + +export class AnthropicProvider implements AIProvider { + private apiKey: string; + private model: string; + + constructor(apiKey: string, model: string = "claude-3-sonnet-20240229") { + this.apiKey = apiKey; + this.model = model; + } + + async generateResponse(messages: any[], context?: any): Promise { + const response = await fetch("https://api.anthropic.com/v1/messages", { + method: "POST", + headers: { + "Authorization": `Bearer ${this.apiKey}`, + "Content-Type": "application/json", + "anthropic-version": "2023-06-01", + }, + body: JSON.stringify({ + model: this.model, + max_tokens: context?.maxTokens || 150, + messages, + }), + }); + + if (!response.ok) { + throw new Error(`Anthropic API error: ${response.statusText}`); + } + + const data = await response.json(); + return data.content[0].text; + } +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/providers/index.ts b/typescript-sdk/integrations/community-whatsapp/src/providers/index.ts new file mode 100644 index 000000000..9406add47 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/providers/index.ts @@ -0,0 +1,2 @@ +export * from "./openai-provider"; +export * from "./anthropic-provider"; \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/providers/openai-provider.ts b/typescript-sdk/integrations/community-whatsapp/src/providers/openai-provider.ts new file mode 100644 index 000000000..8a111b78a --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/providers/openai-provider.ts @@ -0,0 +1,34 @@ +import { AIProvider } from "../types"; + +export class OpenAIProvider implements AIProvider { + private apiKey: string; + private model: string; + + constructor(apiKey: string, model: string = "gpt-3.5-turbo") { + this.apiKey = apiKey; + this.model = model; + } + + async generateResponse(messages: any[], context?: any): Promise { + const response = await fetch("https://api.openai.com/v1/chat/completions", { + method: "POST", + headers: { + "Authorization": `Bearer ${this.apiKey}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + model: this.model, + messages, + max_tokens: context?.maxTokens || 150, + temperature: context?.temperature || 0.7, + }), + }); + + if (!response.ok) { + throw new Error(`OpenAI API error: ${response.statusText}`); + } + + const data = await response.json(); + return data.choices[0].message.content; + } +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/tests/ai-test.ts b/typescript-sdk/integrations/community-whatsapp/src/tests/ai-test.ts new file mode 100644 index 000000000..6575a1747 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/tests/ai-test.ts @@ -0,0 +1,81 @@ +import { EnhancedWhatsAppAgent } from "../agents/enhanced-whatsapp-agent"; + +// Test the enhanced WhatsApp agent with AI +export async function aiTest() { + console.log("๐Ÿค– Creating Enhanced WhatsApp Agent with AI..."); + + // Create an enhanced agent (without real AI provider for demo) + const agent = new EnhancedWhatsAppAgent({ + phoneNumberId: "test-phone-id", + accessToken: "test-access-token", + webhookSecret: "test-webhook-secret", + threadId: "ai-conversation", + systemPrompt: "You are a helpful WhatsApp assistant. Be friendly and concise.", + maxTokens: 150, + temperature: 0.7, + }); + + console.log("โœ… Enhanced agent created successfully!"); + console.log("๐Ÿง  System prompt:", agent.setSystemPrompt); + console.log("๐Ÿ“ Max tokens:", 150); + console.log("๐ŸŒก๏ธ Temperature:", 0.7); + + // Test AI response generation (will use fallback since no AI provider) + console.log("\n๐Ÿค– Testing AI response generation..."); + + const testMessages = [ + { role: "user", content: "Hello, how are you?" } + ]; + + // This will use the fallback response since no AI provider is configured + const response = await (agent as any).generateAIResponse(testMessages); + console.log("โœ… AI response generated:"); + console.log(" Response:", response); + + // Test webhook handling with AI + console.log("\n๐Ÿ“จ Testing webhook handling with AI..."); + + const testWebhook = { + object: "whatsapp_business_account", + entry: [{ + id: "123456789", + changes: [{ + value: { + messaging_product: "whatsapp", + metadata: { + display_phone_number: "+1234567890", + phone_number_id: "test-phone-id" + }, + messages: [{ + id: "test-message-id", + from: "1234567890", + timestamp: "1234567890", + type: "text" as const, + text: { + body: "Hello from WhatsApp!" + } + }] + }, + field: "messages" + }] + }] + }; + + const webhookBody = JSON.stringify(testWebhook); + const signature = "sha256=test-signature"; + + try { + await agent.handleWebhookWithAI(webhookBody, signature); + console.log("โœ… Webhook handled with AI successfully!"); + } catch (error) { + console.log("โš ๏ธ Webhook handling failed (expected due to fake signature):", (error as Error).message); + } + + console.log("\n๐ŸŽ‰ AI test completed successfully!"); + return agent; +} + +// Run the test if this file is executed directly +if (require.main === module) { + aiTest().catch(console.error); +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/tests/simple-test.ts b/typescript-sdk/integrations/community-whatsapp/src/tests/simple-test.ts new file mode 100644 index 000000000..7d5d1fae8 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/tests/simple-test.ts @@ -0,0 +1,75 @@ +import { WhatsAppAgent } from "../agents/whatsapp-agent"; + +// Simple test to understand the WhatsApp agent +export async function simpleTest() { + console.log("๐Ÿค– Creating WhatsApp Agent..."); + + // Create a basic WhatsApp agent + const agent = new WhatsAppAgent({ + phoneNumberId: "test-phone-id", + accessToken: "test-access-token", + webhookSecret: "test-webhook-secret", + threadId: "test-conversation", + }); + + console.log("โœ… Agent created successfully!"); + console.log("๐Ÿ“ฑ Phone Number ID:", agent.phoneNumberId); + console.log("๐Ÿงต Thread ID:", agent.threadId); + + // Test webhook signature verification + console.log("\n๐Ÿ” Testing webhook signature verification..."); + const testBody = '{"test": "data"}'; + const testSignature = "sha256=1234567890abcdef"; + + const isValid = agent.verifyWebhookSignature(testBody, testSignature); + console.log("โœ… Signature verification test completed (result:", isValid, ")"); + + // Test message conversion + console.log("\n๐Ÿ“ Testing message conversion..."); + const whatsappMessage = { + id: "test-message-id", + from: "1234567890", + timestamp: "1234567890", + type: "text" as const, + text: { + body: "Hello from WhatsApp!" + } + }; + + const aguiMessage = agent.convertWhatsAppMessageToAGUI(whatsappMessage); + console.log("โœ… WhatsApp message converted to AG-UI format:"); + console.log(" ID:", aguiMessage.id); + console.log(" Role:", aguiMessage.role); + console.log(" Content:", aguiMessage.content); + + // Test webhook processing + console.log("\n๐Ÿ“จ Testing webhook processing..."); + const testWebhook = { + object: "whatsapp_business_account", + entry: [{ + id: "123456789", + changes: [{ + value: { + messaging_product: "whatsapp", + metadata: { + display_phone_number: "+1234567890", + phone_number_id: "test-phone-id" + }, + messages: [whatsappMessage] + }, + field: "messages" + }] + }] + }; + + const messages = agent.processWebhook(testWebhook); + console.log("โœ… Webhook processed, found", messages.length, "message(s)"); + + console.log("\n๐ŸŽ‰ All tests completed successfully!"); + return agent; +} + +// Run the test if this file is executed directly +if (require.main === module) { + simpleTest().catch(console.error); +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/tests/whatsapp-agent.test.ts b/typescript-sdk/integrations/community-whatsapp/src/tests/whatsapp-agent.test.ts new file mode 100644 index 000000000..f560f15f7 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/tests/whatsapp-agent.test.ts @@ -0,0 +1,217 @@ +import { WhatsAppAgent } from "../agents/whatsapp-agent"; +import { WhatsAppMessage } from "../types"; + +describe("WhatsAppAgent", () => { + let agent: WhatsAppAgent; + + beforeEach(() => { + agent = new WhatsAppAgent({ + phoneNumberId: "test-phone-number-id", + accessToken: "test-access-token", + webhookSecret: "test-webhook-secret", + description: "Test WhatsApp Agent", + threadId: "test-thread-id", + }); + }); + + describe("constructor", () => { + it("should create a WhatsApp agent with correct configuration", () => { + expect(agent).toBeInstanceOf(WhatsAppAgent); + expect(agent.description).toBe("Test WhatsApp Agent"); + expect(agent.threadId).toBe("test-thread-id"); + }); + + it("should use default API version when not provided", () => { + const agentWithDefaults = new WhatsAppAgent({ + phoneNumberId: "test-phone-number-id", + accessToken: "test-access-token", + webhookSecret: "test-webhook-secret", + }); + + expect(agentWithDefaults).toBeInstanceOf(WhatsAppAgent); + }); + }); + + describe("verifyWebhookSignature", () => { + it("should verify valid webhook signature", () => { + const body = '{"test": "data"}'; + const signature = "sha256=1234567890abcdef"; + + // Mock the crypto module + const mockCreateHmac = jest.fn().mockReturnValue({ + update: jest.fn().mockReturnThis(), + digest: jest.fn().mockReturnValue("1234567890abcdef"), + }); + + jest.doMock("crypto", () => ({ + createHmac: mockCreateHmac, + })); + + const result = agent.verifyWebhookSignature(body, signature); + expect(result).toBe(true); + }); + + it("should reject invalid webhook signature", () => { + const body = '{"test": "data"}'; + const signature = "sha256=invalid-signature"; + + const mockCreateHmac = jest.fn().mockReturnValue({ + update: jest.fn().mockReturnThis(), + digest: jest.fn().mockReturnValue("1234567890abcdef"), + }); + + jest.doMock("crypto", () => ({ + createHmac: mockCreateHmac, + })); + + const result = agent.verifyWebhookSignature(body, signature); + expect(result).toBe(false); + }); + }); + + describe("convertWhatsAppMessageToAGUI", () => { + it("should convert text message correctly", () => { + const whatsappMessage: WhatsAppMessage = { + id: "test-message-id", + from: "1234567890", + timestamp: "1234567890", + type: "text", + text: { + body: "Hello, world!", + }, + }; + + const result = (agent as any).convertWhatsAppMessageToAGUI(whatsappMessage); + + expect(result).toEqual({ + id: "test-message-id", + role: "user", + content: "Hello, world!", + timestamp: expect.any(String), + }); + }); + + it("should convert image message correctly", () => { + const whatsappMessage: WhatsAppMessage = { + id: "test-message-id", + from: "1234567890", + timestamp: "1234567890", + type: "image", + image: { + id: "image-id", + mime_type: "image/jpeg", + sha256: "abc123", + caption: "Beautiful sunset", + }, + }; + + const result = (agent as any).convertWhatsAppMessageToAGUI(whatsappMessage); + + expect(result).toEqual({ + id: "test-message-id", + role: "user", + content: "[Image]: Beautiful sunset", + timestamp: expect.any(String), + }); + }); + + it("should convert audio message correctly", () => { + const whatsappMessage: WhatsAppMessage = { + id: "test-message-id", + from: "1234567890", + timestamp: "1234567890", + type: "audio", + audio: { + id: "audio-id", + mime_type: "audio/ogg", + sha256: "def456", + }, + }; + + const result = (agent as any).convertWhatsAppMessageToAGUI(whatsappMessage); + + expect(result).toEqual({ + id: "test-message-id", + role: "user", + content: "[Audio message]", + timestamp: expect.any(String), + }); + }); + }); + + describe("processWebhook", () => { + it("should extract messages from webhook data", () => { + const webhookData = { + object: "whatsapp_business_account", + entry: [ + { + id: "123456789", + changes: [ + { + value: { + messaging_product: "whatsapp", + metadata: { + display_phone_number: "+1234567890", + phone_number_id: "test-phone-number-id", + }, + messages: [ + { + id: "wamid.123456789", + from: "1234567890", + timestamp: "1234567890", + type: "text", + text: { + body: "Hello!", + }, + }, + ], + }, + field: "messages", + }, + ], + }, + ], + }; + + const messages = agent.processWebhook(webhookData); + + expect(messages).toHaveLength(1); + expect(messages[0]).toEqual({ + id: "wamid.123456789", + from: "1234567890", + timestamp: "1234567890", + type: "text", + text: { + body: "Hello!", + }, + }); + }); + + it("should handle webhook with no messages", () => { + const webhookData = { + object: "whatsapp_business_account", + entry: [ + { + id: "123456789", + changes: [ + { + value: { + messaging_product: "whatsapp", + metadata: { + display_phone_number: "+1234567890", + phone_number_id: "test-phone-number-id", + }, + }, + field: "messages", + }, + ], + }, + ], + }; + + const messages = agent.processWebhook(webhookData); + + expect(messages).toHaveLength(0); + }); + }); +}); \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/types/index.ts b/typescript-sdk/integrations/community-whatsapp/src/types/index.ts new file mode 100644 index 000000000..ff3b6defc --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/types/index.ts @@ -0,0 +1,180 @@ +import { AgentConfig } from "@ag-ui/client"; + +export interface AIProvider { + generateResponse(messages: any[], context?: any): Promise; +} + +export interface WhatsAppAgentConfig extends AgentConfig { + phoneNumberId: string; + accessToken: string; + webhookSecret: string; + apiVersion?: string; + baseUrl?: string; +} + +export interface WhatsAppMessage { + id: string; + from: string; + timestamp: string; + type: "text" | "image" | "audio" | "document" | "video" | "location" | "contact"; + text?: { + body: string; + }; + image?: { + id: string; + mime_type: string; + sha256: string; + caption?: string; + }; + audio?: { + id: string; + mime_type: string; + sha256: string; + }; + document?: { + id: string; + filename: string; + mime_type: string; + sha256: string; + }; + video?: { + id: string; + mime_type: string; + sha256: string; + caption?: string; + }; + location?: { + latitude: number; + longitude: number; + name?: string; + address?: string; + }; + contacts?: Array<{ + name: { + formatted_name: string; + first_name?: string; + last_name?: string; + }; + phones: Array<{ + phone: string; + type?: string; + }>; + }>; +} + +export interface WhatsAppWebhookEntry { + object: string; + entry: Array<{ + id: string; + changes: Array<{ + value: { + messaging_product: string; + metadata: { + display_phone_number: string; + phone_number_id: string; + }; + contacts?: Array<{ + profile: { + name: string; + }; + wa_id: string; + }>; + messages?: WhatsAppMessage[]; + statuses?: Array<{ + id: string; + status: "sent" | "delivered" | "read" | "failed"; + timestamp: string; + recipient_id: string; + }>; + }; + field: string; + }>; + }>; +} + +export interface WhatsAppSendMessageRequest { + messaging_product: string; + recipient_type: string; + to: string; + type: "text" | "image" | "audio" | "document" | "video" | "location" | "contact" | "template"; + text?: { + body: string; + preview_url?: boolean; + }; + image?: { + id?: string; + link?: string; + caption?: string; + }; + audio?: { + id?: string; + link?: string; + }; + document?: { + id?: string; + link?: string; + caption?: string; + filename?: string; + }; + video?: { + id?: string; + link?: string; + caption?: string; + }; + location?: { + latitude: number; + longitude: number; + name?: string; + address?: string; + }; + contacts?: Array<{ + name: { + formatted_name: string; + first_name?: string; + last_name?: string; + }; + phones: Array<{ + phone: string; + type?: string; + }>; + }>; + template?: { + name: string; + language: { + code: string; + }; + components?: Array<{ + type: string; + parameters?: Array<{ + type: string; + text?: string; + image?: { + link: string; + }; + }>; + }>; + }; +} + +export interface WhatsAppSendMessageResponse { + messaging_product: string; + contacts: Array<{ + input: string; + wa_id: string; + }>; + messages: Array<{ + id: string; + }>; +} + +export interface WhatsAppError { + error: { + message: string; + type: string; + code: number; + error_data?: { + details: string; + }; + fbtrace_id: string; + }; +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/utils/index.ts b/typescript-sdk/integrations/community-whatsapp/src/utils/index.ts new file mode 100644 index 000000000..de6fbfd60 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from "./webhook"; +export * from "./message-converter"; \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/utils/message-converter.ts b/typescript-sdk/integrations/community-whatsapp/src/utils/message-converter.ts new file mode 100644 index 000000000..59694d9cd --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/utils/message-converter.ts @@ -0,0 +1,61 @@ +import { Message } from "@ag-ui/client"; +import { WhatsAppMessage, WhatsAppSendMessageRequest } from "../types"; + +/** + * Convert WhatsApp message to AG-UI message format + */ +export function convertWhatsAppMessageToAGUI(whatsappMessage: WhatsAppMessage): Message { + let content = ""; + + switch (whatsappMessage.type) { + case "text": + content = whatsappMessage.text?.body || ""; + break; + case "image": + content = `[Image]${whatsappMessage.image?.caption ? `: ${whatsappMessage.image.caption}` : ""}`; + break; + case "audio": + content = "[Audio message]"; + break; + case "document": + content = `[Document: ${whatsappMessage.document?.filename || "Unknown file"}]`; + break; + case "video": + content = `[Video]${whatsappMessage.video?.caption ? `: ${whatsappMessage.video.caption}` : ""}`; + break; + case "location": + const location = whatsappMessage.location; + content = `[Location: ${location?.name || "Unknown location"} at ${location?.latitude}, ${location?.longitude}]`; + break; + case "contact": + const contacts = whatsappMessage.contacts; + if (contacts && contacts.length > 0) { + const contact = contacts[0]; + content = `[Contact: ${contact.name.formatted_name}]`; + } + break; + default: + content = `[${whatsappMessage.type} message]`; + } + + return { + id: whatsappMessage.id, + role: "user", + content, + }; +} + +/** + * Convert AG-UI message to WhatsApp message format + */ +export function convertAGUIMessageToWhatsApp(message: Message): WhatsAppSendMessageRequest { + return { + messaging_product: "whatsapp", + recipient_type: "individual", + to: "", // This will be set by the caller + type: "text", + text: { + body: message.content || "", + }, + }; +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/src/utils/webhook.ts b/typescript-sdk/integrations/community-whatsapp/src/utils/webhook.ts new file mode 100644 index 000000000..6ed2b35e2 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/src/utils/webhook.ts @@ -0,0 +1,30 @@ +import { createHmac } from "crypto"; +import { WhatsAppWebhookEntry, WhatsAppMessage } from "../types"; + +/** + * Verify webhook signature from WhatsApp + */ +export function verifyWebhookSignature(body: string, signature: string, webhookSecret: string): boolean { + const expectedSignature = createHmac("sha256", webhookSecret) + .update(body) + .digest("hex"); + + return signature === `sha256=${expectedSignature}`; +} + +/** + * Process incoming webhook from WhatsApp + */ +export function processWebhook(body: WhatsAppWebhookEntry): WhatsAppMessage[] { + const messages: WhatsAppMessage[] = []; + + for (const entry of body.entry) { + for (const change of entry.changes) { + if (change.value.messages) { + messages.push(...change.value.messages); + } + } + } + + return messages; +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/tsconfig.json b/typescript-sdk/integrations/community-whatsapp/tsconfig.json new file mode 100644 index 000000000..4d77c0bc5 --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "esnext", + "lib": ["dom", "dom.iterable", "esnext"], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "moduleResolution": "node", + "skipLibCheck": true, + "strict": true, + "jsx": "react-jsx", + "esModuleInterop": true, + "resolveJsonModule": true, + "isolatedModules": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "stripInternal": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] +} \ No newline at end of file diff --git a/typescript-sdk/integrations/community-whatsapp/tsup.config.ts b/typescript-sdk/integrations/community-whatsapp/tsup.config.ts new file mode 100644 index 000000000..e24c0244b --- /dev/null +++ b/typescript-sdk/integrations/community-whatsapp/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["cjs", "esm"], + dts: true, + splitting: false, + sourcemap: true, + clean: true, +}); \ No newline at end of file diff --git a/typescript-sdk/pnpm-lock.yaml b/typescript-sdk/pnpm-lock.yaml index 4e2d348c1..83a64af0c 100644 --- a/typescript-sdk/pnpm-lock.yaml +++ b/typescript-sdk/pnpm-lock.yaml @@ -119,7 +119,7 @@ importers: version: 1.9.2(@types/react@19.1.5)(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@copilotkit/runtime': specifier: 1.9.2 - version: 1.9.2(@ag-ui/client@0.0.33)(@ag-ui/core@0.0.33)(@ag-ui/encoder@0.0.33)(@ag-ui/proto@0.0.33)(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@smithy/util-utf8@2.3.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@5.3.2)(jsonwebtoken@9.0.2)(lodash@4.17.21)(pg@8.16.3)(playwright@1.53.2)(react@19.1.0)(redis@5.6.1)(ws@8.18.3) + version: 1.9.2(@ag-ui/client@0.0.33)(@ag-ui/core@0.0.33)(@ag-ui/encoder@0.0.33)(@ag-ui/proto@0.0.33)(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@libsql/client@0.15.9)(@smithy/eventstream-codec@4.0.4)(@smithy/protocol-http@5.1.2)(@smithy/signature-v4@5.1.2)(@smithy/util-utf8@4.0.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@7.0.4)(jsonwebtoken@9.0.2)(lodash@4.17.21)(pg@8.16.3)(playwright@1.53.2)(react@19.1.0)(redis@5.6.1)(ws@8.18.3) '@copilotkit/runtime-client-gql': specifier: 1.9.2 version: 1.9.2(graphql@16.11.0)(react@19.1.0) @@ -146,10 +146,10 @@ importers: version: 0.11.5(@mastra/core@0.11.1(@sinclair/typebox@0.34.37)(openapi-types@12.1.3)(react@19.1.0)(zod@3.25.67))(react@19.1.0) '@mdx-js/loader': specifier: ^3.1.0 - version: 3.1.0(acorn@8.14.1)(webpack@5.99.9) + version: 3.1.0(acorn@8.15.0)(webpack@5.99.9) '@mdx-js/mdx': specifier: ^3.1.0 - version: 3.1.0(acorn@8.14.1) + version: 3.1.0(acorn@8.15.0) '@mdx-js/react': specifier: ^3.1.0 version: 3.1.0(@types/react@19.1.5)(react@19.1.0) @@ -158,7 +158,7 @@ importers: version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@next/mdx': specifier: ^15.2.3 - version: 15.3.2(@mdx-js/loader@3.1.0(acorn@8.14.1)(webpack@5.99.9))(@mdx-js/react@3.1.0(@types/react@19.1.5)(react@19.1.0)) + version: 15.3.2(@mdx-js/loader@3.1.0(acorn@8.15.0)(webpack@5.99.9))(@mdx-js/react@3.1.0(@types/react@19.1.5)(react@19.1.0)) '@radix-ui/react-dropdown-menu': specifier: ^2.1.6 version: 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.5))(@types/react@19.1.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -307,7 +307,35 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + tsup: + specifier: ^8.0.2 + version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) + typescript: + specifier: ^5.3.3 + version: 5.8.2 + + integrations/community-whatsapp: + dependencies: + '@ag-ui/client': + specifier: workspace:* + version: link:../../packages/client + rxjs: + specifier: 7.8.1 + version: 7.8.1 + devDependencies: + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 + '@types/node': + specifier: ^20.11.19 + version: 20.19.4 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.19.4) + ts-jest: + specifier: ^29.1.2 + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.5)(jest@29.7.0(@types/node@20.19.4))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -335,7 +363,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -350,10 +378,10 @@ importers: version: link:../../packages/client '@langchain/core': specifier: ^0.3.38 - version: 0.3.56(openai@4.104.0(zod@3.25.71)) + version: 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) '@langchain/langgraph-sdk': specifier: ^0.0.78 - version: 0.0.78(@langchain/core@0.3.56(openai@4.104.0(zod@3.25.71)))(react@19.1.0) + version: 0.0.78(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(react@19.1.0) partial-json: specifier: ^0.1.7 version: 0.1.7 @@ -372,7 +400,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -400,7 +428,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -418,7 +446,7 @@ importers: version: 1.2.11(zod@3.25.67) '@copilotkit/runtime': specifier: ^1.8.13 - version: 1.8.13(@ag-ui/client@packages+client)(@ag-ui/core@0.0.35)(@ag-ui/encoder@0.0.35)(@ag-ui/proto@0.0.35)(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))))(@smithy/util-utf8@2.3.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@5.3.2)(jsonwebtoken@9.0.2)(lodash@4.17.21)(pg@8.16.3)(playwright@1.53.2)(react@19.1.0)(redis@5.6.1)(ws@8.18.3) + version: 1.8.13(@ag-ui/client@packages+client)(@ag-ui/core@0.0.35)(@ag-ui/encoder@0.0.35)(@ag-ui/proto@0.0.35)(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))))(@libsql/client@0.15.9)(@smithy/eventstream-codec@4.0.4)(@smithy/protocol-http@5.1.2)(@smithy/signature-v4@5.1.2)(@smithy/util-utf8@4.0.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@7.0.4)(jsonwebtoken@9.0.2)(lodash@4.17.21)(pg@8.16.3)(playwright@1.53.2)(react@19.1.0)(redis@5.6.1)(ws@8.18.3) '@mastra/client-js': specifier: ^0.10.9 version: 0.10.9(@sinclair/typebox@0.34.37)(openapi-types@12.1.3)(react@19.1.0)(zod@3.25.67) @@ -443,7 +471,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -471,7 +499,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -499,7 +527,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -527,7 +555,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -555,7 +583,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -589,7 +617,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -623,7 +651,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -672,7 +700,7 @@ importers: version: 29.7.0(@types/node@20.17.50) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -694,10 +722,10 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.50) + version: 29.7.0(@types/node@20.19.4) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.19.4))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -719,10 +747,10 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.50) + version: 29.7.0(@types/node@20.19.4) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.19.4))(typescript@5.8.2) tsup: specifier: ^8.0.2 version: 8.5.0(jiti@2.4.2)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.2)(yaml@2.8.0) @@ -750,10 +778,10 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.50) + version: 29.7.0(@types/node@20.19.4) ts-jest: specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2) + version: 29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.19.4))(typescript@5.8.2) ts-proto: specifier: ^2.7.0 version: 2.7.0 @@ -1208,18 +1236,10 @@ packages: resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==} engines: {node: '>=6.9.0'} - '@babel/core@7.27.1': - resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} - engines: {node: '>=6.9.0'} - '@babel/core@7.28.0': resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} engines: {node: '>=6.9.0'} - '@babel/generator@7.27.1': - resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.28.0': resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} engines: {node: '>=6.9.0'} @@ -1236,12 +1256,6 @@ packages: resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.27.1': - resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/helper-module-transforms@7.27.3': resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} engines: {node: '>=6.9.0'} @@ -1264,19 +1278,10 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.27.1': - resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} - engines: {node: '>=6.9.0'} - '@babel/helpers@7.27.6': resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} engines: {node: '>=6.9.0'} - '@babel/parser@7.27.2': - resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.28.0': resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} engines: {node: '>=6.0.0'} @@ -1381,18 +1386,10 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.27.1': - resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} - engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.0': resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} engines: {node: '>=6.9.0'} - '@babel/types@7.27.1': - resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} - engines: {node: '>=6.9.0'} - '@babel/types@7.28.0': resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==} engines: {node: '>=6.9.0'} @@ -4940,11 +4937,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -5175,11 +5167,6 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.24.5: - resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - browserslist@4.25.1: resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -5682,9 +5669,6 @@ packages: electrodb@3.4.3: resolution: {integrity: sha512-4KpIF56mg+edhV+T6yzOiDEN7LnyWLX9iRp6+D6lYldX8j6VNBb8i5QK71k3V0hoCqKdl70i69ph7NBdPCkFwQ==} - electron-to-chromium@1.5.155: - resolution: {integrity: sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==} - electron-to-chromium@1.5.179: resolution: {integrity: sha512-UWKi/EbBopgfFsc5k61wFpV7WrnnSlSzW/e2XcBmS6qKYTivZlLtoll5/rdqRTxGglGHkmkW0j0pFNJG10EUIQ==} @@ -6281,10 +6265,6 @@ packages: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported - globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -10779,26 +10759,6 @@ snapshots: '@babel/compat-data@7.27.2': {} - '@babel/core@7.27.1': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.1 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) - '@babel/helpers': 7.27.1 - '@babel/parser': 7.27.2 - '@babel/template': 7.27.2 - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 - convert-source-map: 2.0.0 - debug: 4.4.1 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/core@7.28.0': dependencies: '@ampproject/remapping': 2.3.0 @@ -10818,15 +10778,6 @@ snapshots: semver: 6.3.1 transitivePeerDependencies: - supports-color - optional: true - - '@babel/generator@7.27.1': - dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.1.0 '@babel/generator@7.28.0': dependencies: @@ -10835,32 +10786,21 @@ snapshots: '@jridgewell/gen-mapping': 0.3.12 '@jridgewell/trace-mapping': 0.3.29 jsesc: 3.1.0 - optional: true '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.27.2 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.24.5 + browserslist: 4.25.1 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-globals@7.28.0': - optional: true + '@babel/helper-globals@7.28.0': {} '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.1 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.0 transitivePeerDependencies: - supports-color @@ -10872,7 +10812,6 @@ snapshots: '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color - optional: true '@babel/helper-plugin-utils@7.27.1': {} @@ -10882,199 +10821,98 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.27.1': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.27.1 - '@babel/helpers@7.27.6': dependencies: '@babel/template': 7.27.2 '@babel/types': 7.28.0 - optional: true - - '@babel/parser@7.27.2': - dependencies: - '@babel/types': 7.27.1 '@babel/parser@7.28.0': dependencies: '@babel/types': 7.28.0 - optional: true - - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.1)': + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - optional: true - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.1)': + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 '@babel/runtime@7.27.1': {} @@ -11082,20 +10920,8 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 - - '@babel/traverse@7.27.1': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.1 - '@babel/parser': 7.27.2 - '@babel/template': 7.27.2 - '@babel/types': 7.27.1 - debug: 4.4.1 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 '@babel/traverse@7.28.0': dependencies: @@ -11108,18 +10934,11 @@ snapshots: debug: 4.4.1 transitivePeerDependencies: - supports-color - optional: true - - '@babel/types@7.27.1': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 '@babel/types@7.28.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - optional: true '@bcoe/v8-coverage@0.2.3': {} @@ -11223,7 +11042,7 @@ snapshots: - encoding - graphql - '@copilotkit/runtime@1.8.13(@ag-ui/client@packages+client)(@ag-ui/core@0.0.35)(@ag-ui/encoder@0.0.35)(@ag-ui/proto@0.0.35)(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))))(@smithy/util-utf8@2.3.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@5.3.2)(jsonwebtoken@9.0.2)(lodash@4.17.21)(pg@8.16.3)(playwright@1.53.2)(react@19.1.0)(redis@5.6.1)(ws@8.18.3)': + '@copilotkit/runtime@1.8.13(@ag-ui/client@packages+client)(@ag-ui/core@0.0.35)(@ag-ui/encoder@0.0.35)(@ag-ui/proto@0.0.35)(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))))(@libsql/client@0.15.9)(@smithy/eventstream-codec@4.0.4)(@smithy/protocol-http@5.1.2)(@smithy/signature-v4@5.1.2)(@smithy/util-utf8@4.0.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@7.0.4)(jsonwebtoken@9.0.2)(lodash@4.17.21)(pg@8.16.3)(playwright@1.53.2)(react@19.1.0)(redis@5.6.1)(ws@8.18.3)': dependencies: '@ag-ui/client': link:packages/client '@ag-ui/core': 0.0.35 @@ -11232,7 +11051,7 @@ snapshots: '@anthropic-ai/sdk': 0.27.3 '@copilotkit/shared': 1.8.13 '@graphql-yoga/plugin-defer-stream': 3.13.4(graphql-yoga@5.13.4(graphql@16.11.0))(graphql@16.11.0) - '@langchain/community': 0.3.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(@smithy/util-utf8@2.3.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@5.3.2)(jsonwebtoken@9.0.2)(lodash@4.17.21)(openai@4.100.0(ws@8.18.3)(zod@3.25.71))(pg@8.16.3)(playwright@1.53.2)(redis@5.6.1)(ws@8.18.3) + '@langchain/community': 0.3.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(@libsql/client@0.15.9)(@smithy/eventstream-codec@4.0.4)(@smithy/protocol-http@5.1.2)(@smithy/signature-v4@5.1.2)(@smithy/util-utf8@4.0.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@7.0.4)(jsonwebtoken@9.0.2)(lodash@4.17.21)(openai@4.100.0(ws@8.18.3)(zod@3.25.71))(pg@8.16.3)(playwright@1.53.2)(redis@5.6.1)(ws@8.18.3) '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) '@langchain/google-gauth': 0.1.8(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(zod@3.25.71) '@langchain/langgraph-sdk': 0.0.70(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(react@19.1.0) @@ -11400,7 +11219,7 @@ snapshots: - ws - youtubei.js - '@copilotkit/runtime@1.9.2(@ag-ui/client@0.0.33)(@ag-ui/core@0.0.33)(@ag-ui/encoder@0.0.33)(@ag-ui/proto@0.0.33)(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@smithy/util-utf8@2.3.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@5.3.2)(jsonwebtoken@9.0.2)(lodash@4.17.21)(pg@8.16.3)(playwright@1.53.2)(react@19.1.0)(redis@5.6.1)(ws@8.18.3)': + '@copilotkit/runtime@1.9.2(@ag-ui/client@0.0.33)(@ag-ui/core@0.0.33)(@ag-ui/encoder@0.0.33)(@ag-ui/proto@0.0.33)(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@libsql/client@0.15.9)(@smithy/eventstream-codec@4.0.4)(@smithy/protocol-http@5.1.2)(@smithy/signature-v4@5.1.2)(@smithy/util-utf8@4.0.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@7.0.4)(jsonwebtoken@9.0.2)(lodash@4.17.21)(pg@8.16.3)(playwright@1.53.2)(react@19.1.0)(redis@5.6.1)(ws@8.18.3)': dependencies: '@ag-ui/client': 0.0.33 '@ag-ui/core': 0.0.33 @@ -11410,12 +11229,12 @@ snapshots: '@anthropic-ai/sdk': 0.27.3 '@copilotkit/shared': 1.9.2 '@graphql-yoga/plugin-defer-stream': 3.13.4(graphql-yoga@5.13.4(graphql@16.11.0))(graphql@16.11.0) - '@langchain/aws': 0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))) - '@langchain/community': 0.3.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(@smithy/util-utf8@2.3.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@5.3.2)(jsonwebtoken@9.0.2)(lodash@4.17.21)(openai@4.104.0(ws@8.18.3)(zod@3.25.71))(pg@8.16.3)(playwright@1.53.2)(redis@5.6.1)(ws@8.18.3) - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - '@langchain/google-gauth': 0.1.8(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(zod@3.25.71) - '@langchain/langgraph-sdk': 0.0.70(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(react@19.1.0) - '@langchain/openai': 0.4.9(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(ws@8.18.3) + '@langchain/aws': 0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))) + '@langchain/community': 0.3.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(@libsql/client@0.15.9)(@smithy/eventstream-codec@4.0.4)(@smithy/protocol-http@5.1.2)(@smithy/signature-v4@5.1.2)(@smithy/util-utf8@4.0.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@7.0.4)(jsonwebtoken@9.0.2)(lodash@4.17.21)(openai@4.104.0(ws@8.18.3)(zod@3.25.71))(pg@8.16.3)(playwright@1.53.2)(redis@5.6.1)(ws@8.18.3) + '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) + '@langchain/google-gauth': 0.1.8(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(zod@3.25.71) + '@langchain/langgraph-sdk': 0.0.70(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(react@19.1.0) + '@langchain/openai': 0.4.9(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(ws@8.18.3) class-transformer: 0.5.1 class-validator: 0.14.2 express: 4.21.2 @@ -12267,7 +12086,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 '@types/node': 20.19.4 chalk: 4.1.2 collect-v8-coverage: 1.0.2 @@ -12295,7 +12114,7 @@ snapshots: '@jest/source-map@29.6.3': dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 callsites: 3.1.0 graceful-fs: 4.2.11 @@ -12315,9 +12134,9 @@ snapshots: '@jest/transform@29.7.0': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -12346,13 +12165,12 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.4 '@jridgewell/trace-mapping': 0.3.29 - optional: true '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping': 0.3.29 '@jridgewell/resolve-uri@3.1.2': {} @@ -12366,19 +12184,17 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.4': - optional: true + '@jridgewell/sourcemap-codec@1.5.4': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.4 '@jridgewell/trace-mapping@0.3.29': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.4 - optional: true '@js-sdsl/ordered-map@4.4.2': {} @@ -12393,19 +12209,8 @@ snapshots: '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) transitivePeerDependencies: - aws-crt - optional: true - - '@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))': - dependencies: - '@aws-sdk/client-bedrock-agent-runtime': 3.844.0 - '@aws-sdk/client-bedrock-runtime': 3.844.0 - '@aws-sdk/client-kendra': 3.844.0 - '@aws-sdk/credential-provider-node': 3.844.0 - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - transitivePeerDependencies: - - aws-crt - '@langchain/community@0.3.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(@smithy/util-utf8@2.3.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@5.3.2)(jsonwebtoken@9.0.2)(lodash@4.17.21)(openai@4.100.0(ws@8.18.3)(zod@3.25.71))(pg@8.16.3)(playwright@1.53.2)(redis@5.6.1)(ws@8.18.3)': + '@langchain/community@0.3.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(@libsql/client@0.15.9)(@smithy/eventstream-codec@4.0.4)(@smithy/protocol-http@5.1.2)(@smithy/signature-v4@5.1.2)(@smithy/util-utf8@4.0.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@7.0.4)(jsonwebtoken@9.0.2)(lodash@4.17.21)(openai@4.100.0(ws@8.18.3)(zod@3.25.71))(pg@8.16.3)(playwright@1.53.2)(redis@5.6.1)(ws@8.18.3)': dependencies: '@browserbasehq/stagehand': 2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67) '@ibm-cloud/watsonx-ai': 1.6.8 @@ -12430,12 +12235,16 @@ snapshots: '@aws-sdk/client-kendra': 3.844.0 '@aws-sdk/credential-provider-node': 3.844.0 '@browserbasehq/sdk': 2.6.0 - '@smithy/util-utf8': 2.3.0 + '@libsql/client': 0.15.9 + '@smithy/eventstream-codec': 4.0.4 + '@smithy/protocol-http': 5.1.2 + '@smithy/signature-v4': 5.1.2 + '@smithy/util-utf8': 4.0.0 '@upstash/redis': 1.35.1 cohere-ai: 7.17.1 fast-xml-parser: 5.2.5 google-auth-library: 10.1.0 - ignore: 5.3.2 + ignore: 7.0.4 jsonwebtoken: 9.0.2 lodash: 4.17.21 pg: 8.16.3 @@ -12460,19 +12269,19 @@ snapshots: - handlebars - peggy - '@langchain/community@0.3.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(@smithy/util-utf8@2.3.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@5.3.2)(jsonwebtoken@9.0.2)(lodash@4.17.21)(openai@4.104.0(ws@8.18.3)(zod@3.25.71))(pg@8.16.3)(playwright@1.53.2)(redis@5.6.1)(ws@8.18.3)': + '@langchain/community@0.3.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-agent-runtime@3.844.0)(@aws-sdk/client-bedrock-runtime@3.844.0)(@aws-sdk/client-dynamodb@3.844.0)(@aws-sdk/client-kendra@3.844.0)(@aws-sdk/credential-provider-node@3.844.0)(@browserbasehq/sdk@2.6.0)(@browserbasehq/stagehand@2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67))(@ibm-cloud/watsonx-ai@1.6.8)(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(@libsql/client@0.15.9)(@smithy/eventstream-codec@4.0.4)(@smithy/protocol-http@5.1.2)(@smithy/signature-v4@5.1.2)(@smithy/util-utf8@4.0.0)(@upstash/redis@1.35.1)(axios@1.10.0)(cohere-ai@7.17.1)(fast-xml-parser@5.2.5)(google-auth-library@10.1.0)(ibm-cloud-sdk-core@5.4.0)(ignore@7.0.4)(jsonwebtoken@9.0.2)(lodash@4.17.21)(openai@4.104.0(ws@8.18.3)(zod@3.25.71))(pg@8.16.3)(playwright@1.53.2)(redis@5.6.1)(ws@8.18.3)': dependencies: '@browserbasehq/stagehand': 2.4.0(deepmerge@4.3.1)(dotenv@17.0.1)(react@19.1.0)(zod@3.25.67) '@ibm-cloud/watsonx-ai': 1.6.8 - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - '@langchain/openai': 0.4.9(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(ws@8.18.3) + '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) + '@langchain/openai': 0.4.9(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(ws@8.18.3) binary-extensions: 2.3.0 expr-eval: 2.0.2 flat: 5.0.2 ibm-cloud-sdk-core: 5.4.0 js-yaml: 4.1.0 langchain: 0.3.26(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(axios@1.10.0)(openai@4.104.0(ws@8.18.3)(zod@3.25.71))(ws@8.18.3) - langsmith: 0.3.29(openai@4.104.0(zod@3.25.71)) + langsmith: 0.3.29(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) openai: 4.104.0(ws@8.18.3)(zod@3.25.71) uuid: 10.0.0 zod: 3.25.71 @@ -12485,12 +12294,16 @@ snapshots: '@aws-sdk/client-kendra': 3.844.0 '@aws-sdk/credential-provider-node': 3.844.0 '@browserbasehq/sdk': 2.6.0 - '@smithy/util-utf8': 2.3.0 + '@libsql/client': 0.15.9 + '@smithy/eventstream-codec': 4.0.4 + '@smithy/protocol-http': 5.1.2 + '@smithy/signature-v4': 5.1.2 + '@smithy/util-utf8': 4.0.0 '@upstash/redis': 1.35.1 cohere-ai: 7.17.1 fast-xml-parser: 5.2.5 google-auth-library: 10.1.0 - ignore: 5.3.2 + ignore: 7.0.4 jsonwebtoken: 9.0.2 lodash: 4.17.21 pg: 8.16.3 @@ -12539,24 +12352,7 @@ snapshots: camelcase: 6.3.0 decamelize: 1.2.0 js-tiktoken: 1.0.20 - langsmith: 0.3.29(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) - mustache: 4.2.0 - p-queue: 6.6.2 - p-retry: 4.6.2 - uuid: 10.0.0 - zod: 3.25.71 - zod-to-json-schema: 3.24.5(zod@3.25.71) - transitivePeerDependencies: - - openai - - '@langchain/core@0.3.56(openai@4.104.0(zod@3.25.71))': - dependencies: - '@cfworker/json-schema': 4.1.1 - ansi-styles: 5.2.0 - camelcase: 6.3.0 - decamelize: 1.2.0 - js-tiktoken: 1.0.20 - langsmith: 0.3.29(openai@4.104.0(zod@3.25.71)) + langsmith: 0.3.29(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) mustache: 4.2.0 p-queue: 6.6.2 p-retry: 4.6.2 @@ -12574,14 +12370,6 @@ snapshots: transitivePeerDependencies: - zod - '@langchain/google-common@0.1.8(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(zod@3.25.71)': - dependencies: - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - uuid: 10.0.0 - zod-to-json-schema: 3.24.6(zod@3.25.71) - transitivePeerDependencies: - - zod - '@langchain/google-gauth@0.1.8(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(zod@3.25.71)': dependencies: '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) @@ -12592,16 +12380,6 @@ snapshots: - supports-color - zod - '@langchain/google-gauth@0.1.8(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(zod@3.25.71)': - dependencies: - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - '@langchain/google-common': 0.1.8(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(zod@3.25.71) - google-auth-library: 8.9.0 - transitivePeerDependencies: - - encoding - - supports-color - - zod - '@langchain/langgraph-sdk@0.0.70(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(react@19.1.0)': dependencies: '@types/json-schema': 7.0.15 @@ -12612,16 +12390,6 @@ snapshots: '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) react: 19.1.0 - '@langchain/langgraph-sdk@0.0.70(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(react@19.1.0)': - dependencies: - '@types/json-schema': 7.0.15 - p-queue: 6.6.2 - p-retry: 4.6.2 - uuid: 9.0.1 - optionalDependencies: - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - react: 19.1.0 - '@langchain/langgraph-sdk@0.0.78(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(react@19.1.0)': dependencies: '@types/json-schema': 7.0.15 @@ -12632,16 +12400,6 @@ snapshots: '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) react: 19.1.0 - '@langchain/langgraph-sdk@0.0.78(@langchain/core@0.3.56(openai@4.104.0(zod@3.25.71)))(react@19.1.0)': - dependencies: - '@types/json-schema': 7.0.15 - p-queue: 6.6.2 - p-retry: 4.6.2 - uuid: 9.0.1 - optionalDependencies: - '@langchain/core': 0.3.56(openai@4.104.0(zod@3.25.71)) - react: 19.1.0 - '@langchain/openai@0.4.9(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(ws@8.18.3)': dependencies: '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) @@ -12653,27 +12411,11 @@ snapshots: - encoding - ws - '@langchain/openai@0.4.9(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(ws@8.18.3)': - dependencies: - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - js-tiktoken: 1.0.20 - openai: 4.104.0(ws@8.18.3)(zod@3.25.71) - zod: 3.25.71 - zod-to-json-schema: 3.24.6(zod@3.25.71) - transitivePeerDependencies: - - encoding - - ws - '@langchain/textsplitters@0.1.0(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))': dependencies: '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) js-tiktoken: 1.0.20 - '@langchain/textsplitters@0.1.0(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))': - dependencies: - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - js-tiktoken: 1.0.20 - '@libsql/client@0.15.9': dependencies: '@libsql/core': 0.15.9 @@ -13050,9 +12792,9 @@ snapshots: zod-from-json-schema: 0.0.5 zod-to-json-schema: 3.24.6(zod@3.25.67) - '@mdx-js/loader@3.1.0(acorn@8.14.1)(webpack@5.99.9)': + '@mdx-js/loader@3.1.0(acorn@8.15.0)(webpack@5.99.9)': dependencies: - '@mdx-js/mdx': 3.1.0(acorn@8.14.1) + '@mdx-js/mdx': 3.1.0(acorn@8.15.0) source-map: 0.7.4 optionalDependencies: webpack: 5.99.9 @@ -13060,7 +12802,7 @@ snapshots: - acorn - supports-color - '@mdx-js/mdx@3.1.0(acorn@8.14.1)': + '@mdx-js/mdx@3.1.0(acorn@8.15.0)': dependencies: '@types/estree': 1.0.7 '@types/estree-jsx': 1.0.5 @@ -13074,7 +12816,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.6 markdown-extensions: 2.0.0 recma-build-jsx: 1.0.0 - recma-jsx: 1.0.0(acorn@8.14.1) + recma-jsx: 1.0.0(acorn@8.15.0) recma-stringify: 1.0.0 rehype-recma: 1.0.0 remark-mdx: 3.1.0 @@ -13122,11 +12864,11 @@ snapshots: dependencies: fast-glob: 3.3.1 - '@next/mdx@15.3.2(@mdx-js/loader@3.1.0(acorn@8.14.1)(webpack@5.99.9))(@mdx-js/react@3.1.0(@types/react@19.1.5)(react@19.1.0))': + '@next/mdx@15.3.2(@mdx-js/loader@3.1.0(acorn@8.15.0)(webpack@5.99.9))(@mdx-js/react@3.1.0(@types/react@19.1.5)(react@19.1.0))': dependencies: source-map: 0.7.4 optionalDependencies: - '@mdx-js/loader': 3.1.0(acorn@8.14.1)(webpack@5.99.9) + '@mdx-js/loader': 3.1.0(acorn@8.15.0)(webpack@5.99.9) '@mdx-js/react': 3.1.0(@types/react@19.1.5)(react@19.1.0) '@next/swc-darwin-arm64@15.2.1': @@ -15090,24 +14832,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.7 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.27.1 + '@babel/types': 7.28.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 '@types/babel__traverse@7.20.7': dependencies: - '@babel/types': 7.27.1 + '@babel/types': 7.28.0 '@types/bunyan@1.8.11': dependencies: @@ -15139,12 +14881,11 @@ snapshots: '@types/estree-jsx@1.0.5': dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/estree@1.0.7': {} - '@types/estree@1.0.8': - optional: true + '@types/estree@1.0.8': {} '@types/graceful-fs@4.1.9': dependencies: @@ -15580,18 +15321,15 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-attributes@1.9.5(acorn@8.14.1): + acorn-import-attributes@1.9.5(acorn@8.15.0): dependencies: - acorn: 8.14.1 + acorn: 8.15.0 - acorn-jsx@5.3.2(acorn@8.14.1): + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: - acorn: 8.14.1 - - acorn@8.14.1: {} + acorn: 8.15.0 - acorn@8.15.0: - optional: true + acorn@8.15.0: {} agent-base@6.0.2: dependencies: @@ -15803,19 +15541,6 @@ snapshots: axobject-query@4.1.0: {} - babel-jest@29.7.0(@babel/core@7.27.1): - dependencies: - '@babel/core': 7.27.1 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.27.1) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - babel-jest@29.7.0(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 @@ -15828,7 +15553,6 @@ snapshots: slash: 3.0.0 transitivePeerDependencies: - supports-color - optional: true babel-plugin-istanbul@6.1.1: dependencies: @@ -15843,29 +15567,10 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.27.1 + '@babel/types': 7.28.0 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.7 - babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.1): - dependencies: - '@babel/core': 7.27.1 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.27.1) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.27.1) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.27.1) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.27.1) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.1) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.27.1) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.27.1) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.1) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.1) - babel-preset-current-node-syntax@1.1.0(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 @@ -15884,20 +15589,12 @@ snapshots: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.0) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.0) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.0) - optional: true - - babel-preset-jest@29.6.3(@babel/core@7.27.1): - dependencies: - '@babel/core': 7.27.1 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.1) babel-preset-jest@29.6.3(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.1.0(@babel/core@7.28.0) - optional: true bail@2.0.2: {} @@ -15947,20 +15644,12 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.24.5: - dependencies: - caniuse-lite: 1.0.30001718 - electron-to-chromium: 1.5.155 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.24.5) - browserslist@4.25.1: dependencies: caniuse-lite: 1.0.30001726 electron-to-chromium: 1.5.179 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.1) - optional: true bs-logger@0.2.6: dependencies: @@ -16021,8 +15710,7 @@ snapshots: caniuse-lite@1.0.30001718: {} - caniuse-lite@1.0.30001726: - optional: true + caniuse-lite@1.0.30001726: {} case-anything@2.1.13: {} @@ -16216,6 +15904,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@20.19.4): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.19.4) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + crelt@1.0.6: {} cross-inspect@1.0.1: @@ -16381,10 +16084,7 @@ snapshots: transitivePeerDependencies: - '@aws-sdk/client-dynamodb' - electron-to-chromium@1.5.155: {} - - electron-to-chromium@1.5.179: - optional: true + electron-to-chromium@1.5.179: {} emittery@0.13.1: {} @@ -16530,7 +16230,7 @@ snapshots: esast-util-from-js@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 - acorn: 8.14.1 + acorn: 8.15.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.2 @@ -16787,8 +16487,8 @@ snapshots: espree@10.3.0: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.0 esprima@4.0.1: {} @@ -16808,7 +16508,7 @@ snapshots: estree-util-attach-comments@3.0.0: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 estree-util-build-jsx@3.0.1: dependencies: @@ -16821,7 +16521,7 @@ snapshots: estree-util-scope@1.0.0: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 devlop: 1.1.0 estree-util-to-js@2.0.0: @@ -16837,7 +16537,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 esutils@2.0.3: {} @@ -17273,8 +16973,6 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 - globals@11.12.0: {} - globals@14.0.0: {} globalthis@1.0.4: @@ -17461,7 +17159,7 @@ snapshots: hast-util-to-estree@3.1.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 @@ -17482,7 +17180,7 @@ snapshots: hast-util-to-jsx-runtime@2.3.6: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/hast': 3.0.4 '@types/unist': 3.0.3 comma-separated-tokens: 2.0.3 @@ -17631,8 +17329,8 @@ snapshots: import-in-the-middle@1.14.0: dependencies: - acorn: 8.14.1 - acorn-import-attributes: 1.9.5(acorn@8.14.1) + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) cjs-module-lexer: 1.4.3 module-details-from-path: 1.0.4 @@ -17846,8 +17544,8 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/core': 7.28.0 + '@babel/parser': 7.28.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -17856,8 +17554,8 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/core': 7.28.0 + '@babel/parser': 7.28.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.7.2 @@ -17956,12 +17654,31 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@20.19.4): + dependencies: + '@jest/core': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.19.4) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.19.4) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-config@29.7.0(@types/node@20.17.50): dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) + babel-jest: 29.7.0(@babel/core@7.28.0) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -17988,10 +17705,10 @@ snapshots: jest-config@29.7.0(@types/node@20.19.4): dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) + babel-jest: 29.7.0(@babel/core@7.28.0) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -18172,15 +17889,15 @@ snapshots: jest-snapshot@29.7.0: dependencies: - '@babel/core': 7.27.1 - '@babel/generator': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.1) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.1) - '@babel/types': 7.27.1 + '@babel/core': 7.28.0 + '@babel/generator': 7.28.0 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0) + '@babel/types': 7.28.0 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.1) + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.28.0) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -18250,6 +17967,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@20.19.4): + dependencies: + '@jest/core': 29.7.0 + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@20.19.4) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jiti@2.4.2: {} jose@5.10.0: {} @@ -18402,13 +18131,13 @@ snapshots: langchain@0.3.26(@langchain/aws@0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))))(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(axios@1.10.0)(openai@4.104.0(ws@8.18.3)(zod@3.25.71))(ws@8.18.3): dependencies: - '@langchain/core': 0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) - '@langchain/openai': 0.4.9(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71)))(ws@8.18.3) - '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))) + '@langchain/core': 0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)) + '@langchain/openai': 0.4.9(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71)))(ws@8.18.3) + '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))) js-tiktoken: 1.0.20 js-yaml: 4.1.0 jsonpointer: 5.0.1 - langsmith: 0.3.29(openai@4.104.0(zod@3.25.71)) + langsmith: 0.3.29(openai@4.104.0(ws@8.18.3)(zod@3.25.71)) openapi-types: 12.1.3 p-retry: 4.6.2 uuid: 10.0.0 @@ -18416,7 +18145,7 @@ snapshots: zod: 3.25.71 zod-to-json-schema: 3.24.6(zod@3.25.71) optionalDependencies: - '@langchain/aws': 0.1.11(@langchain/core@0.3.56(openai@4.104.0(ws@8.18.3)(zod@3.25.71))) + '@langchain/aws': 0.1.11(@langchain/core@0.3.56(openai@4.100.0(ws@8.18.3)(zod@3.25.71))) axios: 1.10.0(debug@4.4.1) transitivePeerDependencies: - encoding @@ -18435,7 +18164,7 @@ snapshots: optionalDependencies: openai: 4.100.0(ws@8.18.3)(zod@3.25.67) - langsmith@0.3.29(openai@4.104.0(zod@3.25.71)): + langsmith@0.3.29(openai@4.104.0(ws@8.18.3)(zod@3.25.71)): dependencies: '@types/uuid': 10.0.0 chalk: 4.1.2 @@ -18576,7 +18305,7 @@ snapshots: log-symbols@5.1.0: dependencies: - chalk: 5.2.0 + chalk: 5.4.1 is-unicode-supported: 1.3.0 long@5.3.2: {} @@ -18970,7 +18699,7 @@ snapshots: micromark-extension-mdx-expression@3.0.1: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 devlop: 1.1.0 micromark-factory-mdx-expression: 2.0.3 micromark-factory-space: 2.0.1 @@ -18981,7 +18710,7 @@ snapshots: micromark-extension-mdx-jsx@3.0.2: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 micromark-factory-mdx-expression: 2.0.3 @@ -18998,7 +18727,7 @@ snapshots: micromark-extension-mdxjs-esm@3.0.0: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-util-character: 2.1.1 @@ -19010,8 +18739,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) micromark-extension-mdx-expression: 3.0.1 micromark-extension-mdx-jsx: 3.0.2 micromark-extension-mdx-md: 2.0.0 @@ -19047,7 +18776,7 @@ snapshots: micromark-factory-mdx-expression@2.0.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 devlop: 1.1.0 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 @@ -19163,7 +18892,7 @@ snapshots: micromark-util-events-to-acorn@2.0.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/unist': 3.0.3 devlop: 1.1.0 estree-util-visit: 2.0.0 @@ -19310,7 +19039,7 @@ snapshots: mlly@1.7.4: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.6.1 @@ -20161,13 +19890,13 @@ snapshots: recma-build-jsx@1.0.0: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 estree-util-build-jsx: 3.0.1 vfile: 6.0.3 - recma-jsx@1.0.0(acorn@8.14.1): + recma-jsx@1.0.0(acorn@8.15.0): dependencies: - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn-jsx: 5.3.2(acorn@8.15.0) estree-util-to-js: 2.0.0 recma-parse: 1.0.0 recma-stringify: 1.0.0 @@ -20177,14 +19906,14 @@ snapshots: recma-parse@1.0.0: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 esast-util-from-js: 2.0.1 unified: 11.0.5 vfile: 6.0.3 recma-stringify@1.0.0: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 estree-util-to-js: 2.0.0 unified: 11.0.5 vfile: 6.0.3 @@ -20242,7 +19971,7 @@ snapshots: rehype-recma@1.0.0: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/hast': 3.0.4 hast-util-to-estree: 3.1.3 transitivePeerDependencies: @@ -20763,7 +20492,7 @@ snapshots: sucrase@3.35.0: dependencies: - '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/gen-mapping': 0.3.12 commander: 4.1.1 glob: 10.4.5 lines-and-columns: 1.2.4 @@ -20909,7 +20638,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.3.4(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2): + ts-jest@29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 @@ -20924,18 +20653,39 @@ snapshots: typescript: 5.8.2 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.0) + esbuild: 0.25.4 + + ts-jest@29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.19.4))(typescript@5.8.2): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.19.4) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.2 + type-fest: 4.41.0 + typescript: 5.8.2 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.28.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) + babel-jest: 29.7.0(@babel/core@7.28.0) esbuild: 0.25.4 - ts-jest@29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2): + ts-jest@29.3.4(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.5)(jest@29.7.0(@types/node@20.19.4))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.50) + jest: 29.7.0(@types/node@20.19.4) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -20949,6 +20699,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.28.0) + esbuild: 0.25.5 ts-poet@6.11.0: dependencies: @@ -21227,18 +20978,11 @@ snapshots: untruncate-json@0.0.1: {} - update-browserslist-db@1.1.3(browserslist@4.24.5): - dependencies: - browserslist: 4.24.5 - escalade: 3.2.0 - picocolors: 1.1.1 - update-browserslist-db@1.1.3(browserslist@4.25.1): dependencies: browserslist: 4.25.1 escalade: 3.2.0 picocolors: 1.1.1 - optional: true uri-js@4.4.1: dependencies: @@ -21297,7 +21041,7 @@ snapshots: v8-to-istanbul@9.3.0: dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 From 5b0ee0d42e3e8a5bc64ad79206b05ad803e728c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Valverde?= Date: Fri, 1 Aug 2025 06:16:23 +0200 Subject: [PATCH 02/14] Add whatsapp-client-demo --- .../apps/client-whatsapp-example/.gitignore | 44 + .../apps/client-whatsapp-example/README.md | 190 +++ .../apps/client-whatsapp-example/package.json | 28 + .../src/app/api/send-message/route.ts | 78 ++ .../src/app/api/webhook/route.ts | 64 + .../src/app/config/page.tsx | 329 +++++ .../src/app/globals.css | 21 + .../src/app/layout.tsx | 34 + .../client-whatsapp-example/src/app/page.tsx | 365 ++++++ .../client-whatsapp-example/src/lib/config.ts | 92 ++ .../client-whatsapp-example/tsconfig.json | 27 + typescript-sdk/pnpm-lock.yaml | 1083 ++++++++++++++++- 12 files changed, 2314 insertions(+), 41 deletions(-) create mode 100644 typescript-sdk/apps/client-whatsapp-example/.gitignore create mode 100644 typescript-sdk/apps/client-whatsapp-example/README.md create mode 100644 typescript-sdk/apps/client-whatsapp-example/package.json create mode 100644 typescript-sdk/apps/client-whatsapp-example/src/app/api/send-message/route.ts create mode 100644 typescript-sdk/apps/client-whatsapp-example/src/app/api/webhook/route.ts create mode 100644 typescript-sdk/apps/client-whatsapp-example/src/app/config/page.tsx create mode 100644 typescript-sdk/apps/client-whatsapp-example/src/app/globals.css create mode 100644 typescript-sdk/apps/client-whatsapp-example/src/app/layout.tsx create mode 100644 typescript-sdk/apps/client-whatsapp-example/src/app/page.tsx create mode 100644 typescript-sdk/apps/client-whatsapp-example/src/lib/config.ts create mode 100644 typescript-sdk/apps/client-whatsapp-example/tsconfig.json diff --git a/typescript-sdk/apps/client-whatsapp-example/.gitignore b/typescript-sdk/apps/client-whatsapp-example/.gitignore new file mode 100644 index 000000000..2a5eb5b3f --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/.gitignore @@ -0,0 +1,44 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# demo config file +.config.json \ No newline at end of file diff --git a/typescript-sdk/apps/client-whatsapp-example/README.md b/typescript-sdk/apps/client-whatsapp-example/README.md new file mode 100644 index 000000000..67badf260 --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/README.md @@ -0,0 +1,190 @@ +# AG-UI WhatsApp Example + +A Next.js demonstration application showcasing AG-UI's WhatsApp Business API integration. This example shows how to build a web application that can send WhatsApp messages and receive webhooks. + +## Features + +- **WhatsApp Business API Integration**: Send messages using the WhatsApp Business API +- **Web-based Configuration**: Secure configuration interface for WhatsApp credentials +- **Debug Tools**: Built-in debugging tools to test API credentials +- **Webhook Support**: Receive and process incoming WhatsApp messages +- **Modern UI**: Clean, responsive interface built with Next.js and Tailwind CSS + +## Tech Stack + +- **Framework**: Next.js 15 (App Router) +- **Styling**: Tailwind CSS +- **WhatsApp Integration**: AG-UI Community WhatsApp Package +- **Language**: TypeScript +- **Deployment**: Vercel-ready + +## Prerequisites + +- Node.js 18+ +- WhatsApp Business API account +- Meta Developer Console access + +## Quick Start + +1. **Install dependencies**: + ```bash + pnpm install + ``` + +2. **Run the development server**: + ```bash + pnpm dev + ``` + +3. **Open your browser**: + Navigate to [http://localhost:3000](http://localhost:3000) + +## WhatsApp Business API Setup + +### 1. Create WhatsApp Business API App + +1. Go to [Meta Developer Console](https://developers.facebook.com/) +2. Create a new app or use an existing one +3. Add the **WhatsApp Business API** product +4. Configure your phone number + +### 2. Get Your Credentials + +You'll need these values from your Meta Developer Console: + +- **Phone Number ID**: Found in WhatsApp Business API โ†’ Phone Numbers +- **Access Token**: Generated from System Users โ†’ Generate Token +- **Webhook Secret**: Create a strong secret for webhook verification +- **Verify Token**: Any string for webhook verification challenges + +### 3. Configure the App + +1. Open the app in your browser +2. Click **"Configure"** in the top right +3. Enter your WhatsApp Business API credentials +4. Save the configuration + +### 4. Test the Integration + +1. **Debug Credentials**: Click "Debug Credentials" to test your setup +2. **Send Messages**: Use the form to send test messages +3. **Check Webhooks**: Configure your webhook URL in Meta Developer Console + +## Project Structure + +``` +client-whatsapp-example/ +โ”œโ”€โ”€ src/ +โ”‚ โ”œโ”€โ”€ app/ +โ”‚ โ”‚ โ”œโ”€โ”€ api/ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ config/ # Configuration management +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ debug/ # Debug API endpoint +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ send-message/ # Send WhatsApp messages +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ webhook/ # Receive webhooks +โ”‚ โ”‚ โ”œโ”€โ”€ config/ # Configuration page +โ”‚ โ”‚ โ””โ”€โ”€ page.tsx # Main application page +โ”‚ โ””โ”€โ”€ lib/ +โ”‚ โ””โ”€โ”€ config.ts # Configuration utilities +โ”œโ”€โ”€ public/ # Static assets +โ””โ”€โ”€ README.md # This file +``` + +## API Endpoints + +### Configuration Management +- `GET /api/config` - Get current configuration status +- `POST /api/config` - Save new configuration + +### WhatsApp Integration +- `POST /api/send-message` - Send WhatsApp message +- `GET/POST /api/webhook` - Handle WhatsApp webhooks + +### Debug Tools +- `GET /api/debug` - Test WhatsApp API credentials + +## Environment Variables + +Create a `.env.local` file with your WhatsApp credentials: + +```env +# WhatsApp Business API Configuration +WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id_here +WHATSAPP_ACCESS_TOKEN=your_access_token_here +WHATSAPP_WEBHOOK_SECRET=your_webhook_secret_here +WHATSAPP_VERIFY_TOKEN=your_verify_token_here +``` + +## Deployment + +### Vercel Deployment + +1. **Push to GitHub**: + ```bash + git add . + git commit -m "Add WhatsApp example app" + git push origin main + ``` + +2. **Deploy to Vercel**: + - Connect your GitHub repository to Vercel + - Add environment variables in Vercel dashboard + - Deploy automatically + +### Environment Variables in Production + +Set these in your Vercel dashboard: +- `WHATSAPP_PHONE_NUMBER_ID` +- `WHATSAPP_ACCESS_TOKEN` +- `WHATSAPP_WEBHOOK_SECRET` +- `WHATSAPP_VERIFY_TOKEN` + +## Security Notes + +- **Demo Configuration**: This example uses file-based storage for demo purposes +- **Production**: Use secure environment variables or a database +- **Webhook Security**: Always verify webhook signatures in production +- **Access Tokens**: Keep your access tokens secure and rotate regularly + +## Troubleshooting + +### Common Issues + +1. **"Phone Number ID does not exist"** + - Verify your Phone Number ID in Meta Developer Console + - Check that your access token has the right permissions + +2. **"Missing permissions"** + - Ensure your access token has `whatsapp_business_messaging` permission + - Check that you're using the correct Phone Number ID + +3. **"Webhook verification failed"** + - Verify your webhook secret matches in both places + - Check that your webhook URL is accessible + +### Debug Tools + +Use the built-in debug tools to: +- Test your WhatsApp API credentials +- Verify your Phone Number ID +- Check API permissions +- Validate webhook configuration + +## Contributing + +This is part of the AG-UI project. To contribute: + +1. Fork the AG-UI repository +2. Create a feature branch +3. Make your changes +4. Submit a pull request + +## License + +This example is part of the AG-UI project and follows the same license terms. + +## Related Links + +- [AG-UI Documentation](https://docs.ag-ui.com) +- [WhatsApp Business API Documentation](https://developers.facebook.com/docs/whatsapp) +- [Meta Developer Console](https://developers.facebook.com/) +- [Next.js Documentation](https://nextjs.org/docs) \ No newline at end of file diff --git a/typescript-sdk/apps/client-whatsapp-example/package.json b/typescript-sdk/apps/client-whatsapp-example/package.json new file mode 100644 index 000000000..70e4acf34 --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/package.json @@ -0,0 +1,28 @@ +{ + "name": "@ag-ui/client-whatsapp-example", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@ag-ui/community-whatsapp": "workspace:../../integrations/community-whatsapp", + "next": "15.4.5", + "react": "^18", + "react-dom": "^18" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "autoprefixer": "^10.0.1", + "eslint": "^8", + "eslint-config-next": "15.4.5", + "postcss": "^8", + "tailwindcss": "^3.3.0", + "typescript": "^5" + } +} \ No newline at end of file diff --git a/typescript-sdk/apps/client-whatsapp-example/src/app/api/send-message/route.ts b/typescript-sdk/apps/client-whatsapp-example/src/app/api/send-message/route.ts new file mode 100644 index 000000000..a8b400d88 --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/src/app/api/send-message/route.ts @@ -0,0 +1,78 @@ +import { NextRequest, NextResponse } from "next/server"; +// import { WhatsAppAgent } from "@ag-ui/community-whatsapp"; +import { getConfig } from "@/lib/config"; + +export async function POST(request: NextRequest) { + try { + console.log("Send message API called"); + const config = getConfig(); + console.log("Config retrieved:", config ? "exists" : "null"); + + if (!config) { + console.log("No configuration found, returning error"); + return NextResponse.json( + { error: "WhatsApp configuration not found. Please configure your settings first." }, + { status: 500 } + ); + } + + console.log("Creating WhatsApp agent with config"); + console.log("Phone Number ID:", config.phoneNumberId); + console.log("Has Access Token:", !!config.accessToken); + console.log("Has Webhook Secret:", !!config.webhookSecret); + + // const agent = new WhatsAppAgent({ + // phoneNumberId: config.phoneNumberId, + // accessToken: config.accessToken, + // webhookSecret: config.webhookSecret, + // }); + + const { phoneNumber, message } = await request.json(); + console.log("Sending message to:", phoneNumber); + console.log("Message content:", message); + + if (!phoneNumber || !message) { + return NextResponse.json( + { error: "phoneNumber and message are required" }, + { status: 400 } + ); + } + + console.log("Calling sendMessageToNumber"); + try { + // const response = await agent.sendMessageToNumber(phoneNumber, message); + // console.log("Message sent successfully:", response.messages[0].id); + + // Temporary mock response for testing + const response = { + messages: [{ id: "mock-message-id" }] + }; + + return NextResponse.json({ + success: true, + messageId: response.messages[0].id, + response, + }); + } catch (sendError) { + console.error("Detailed send error:", { + error: sendError, + message: sendError instanceof Error ? sendError.message : 'Unknown error', + stack: sendError instanceof Error ? sendError.stack : undefined + }); + + return NextResponse.json( + { + error: "WhatsApp integration not available in this example", + details: sendError instanceof Error ? sendError.message : 'Unknown error' + }, + { status: 500 } + ); + } + } catch (error) { + console.error("Send message error:", error); + return NextResponse.json( + { error: "Failed to send message" }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/typescript-sdk/apps/client-whatsapp-example/src/app/api/webhook/route.ts b/typescript-sdk/apps/client-whatsapp-example/src/app/api/webhook/route.ts new file mode 100644 index 000000000..c6c0e30c7 --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/src/app/api/webhook/route.ts @@ -0,0 +1,64 @@ +import { NextRequest, NextResponse } from "next/server"; +// import { WhatsAppAgent } from "@ag-ui/community-whatsapp"; +import { getConfig } from "@/lib/config"; + +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url); + const mode = searchParams.get("hub.mode"); + const token = searchParams.get("hub.verify_token"); + const challenge = searchParams.get("hub.challenge"); + + console.log("Webhook verification request:", { mode, token, challenge }); + + const config = getConfig(); + if (!config) { + console.log("No configuration found for webhook verification"); + return NextResponse.json({ error: "Configuration not found" }, { status: 500 }); + } + + if (mode === "subscribe" && token === config.verifyToken) { + console.log("Webhook verified successfully"); + return new NextResponse(challenge, { status: 200 }); + } + + console.log("Webhook verification failed"); + return NextResponse.json({ error: "Forbidden" }, { status: 403 }); +} + +export async function POST(request: NextRequest) { + try { + console.log("Webhook POST received"); + const config = getConfig(); + + if (!config) { + console.log("No configuration found for webhook processing"); + return NextResponse.json({ error: "Configuration not found" }, { status: 500 }); + } + + // const agent = new WhatsAppAgent({ + // phoneNumberId: config.phoneNumberId, + // accessToken: config.accessToken, + // webhookSecret: config.webhookSecret, + // }); + + const body = await request.text(); + console.log("Webhook body:", body); + + // Verify webhook signature + // const signature = request.headers.get("x-hub-signature-256"); + // if (!signature || !agent.verifyWebhookSignature(body, signature)) { + // console.log("Webhook signature verification failed"); + // return NextResponse.json({ error: "Invalid signature" }, { status: 401 }); + // } + + // Process webhook + // const webhookData = JSON.parse(body); + // const processedMessages = await agent.processWebhook(webhookData); + + console.log("Webhook processed successfully (mock)"); + return NextResponse.json({ success: true }); + } catch (error) { + console.error("Webhook processing error:", error); + return NextResponse.json({ error: "Webhook processing failed" }, { status: 500 }); + } +} \ No newline at end of file diff --git a/typescript-sdk/apps/client-whatsapp-example/src/app/config/page.tsx b/typescript-sdk/apps/client-whatsapp-example/src/app/config/page.tsx new file mode 100644 index 000000000..826b85acf --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/src/app/config/page.tsx @@ -0,0 +1,329 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; + +interface ConfigForm { + phoneNumberId: string; + accessToken: string; + webhookSecret: string; + verifyToken: string; +} + +export default function ConfigPage() { + const router = useRouter(); + const [form, setForm] = useState({ + phoneNumberId: "", + accessToken: "", + webhookSecret: "", + verifyToken: "", + }); + const [isLoading, setIsLoading] = useState(false); + const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null); + const [showSecrets, setShowSecrets] = useState(false); + + useEffect(() => { + // Load existing config from API + fetch("/api/config") + .then(res => res.json()) + .then(data => { + if (!data.error && data.phoneNumberId) { + setForm({ + phoneNumberId: data.phoneNumberId, + accessToken: "", // Don't load sensitive data + webhookSecret: "", // Don't load sensitive data + verifyToken: "", // Don't load sensitive data + }); + } + }) + .catch(() => { + // Config not found, start with empty form + }); + }, []); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + setMessage(null); + + try { + const response = await fetch("/api/config", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(form), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || "Failed to save configuration"); + } + + setMessage({ + type: "success", + text: "Configuration saved successfully! Redirecting to main page..." + }); + + // Redirect back to main page after a short delay + setTimeout(() => { + router.push("/"); + }, 2000); + } catch (error) { + setMessage({ + type: "error", + text: error instanceof Error ? error.message : "Failed to save configuration. Please try again." + }); + } finally { + setIsLoading(false); + } + }; + + const handleInputChange = (field: keyof ConfigForm, value: string) => { + setForm(prev => ({ + ...prev, + [field]: value + })); + }; + + const generateRandomToken = () => { + const token = Math.random().toString(36).substring(2, 15) + + Math.random().toString(36).substring(2, 15); + handleInputChange("verifyToken", token); + }; + + const generateRandomSecret = () => { + const secret = Math.random().toString(36).substring(2, 15) + + Math.random().toString(36).substring(2, 15) + + Math.random().toString(36).substring(2, 15); + handleInputChange("webhookSecret", secret); + }; + + return ( +
+
+ {/* Header */} +
+

+ WhatsApp Configuration +

+

+ Configure your WhatsApp Business API settings securely +

+
+ +
+ {/* Security Notice */} +
+
+
+ + + +
+
+

+ Security Notice +

+
+

+ This is a demo application. In production, these secrets should be stored securely + on your server using environment variables or a secure configuration service. +

+
+
+
+
+ + {/* Configuration Form */} +
+
+ {/* Phone Number ID */} +
+ + handleInputChange("phoneNumberId", e.target.value)} + placeholder="123456789012345" + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 placeholder-gray-500" + required + /> +

+ Found in your WhatsApp Business API dashboard +

+
+ + {/* Access Token */} +
+ +
+ handleInputChange("accessToken", e.target.value)} + placeholder="EAA..." + className="w-full px-3 py-2 pr-10 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 placeholder-gray-500" + required + /> + +
+

+ Generated from your Meta Developer account +

+
+ + {/* Webhook Secret */} +
+ +
+
+ handleInputChange("webhookSecret", e.target.value)} + placeholder="your-webhook-secret" + className="w-full px-3 py-2 pr-10 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 placeholder-gray-500" + required + /> + +
+ +
+

+ Used to verify webhook signatures +

+
+ + {/* Verify Token */} +
+ +
+ handleInputChange("verifyToken", e.target.value)} + placeholder="your-verify-token" + className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 placeholder-gray-500" + required + /> + +
+

+ Used for webhook verification challenge +

+
+ + {/* Message */} + {message && ( +
+ {message.text} +
+ )} + + {/* Action Buttons */} +
+ + +
+
+
+ + {/* Help Section */} +
+

How to Get These Values

+
+
+

Phone Number ID

+

Found in your WhatsApp Business API dashboard under Phone Numbers

+
+
+

Access Token

+

Generate from Meta Developer Console โ†’ System Users โ†’ Generate Token

+
+
+

Webhook Secret

+

Create a strong secret for verifying webhook signatures

+
+
+

Verify Token

+

Any string you choose for webhook verification challenges

+
+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/typescript-sdk/apps/client-whatsapp-example/src/app/globals.css b/typescript-sdk/apps/client-whatsapp-example/src/app/globals.css new file mode 100644 index 000000000..80dc0f894 --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/src/app/globals.css @@ -0,0 +1,21 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} diff --git a/typescript-sdk/apps/client-whatsapp-example/src/app/layout.tsx b/typescript-sdk/apps/client-whatsapp-example/src/app/layout.tsx new file mode 100644 index 000000000..f7fa87eb8 --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/src/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/typescript-sdk/apps/client-whatsapp-example/src/app/page.tsx b/typescript-sdk/apps/client-whatsapp-example/src/app/page.tsx new file mode 100644 index 000000000..21e616381 --- /dev/null +++ b/typescript-sdk/apps/client-whatsapp-example/src/app/page.tsx @@ -0,0 +1,365 @@ +"use client"; + +import { useState, useEffect } from "react"; +import Link from "next/link"; + +interface SendMessageResult { + success: boolean; + messageId: string; + response: { + messaging_product: string; + contacts: Array<{ + input: string; + wa_id: string; + }>; + messages: Array<{ + id: string; + }>; + }; +} + +interface ConfigStatus { + phoneNumberId: string; + hasAccessToken: boolean; + hasWebhookSecret: boolean; + hasVerifyToken: boolean; +} + +interface DebugResult { + success?: boolean; + error?: string; + message?: string; + phoneNumberInfo?: Record; + status?: number; + response?: Record; +} + +export default function Home() { + const [phoneNumber, setPhoneNumber] = useState(""); + const [message, setMessage] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [configStatus, setConfigStatus] = useState(null); + const [debugResult, setDebugResult] = useState(null); + const [isDebugLoading, setIsDebugLoading] = useState(false); + + useEffect(() => { + // Check configuration status + fetch("/api/config") + .then(res => res.json()) + .then(data => { + if (data.error) { + setConfigStatus(null); + } else { + setConfigStatus(data); + } + }) + .catch(() => { + setConfigStatus(null); + }); + }, []); + + const handleSendMessage = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + setError(null); + setResult(null); + + try { + const response = await fetch("/api/send-message", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ phoneNumber, message }), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || "Failed to send message"); + } + + setResult(data); + } catch (err) { + setError(err instanceof Error ? err.message : "An error occurred"); + } finally { + setIsLoading(false); + } + }; + + const handleDebugCredentials = async () => { + setIsDebugLoading(true); + setDebugResult(null); + + try { + const response = await fetch("/api/debug"); + const data = await response.json(); + setDebugResult(data); + } catch (err) { + setDebugResult({ + error: err instanceof Error ? err.message : "Debug failed" + }); + } finally { + setIsDebugLoading(false); + } + }; + + const isConfigured = configStatus && + configStatus.phoneNumberId && + configStatus.hasAccessToken && + configStatus.hasWebhookSecret && + configStatus.hasVerifyToken; + + return ( +
+
+ {/* Header */} +
+

+ AG-UI WhatsApp Demo +

+

+ A lean demonstration of AG-UI WhatsApp integration. Send messages and + receive webhooks through the WhatsApp Business API. +

+
+ + {/* Main Content */} +
+ {/* Configuration Status */} +
+
+

+ Configuration Status +

+
+ + + Configure + +
+
+ + {configStatus ? ( +
+
+
+ + Phone Number ID: {configStatus.phoneNumberId ? "Configured" : "Not configured"} + +
+
+
+ + Access Token: {configStatus.hasAccessToken ? "Configured" : "Not configured"} + +
+
+
+ + Webhook Secret: {configStatus.hasWebhookSecret ? "Configured" : "Not configured"} + +
+
+
+ + Verify Token: {configStatus.hasVerifyToken ? "Configured" : "Not configured"} + +
+
+ ) : ( +
+

No configuration found

+ + Set Up Configuration + +
+ )} +
+ + {/* Debug Results */} + {debugResult && ( +
+

+ Debug Results +

+ {debugResult.success ? ( +
+

โœ… {debugResult.message || 'Credentials are valid'}

+ {debugResult.phoneNumberInfo && ( +
+ Phone Number Details +
+                        {JSON.stringify(debugResult.phoneNumberInfo, null, 2)}
+                      
+
+ )} +
+ ) : ( +
+

โŒ {debugResult.error}

+ {debugResult.status && ( +

Status: {debugResult.status}

+ )} + {debugResult.response && ( +
+ Error Details +
+                        {JSON.stringify(debugResult.response, null, 2)}
+                      
+
+ )} +
+ )} +
+ )} + + {/* Send Message Form */} +
+

+ Send WhatsApp Message +

+ + {!isConfigured ? ( +
+
+ + + +
+

+ Please configure your WhatsApp Business API settings first. +

+ + Configure Now + +
+ ) : ( +
+
+ + setPhoneNumber(e.target.value)} + placeholder="+1234567890" + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent text-gray-900 placeholder-gray-500" + required + /> +
+
+ +