# Conversations API

Access and manage MAJK conversations with filtering, searching, and message handling.

## Quick Start

```typescript
handler: async (input, ctx) => {
  // List recent conversations
  const conversations = await ctx.majk.conversations.list({
    status: 'active'
  });

  // Get specific conversation
  const conv = await ctx.majk.conversations.get('conv-123');
  if (conv) {
    const messages = await conv.getMessages({ limit: 10 });
    return { title: conv.title, messageCount: messages.length };
  }

  return { conversations: conversations.length };
}
```

## API Reference

### get(id)

Get a conversation by ID.

```typescript
const conv = await ctx.majk.conversations.get('conv-123');
// Returns: ConversationHandle | null
```

### list(filter?)

List conversations with optional filters.

```typescript
const conversations = await ctx.majk.conversations.list({
  status?: 'active' | 'completed' | 'failed' | 'cancelled',
  agentId?: string,
  projectId?: string,
  teamMemberId?: string,
  createdAfter?: Date,
  createdBefore?: Date
});
// Returns: ConversationHandle[]
```

### exists(id)

Check if a conversation exists.

```typescript
const exists = await ctx.majk.conversations.exists('conv-123');
// Returns: boolean
```

### count(filter?)

Count conversations matching a filter.

```typescript
const count = await ctx.majk.conversations.count({ status: 'active' });
// Returns: number
```

### search(query)

Search conversations by text.

```typescript
const results = await ctx.majk.conversations.search('authentication bug');
// Returns: ConversationHandle[]
```

### channel()

Get the event channel for conversations.

```typescript
const channel = ctx.majk.conversations.channel();
```

## ConversationHandle

Handle returned from get/list operations.

### Properties

```typescript
interface ConversationHandle {
  readonly id: string;
  readonly agentId: string;
  readonly title: string;
  readonly status: 'active' | 'completed' | 'failed' | 'cancelled';
  readonly messageCount: number;
  readonly lastMessageAt?: Date;
  readonly workingDirectory?: string;
  readonly projectId?: string;
  readonly teamMemberId?: string;
  readonly createdAt: Date;
  readonly updatedAt: Date;
  readonly version: number;
}
```

### Methods

#### refresh()

Refresh the handle with latest data.

```typescript
await conv.refresh();
```

#### getMessages(options?)

Get conversation messages.

```typescript
const messages = await conv.getMessages({
  limit?: number,
  beforeSeq?: number,
  afterSeq?: number
});
// Returns: Message[]
```

#### send(message)

Send a message to the conversation.

```typescript
await conv.send('Please continue with the analysis');
```

#### getAgent()

Get the agent associated with this conversation.

```typescript
const agent = await conv.getAgent();
```

#### onChange(handler)

Subscribe to conversation changes.

```typescript
const unsubscribe = conv.onChange((updated) => {
  console.log('Conversation updated:', updated.title);
});

// Later
unsubscribe();
```

#### onDelete(handler)

Subscribe to deletion events.

```typescript
const unsubscribe = conv.onDelete(() => {
  console.log('Conversation was deleted');
});
```

#### toEntity()

Convert handle to plain entity object.

```typescript
const entity = conv.toEntity();
// Returns: Conversation
```

## Message Type

```typescript
interface Message {
  id: string;
  conversationId: string;
  role: 'user' | 'assistant' | 'tool' | 'system';
  content: string;
  seq: number;
  createdAt: Date;
  updatedAt: Date;
  version: number;
}
```

## Common Patterns

### Filter Active Conversations

```typescript
const active = await ctx.majk.conversations.list({
  status: 'active',
  createdAfter: new Date(Date.now() - 24 * 60 * 60 * 1000) // Last 24 hours
});

for (const conv of active) {
  ctx.logger.info(`Active: ${conv.title} (${conv.messageCount} messages)`);
}
```

### Get Recent Messages

```typescript
const conv = await ctx.majk.conversations.get(conversationId);
if (conv) {
  // Get last 20 messages
  const messages = await conv.getMessages({ limit: 20 });

  // Get messages before a specific sequence
  const older = await conv.getMessages({ beforeSeq: 50, limit: 10 });
}
```

### Search and Analyze

```typescript
const results = await ctx.majk.conversations.search('error handling');

for (const conv of results) {
  const messages = await conv.getMessages();
  const errorMessages = messages.filter(m =>
    m.content.toLowerCase().includes('error')
  );

  ctx.logger.info(`${conv.title}: ${errorMessages.length} error-related messages`);
}
```

### Monitor Conversation Changes

```typescript
.onReady(async (ctx, cleanup) => {
  const conversations = await ctx.majk.conversations.list({ status: 'active' });

  const unsubscribes = conversations.map(conv =>
    conv.onChange((updated) => {
      ctx.logger.info(`Conversation ${updated.id} updated`);
    })
  );

  cleanup(() => {
    unsubscribes.forEach(unsub => unsub());
  });
})
```

### Aggregate Statistics

```typescript
async function getConversationStats() {
  const [active, completed, failed] = await Promise.all([
    ctx.majk.conversations.count({ status: 'active' }),
    ctx.majk.conversations.count({ status: 'completed' }),
    ctx.majk.conversations.count({ status: 'failed' })
  ]);

  return { active, completed, failed, total: active + completed + failed };
}
```

## Best Practices

1. **Use filters** - Avoid listing all conversations when possible
2. **Paginate messages** - Use limit/beforeSeq for large conversations
3. **Cleanup subscriptions** - Always unsubscribe from onChange/onDelete
4. **Refresh when needed** - Call refresh() before critical operations
5. **Handle null** - get() may return null if conversation doesn't exist

## Next Steps

Run `npx @majkapp/plugin-kit --context` - Full context API
Run `npx @majkapp/plugin-kit --tasks` - Task management
Run `npx @majkapp/plugin-kit --agents` - Agent configuration
