# Zendesk

The Zendesk integration enables your Minded agents to seamlessly interact with Zendesk tickets, conversations, and customer data. This integration provides a complete interface for building intelligent customer support agents that can handle ticket management, customer communication, and workflow automation.

## Overview

The Zendesk integration provides:

* **Ticket Management** - Create, update, and manage ticket status
* **Customer Communication** - Send messages and comments
* **Conversation Handling** - Access conversation history and context
* **Tag Management** - Add and manage ticket tags
* **Custom Fields** - Set and update custom field values
* **Search Capabilities** - Search tickets and conversations
* **Real-time Updates** - Receive and respond to Zendesk events

## Quick Start

### 1. Basic Setup

```typescript
import { Agent } from '@minded/sdk';
import { zendesk } from '@minded/sdk/interfaces/zendesk';
import { events } from '@minded/sdk';

const agent = new Agent({
  memorySchema: yourMemorySchema,
  config: mindedConfig,
  tools: yourTools,
});

// Initialize Zendesk interface
zendesk.init(agent);

// Handle AI messages - send them to Zendesk
agent.on(events.AI_MESSAGE, async ({ message, state }) => {
  await zendesk.sendMessage(state.sessionId!, message);
});
```

### 2. Trigger Configuration

Configure your flow with a Zendesk trigger:

```yaml
# flows/zendeskFlow.yaml
name: Zendesk Support Flow
nodes:
  - name: Zendesk-Trigger
    type: trigger
    triggerType: app
    appTriggerId: zendesk-interface
    appTriggerName: Zendesk Minded Conversation
    appName: Zendesk

  - name: Support-Agent
    type: promptNode
    prompt: |
      You are a helpful customer support agent. 
      Respond to the customer's inquiry professionally and helpfully.

edges:
  - source: Zendesk-Trigger
    target: Support-Agent
    type: stepForward
```

## Available Methods

### Core Communication

#### `sendMessage(sessionId: string, message: string)`

Send a message to the customer in the Zendesk conversation.

```typescript
await zendesk.sendMessage(sessionId, 'Hello! How can I help you today?');
```

#### `sendComment(sessionId: string, comment: string)`

Add an internal comment to the ticket (not visible to customer).

```typescript
await zendesk.sendComment(sessionId, 'Customer issue escalated to tier 2');
```

#### `sendPublicComment(sessionId: string, comment: string)`

Add a public comment to the ticket (visible to customer).

```typescript
await zendesk.sendPublicComment(sessionId, 'Issue resolved - closing ticket');
```

### Conversation Management

#### `getConversation(sessionId: string)`

Retrieve the complete conversation context.

```typescript
const conversation = await zendesk.getConversation(sessionId);
console.log(conversation);
```

#### `getConversationMessages(sessionId: string)`

Get all messages in the conversation.

```typescript
const messages = await zendesk.getConversationMessages(sessionId);
```

### Ticket Operations

#### `getTicket(sessionId: string)`

Retrieve ticket information and metadata.

```typescript
const ticket = await zendesk.getTicket(sessionId);
console.log(`Ticket status: ${ticket.status}`);
```

#### `createTicket(params)`

Create a new ticket with specified parameters.

```typescript
await zendesk.createTicket({
  sessionId: sessionId,
  subject: 'Customer inquiry about order #12345',
  ticketBody: 'Customer is asking about their order status',
  priority: 'normal',
  tags: ['order-inquiry', 'customer-support'],
  customFields: [
    { id: 123, value: 'urgent' },
    { id: 456, value: 'premium-customer' },
  ],
});
```

#### `markTicketAsSolved(sessionId: string)`

Mark a ticket as solved.

```typescript
await zendesk.markTicketAsSolved({ sessionId });
```

#### `markTicketAsOpen(sessionId: string)`

Reopen a closed ticket.

```typescript
await zendesk.markTicketAsOpen({ sessionId });
```

### Tag and Field Management

#### `addTag(sessionId: string, tag: string)`

Add a tag to the ticket.

```typescript
await zendesk.addTag(sessionId, 'escalated');
```

#### `setCustomFields(sessionId: string, fields: any[])`

Set custom field values on the ticket.

```typescript
await zendesk.setCustomFields({
  sessionId,
  fields: [
    { id: 123, value: 'high-priority' },
    { id: 456, value: 'technical-issue' },
  ],
});
```

#### `search(sessionId: string, query: string)`

Search tickets and conversations.

```typescript
const results = await zendesk.search({
  sessionId,
  query: 'customer:john.doe@example.com status:open',
});
```

## Complete Example

Here's a comprehensive example of a Zendesk customer support agent:

