PrimeThink Documentation Help

Working with Chat Members

Overview

Live Pages can access information about all members in the current chat, including both human users and AI agents. This enables features like task assignment, creator tracking, and user-specific filtering.

Getting Chat Members

Use pt.getChatMembers() to retrieve all chat members:

const members = await pt.getChatMembers();

Response Structure

Each member object has a clear, consistent structure:

[ { "id": 123, // Member ID (user_id or agent_id) "type": "user", // "user" or "agent" "name": "John Doe", // Display name // User-specific fields (null for agents) "first_name": "John", "last_name": "Doe", "email": "john@example.com", "is_owner": true // Created the chat }, { "id": 456, "type": "agent", "name": "AI Assistant", // These are null for agents "first_name": null, "last_name": null, "email": null, "is_owner": false } ]

Field Reference

Field

Type

User

Agent

Description

id

number

Member ID

type

string

"user" or "agent"

name

string

Display name (full name or agent name)

first_name

string?

null

First name

last_name

string?

null

Last name

email

string?

null

Email address

is_owner

boolean

Created the chat

Common Use Cases

1. Display All Members

// Get and display all members const members = await pt.getChatMembers(); members.forEach(member => { const icon = member.type === 'user' ? '👤' : '🤖'; console.log(`${icon} ${member.name}`); }); // Filter by type const users = members.filter(m => m.type === 'user'); const agents = members.filter(m => m.type === 'agent'); console.log(`Users: ${users.length}, Agents: ${agents.length}`);

2. Create Member List UI

async function renderMemberList() { const members = await pt.getChatMembers(); const html = members.map(member => { const icon = member.type === 'user' ? '👤' : '🤖'; const badge = member.is_owner ? '<span class="owner-badge">Owner</span>' : ''; const details = member.email ? `<small>${member.email}</small>` : ''; return ` <div class="member-card ${member.type}"> ${icon} <strong>${member.name}</strong> ${badge} ${details} </div> `; }).join(''); document.getElementById('memberList').innerHTML = html; }

3. Get Current User

// Identify the current user (usually the owner) const members = await pt.getChatMembers(); const currentUser = members.find(m => m.type === 'user' && m.is_owner); console.log(`Current user: ${currentUser.name}`); console.log(`User ID: ${currentUser.id}`);

4. Create Assignment Dropdown

async function createAssigneeDropdown() { const members = await pt.getChatMembers(); const users = members.filter(m => m.type === 'user'); const options = users .map(m => `<option value="${m.id}">${m.name}</option>`) .join(''); return ` <select id="assignee" class="px-3 py-2 border rounded"> <option value="">Unassigned</option> ${options} </select> `; } // Usage document.getElementById('assigneeContainer').innerHTML = await createAssigneeDropdown();

Task Assignment Example

A complete example of task assignment with chat members:

<div class="container mx-auto p-6"> <h1 class="text-2xl font-bold mb-4">Team Tasks</h1> <!-- Filter by Assignee --> <div class="mb-4"> <label class="block text-sm font-medium mb-1">Filter by Assignee:</label> <select id="assigneeFilter" onchange="filterTasks()" class="px-3 py-2 border rounded"> <option value="">All Tasks</option> <option value="unassigned">Unassigned</option> </select> </div> <!-- Add New Task --> <div class="bg-white rounded-lg shadow p-4 mb-4"> <input type="text" id="taskInput" placeholder="New task..." class="w-full px-3 py-2 border rounded mb-2" > <div class="flex gap-2"> <select id="taskAssignee" class="flex-1 px-3 py-2 border rounded"> <option value="">Unassigned</option> </select> <button onclick="addTask()" class="bg-blue-500 text-white px-4 py-2 rounded"> Add Task </button> </div> </div> <!-- Task List --> <div id="tasksList"></div> </div> <script> let allMembers = []; let allTasks = []; // Initialize async function init() { // Load members first allMembers = await pt.getChatMembers(); // Populate dropdowns populateAssigneeDropdowns(); // Load tasks await loadTasks(); } function populateAssigneeDropdowns() { const users = allMembers.filter(m => m.type === 'user'); const options = users .map(m => `<option value="${m.id}">${m.name}</option>`) .join(''); // Populate filter dropdown const filterSelect = document.getElementById('assigneeFilter'); const existingOptions = filterSelect.innerHTML; filterSelect.innerHTML = existingOptions + options; // Populate assignment dropdown document.getElementById('taskAssignee').innerHTML = '<option value="">Unassigned</option>' + options; } async function loadTasks() { const entities = await pt.list({ entityNames: ['task'], filters: { completed: false } }); allTasks = entities.filter(e => e.entity_name === 'task'); displayTasks(allTasks); } async function filterTasks() { const assigneeId = document.getElementById('assigneeFilter').value; if (assigneeId === '') { // Show all tasks displayTasks(allTasks); } else if (assigneeId === 'unassigned') { // Show unassigned tasks const filtered = allTasks.filter(task => !task.data.assignee_id); displayTasks(filtered); } else { // Show tasks for specific user const filtered = allTasks.filter(task => task.data.assignee_id === parseInt(assigneeId) ); displayTasks(filtered); } } function displayTasks(tasks) { const html = tasks.map(task => { const assignee = allMembers.find(m => m.id === task.data.assignee_id); const assigneeName = assignee ? assignee.name : 'Unassigned'; const creator = allMembers.find(m => m.id === task.creator_user_id); const creatorName = creator ? creator.name : 'Unknown'; return ` <div class="bg-white rounded-lg shadow p-4 mb-2"> <div class="flex justify-between items-start"> <div> <p class="font-medium">${task.data.text}</p> <p class="text-sm text-gray-600"> Assigned to: ${assigneeName} </p> <p class="text-xs text-gray-400"> Created by: ${creatorName} </p> </div> <div class="flex gap-2"> <button onclick="reassignTask(${task.id})" class="text-blue-500 text-sm" > Reassign </button> <button onclick="deleteTask(${task.id})" class="text-red-500 text-sm" > Delete </button> </div> </div> </div> `; }).join(''); document.getElementById('tasksList').innerHTML = html || '<p class="text-gray-500 text-center">No tasks found</p>'; } async function addTask() { const text = document.getElementById('taskInput').value.trim(); const assigneeId = document.getElementById('taskAssignee').value; if (!text) return; await pt.add('task', { text: text, completed: false, assignee_id: assigneeId ? parseInt(assigneeId) : null }); document.getElementById('taskInput').value = ''; await loadTasks(); } async function reassignTask(taskId) { const task = await pt.get(taskId); const newAssigneeId = prompt('Enter new assignee ID (or leave empty for unassigned):'); await pt.edit(taskId, { ...task.data, assignee_id: newAssigneeId ? parseInt(newAssigneeId) : null }); await loadTasks(); } async function deleteTask(taskId) { if (confirm('Delete this task?')) { await pt.delete(taskId); await loadTasks(); } } // Initialize on page load document.addEventListener('DOMContentLoaded', init); </script>

Filtering by Creator

Every entity has a creator_user_id field that tracks who created it. This is a column-level filter (not JSONB data), making it efficient:

Basic Creator Filtering

// Get tasks created by current user const members = await pt.getChatMembers(); const currentUser = members.find(m => m.type === 'user' && m.is_owner); const myTasks = await pt.list({ entityNames: ['task'], filters: { creator_user_id: currentUser.id } });

Advanced Creator Filtering

// Get tasks created by multiple users const teamIds = [123, 456, 789]; const teamTasks = await pt.list({ entityNames: ['task'], filters: { creator_user_id: { $in: teamIds } } }); // Get tasks NOT created by current user const othersTasks = await pt.list({ entityNames: ['task'], filters: { creator_user_id: { $ne: currentUser.id } } }); // Combine creator filter with data filters const myActiveTasks = await pt.list({ entityNames: ['task'], filters: { creator_user_id: currentUser.id, // Column-level filter completed: false, // JSONB data filter priority: { $in: ['high', 'medium'] } } });

"My Tasks" Toggle

let allMembers = []; let currentUser = null; let showOnlyMyTasks = false; async function init() { allMembers = await pt.getChatMembers(); currentUser = allMembers.find(m => m.type === 'user' && m.is_owner); await loadTasks(); } async function loadTasks() { const filters = { completed: false }; if (showOnlyMyTasks && currentUser) { filters.creator_user_id = currentUser.id; } const entities = await pt.list({ entityNames: ['task'], filters: filters }); displayTasks(entities.filter(e => e.entity_name === 'task')); } function toggleMyTasks() { showOnlyMyTasks = !showOnlyMyTasks; loadTasks(); }

Per-User Settings Example

Store personal preferences using creator_user_id:

// Save user-specific settings async function saveUserSettings(settings) { const members = await pt.getChatMembers(); const currentUser = members.find(m => m.is_owner); // Check if user already has settings const existing = await pt.list({ entityNames: ['user_settings'], filters: { creator_user_id: currentUser.id } }); if (existing.length > 0) { // Update existing settings await pt.edit(existing[0].id, settings); } else { // Create new settings (creator_user_id is set automatically) await pt.add('user_settings', settings); } } // Load user-specific settings async function loadUserSettings() { const members = await pt.getChatMembers(); const currentUser = members.find(m => m.is_owner); const settings = await pt.list({ entityNames: ['user_settings'], filters: { creator_user_id: currentUser.id } }); return settings.length > 0 ? settings[0].data : getDefaultSettings(); } function getDefaultSettings() { return { theme: 'light', pageSize: 20, defaultView: 'list' }; }

Best Practices

1. Cache Members at Initialization

// ✅ GOOD: Load once at app start let allMembers = []; async function initApp() { allMembers = await pt.getChatMembers(); await loadTasks(); } function getMemberName(userId) { const member = allMembers.find(m => m.id === userId); return member ? member.name : 'Unknown'; } // ❌ AVOID: Calling getChatMembers() repeatedly async function displayTask(task) { const members = await pt.getChatMembers(); // Called for every task! const creator = members.find(m => m.id === task.creator_user_id); return creator.name; }

2. Handle Missing Members Gracefully

function getMemberName(userId) { const member = allMembers.find(m => m.id === userId); return member ? member.name : 'Unknown User'; } function displayTaskCreator(task) { const creator = allMembers.find(m => m.id === task.creator_user_id); if (!creator) { return '<span class="text-gray-400">Unknown</span>'; } const icon = creator.type === 'user' ? '👤' : '🤖'; return `${icon} ${creator.name}`; }

3. Separate Users and Agents

// Get only human users for assignment const users = allMembers.filter(m => m.type === 'user'); // Get only agents const agents = allMembers.filter(m => m.type === 'agent'); // Display differently function renderMemberBadge(member) { if (member.type === 'user') { return ` <div class="user-badge"> 👤 ${member.name} ${member.email ? `<small>${member.email}</small>` : ''} </div> `; } else { return ` <div class="agent-badge"> 🤖 ${member.name} </div> `; } }

4. Use Meaningful Variable Names

// ✅ GOOD: Clear variable names const chatMembers = await pt.getChatMembers(); const humanUsers = chatMembers.filter(m => m.type === 'user'); const aiAgents = chatMembers.filter(m => m.type === 'agent'); const chatOwner = chatMembers.find(m => m.is_owner); // ❌ AVOID: Unclear names const m = await pt.getChatMembers(); const u = m.filter(x => x.type === 'user');

Advanced Patterns

Team Dashboard

async function createTeamDashboard() { const members = await pt.getChatMembers(); const users = members.filter(m => m.type === 'user'); // Get all tasks const allTasks = await pt.list({ entityNames: ['task'], filters: { completed: false } }); // Calculate stats per user const stats = users.map(user => { const userTasks = allTasks.filter(t => t.data.assignee_id === user.id); const createdTasks = allTasks.filter(t => t.creator_user_id === user.id); return { user: user, assigned: userTasks.length, created: createdTasks.length, highPriority: userTasks.filter(t => t.data.priority === 'high').length }; }); // Display dashboard displayTeamStats(stats); } function displayTeamStats(stats) { const html = stats.map(stat => ` <div class="bg-white rounded-lg shadow p-4"> <h3 class="font-bold">${stat.user.name}</h3> <p>Assigned: ${stat.assigned}</p> <p>Created: ${stat.created}</p> <p>High Priority: ${stat.highPriority}</p> </div> `).join(''); document.getElementById('teamStats').innerHTML = html; }

User Activity Log

async function getUserActivity(userId) { // Get all entities created by user const created = await pt.list({ entityNames: ['task', 'note', 'event'], filters: { creator_user_id: userId }, limit: 100 }); // Get member info const members = await pt.getChatMembers(); const user = members.find(m => m.id === userId); return { user: user, activities: created.map(entity => ({ type: entity.entity_name, created: entity.created_at, data: entity.data })) }; }

Next Steps

22 October 2025