### Project Structure

```
zendesk-agent/
├── minded.json
├── agentMemorySchema.ts
├── zendeskAgent.ts
├── flows/
│   └── supportFlow.yaml
└── tools/
    ├── escalateIssue.ts
    ├── lookupOrder.ts
    └── index.ts
```

### Configuration

**`minded.json`:**

```json
{
  "flows": ["./flows"],
  "tools": ["./tools"],
  "agent": "./zendeskAgent.ts",
  "llm": {
    "name": "AzureChatOpenAI",
    "properties": {
      "model": "gpt-4o",
      "temperature": 0.7
    }
  }
}
```

### Memory Schema

**`agentMemorySchema.ts`:**

```typescript
import { z } from 'zod';

export default z.object({
  // Customer information
  customerName: z.string().optional(),
  customerEmail: z.string().optional(),
  customerId: z.string().optional(),

  // Issue tracking
  issueType: z.enum(['billing', 'technical', 'general', 'escalation']).optional(),
  issueDescription: z.string().optional(),
  priority: z.enum(['low', 'normal', 'high', 'urgent']).optional(),

  // Ticket information
  ticketId: z.string().optional(),
  ticketStatus: z.string().optional(),
  ticketTags: z.array(z.string()).optional(),

  // Resolution tracking
  resolution: z.string().optional(),
  resolved: z.boolean().optional(),
  escalated: z.boolean().optional(),

  // Conversation context
  conversationStage: z.enum(['greeting', 'information_gathering', 'issue_resolution', 'closing']).optional(),
});
```

### Agent Implementation

**`zendeskAgent.ts`:**

```typescript
import { Agent } from '@minded/sdk';
import { zendesk } from '@minded/sdk/interfaces/zendesk';
import { events } from '@minded/sdk';
import { HumanMessage } from '@langchain/core/messages';
import memorySchema from './schema';
import tools from './tools';
import mindedConfig from './minded.json';

const agent = new Agent({
  memorySchema,
  config: mindedConfig,
  tools,
});

// Initialize Zendesk interface
zendesk.init(agent);

// Handle AI messages
agent.on(events.AI_MESSAGE, async ({ message, state }) => {
  await zendesk.sendMessage(state.sessionId!, message);
});

// Handle trigger events from Zendesk
agent.on(events.TRIGGER_EVENT, async ({ triggerBody, sessionId }) => {
  // Qualify the trigger and set initial context
  const isValidTrigger = triggerBody.content && triggerBody.content.trim().length > 0;

  if (!isValidTrigger) {
    return { isQualified: false };
  }

  return {
    isQualified: true,
    messages: [new HumanMessage({ content: triggerBody.content })],
    sessionId,
    memory: {
      conversationStage: 'greeting',
      customerEmail: triggerBody.customerEmail,
      ticketId: triggerBody.ticketId,
    },
  };
});

// Handle escalation events
agent.on(events.MEMORY_UPDATE, async ({ memory, state }) => {
  if (memory.escalated && !memory.resolved) {
    await zendesk.addTag(state.sessionId!, 'escalated');
    await zendesk.sendComment(state.sessionId!, `Issue escalated: ${memory.issueDescription}`);
  }
});

export default agent;
```

### Flow Definition

**`flows/supportFlow.yaml`:**

```yaml
name: Zendesk Support Flow
nodes:
  - name: Zendesk-Trigger
    type: trigger
    triggerType: app
    appTriggerId: zendesk-interface
    appTriggerName: Zendesk Minded Conversation
    appName: Zendesk

  - name: Support-Agent
    type: promptNode
    prompt: |
      You are a professional customer support agent. 

      Customer Context:
      - Email: {memory.customerEmail}
      - Issue Type: {memory.issueType}
      - Priority: {memory.priority}
      - Stage: {memory.conversationStage}

      Guidelines:
      1. Be empathetic and professional
      2. Gather necessary information about the issue
      3. Provide clear solutions or next steps
      4. Escalate complex issues when needed
      5. Always confirm resolution before closing

      If this is the first interaction, greet the customer and ask about their issue.

  - name: Escalate-Issue
    type: tool
    toolName: escalateIssue

  - name: Resolve-Issue
    type: promptNode
    prompt: |
      The issue has been resolved. Please:
      1. Summarize the solution provided
      2. Ask if the customer needs anything else
      3. Thank them for their patience

edges:
  - source: Zendesk-Trigger
    target: Support-Agent
    type: stepForward

  - source: Support-Agent
    target: Escalate-Issue
    type: promptCondition
    prompt: Customer issue requires escalation to a specialist

  - source: Support-Agent
    target: Resolve-Issue
    type: promptCondition
    prompt: Customer issue has been resolved successfully

  - source: Escalate-Issue
    target: Support-Agent
    type: stepForward

  - source: Resolve-Issue
    target: Support-Agent
    type: promptCondition
    prompt: Customer has additional questions or issues
```

### Tools Implementation

**`tools/escalateIssue.ts`:**

```typescript
import { Tool } from '@minded/sdk';
import { zendesk } from '@minded/sdk/interfaces/zendesk';
import { z } from 'zod';

const escalateIssue: Tool<any, any> = {
  name: 'escalateIssue',
  description: 'Escalate a customer issue to a specialist',
  inputSchema: z.object({
    reason: z.string().describe('Reason for escalation'),
    priority: z.enum(['high', 'urgent']).describe('Escalation priority'),
  }),
  func: async ({ reason, priority }, { memory, sessionId }) => {
    // Add escalation tag
    await zendesk.addTag(sessionId!, 'escalated');

    // Set priority
    await zendesk.setCustomFields({
      sessionId: sessionId!,
      fields: [{ id: 123, value: priority }], // Assuming field ID 123 is priority
    });

    // Add internal comment
    await zendesk.sendComment(sessionId!, `ESCALATED: ${reason} - Priority: ${priority}`);

    return {
      success: true,
      message: `Issue escalated with priority: ${priority}`,
      memory: {
        ...memory,
        escalated: true,
        priority: priority,
      },
    };
  },
};

export default escalateIssue;
```

## Best Practices

### 1. Error Handling

Always implement proper error handling for Zendesk operations:

```typescript
agent.on(events.AI_MESSAGE, async ({ message, state }) => {
  try {
    await zendesk.sendMessage(state.sessionId!, message);
  } catch (err) {
    logger.error({ message: 'Failed to send message to Zendesk', err });
    // Implement fallback or retry logic
  }
});
```

### 2. Memory Management

Use memory to maintain context across the conversation:

```typescript
// Track conversation progress
memory.conversationStage = 'information_gathering';

// Store important customer data
memory.customerEmail = triggerBody.customerEmail;
memory.issueType = 'billing';
```

### 3. Trigger Qualification

Implement proper trigger qualification to handle only relevant events:

```typescript
agent.on(events.TRIGGER_EVENT, async ({ triggerBody, sessionId }) => {
  // Only process triggers with actual content
  if (!triggerBody.content || triggerBody.content.trim().length === 0) {
    return { isQualified: false };
  }

  // Skip automated messages
  if (triggerBody.isAutomated) {
    return { isQualified: false };
  }

  return { isQualified: true };
});
```

### 4. Tag Management

Use tags consistently for tracking and automation:

```typescript
// Add tags based on issue type
if (memory.issueType === 'billing') {
  await zendesk.addTag(sessionId, 'billing-issue');
}

// Track resolution status
if (memory.resolved) {
  await zendesk.addTag(sessionId, 'resolved-by-ai');
}
```

### 5. Custom Fields

Leverage custom fields for enhanced workflow automation:

```typescript
// Set custom fields for reporting and automation
await zendesk.setCustomFields({
  sessionId,
  fields: [
    { id: 123, value: memory.priority },
    { id: 456, value: memory.issueType },
    { id: 789, value: 'ai-handled' },
  ],
});
```

## Integration Architecture

The Zendesk integration follows this architecture:

1. **Trigger Events** - Zendesk sends events to your agent
2. **Agent Processing** - Your agent processes the event and determines response
3. **Zendesk API Calls** - Agent makes calls back to Zendesk via the interface
4. **Real-time Updates** - Changes are reflected in Zendesk immediately

This architecture ensures seamless bi-directional communication between your Minded agent and Zendesk, enabling sophisticated customer support automation while maintaining full control over the conversation flow.

## Troubleshooting

### Common Issues

1. **Connection Issues**: Ensure your Zendesk credentials are properly configured
2. **Permission Errors**: Verify your Zendesk API permissions include required scopes
3. **Rate Limiting**: Implement proper rate limiting and retry logic
4. **Session Management**: Ensure sessionId is properly maintained across requests

### Debug Mode

Enable debug logging to troubleshoot issues:

```typescript
// Add debugging to your agent
agent.on(events.AI_MESSAGE, async ({ message, state }) => {
  console.log('Sending message to Zendesk:', { message, sessionId: state.sessionId });
  await zendesk.sendMessage(state.sessionId!, message);
});
```

For additional support, consult the [Minded platform documentation](https://github.com/minded-ai/mindedjs/blob/main/docs/platform/README.md) or contact support.
