diff --git a/apps/web/src/app/api/agents/[id]/conversation/[conversationId]/route.ts b/apps/web/src/app/api/agents/[id]/conversation/[conversationId]/route.ts index e779b2a..5b6dbd0 100644 --- a/apps/web/src/app/api/agents/[id]/conversation/[conversationId]/route.ts +++ b/apps/web/src/app/api/agents/[id]/conversation/[conversationId]/route.ts @@ -392,10 +392,18 @@ export async function POST(request: NextRequest, context: RouteContext): Promise /** * GET /api/agents/[id]/conversation/[conversationId] - * Retrieve conversation history (accepts id or uid) + * Retrieve conversation history with pagination (accepts id or uid) + * + * Query params: + * - limit: Max messages to return (default: 50, max: 100) + * - offset: Number of messages to skip (default: 0) */ -export async function GET(_request: NextRequest, context: RouteContext): Promise { +export async function GET(request: NextRequest, context: RouteContext): Promise { const { id: idOrUid, conversationId } = await context.params; + const { searchParams } = new URL(request.url); + + const limit = Math.min(Number.parseInt(searchParams.get('limit') || '50', 10), 100); + const offset = Number.parseInt(searchParams.get('offset') || '0', 10); try { // Fetch agent by id or uid @@ -410,7 +418,7 @@ export async function GET(_request: NextRequest, context: RouteContext): Promise return NextResponse.json({ success: false, error: 'Agent not found' }, { status: 404 }); } - // Fetch conversation with messages + // Fetch conversation const conversation = await prisma.conversation.findUnique({ where: { agentId_slug: { @@ -418,11 +426,6 @@ export async function GET(_request: NextRequest, context: RouteContext): Promise slug: conversationId, }, }, - include: { - messages: { - orderBy: { createdAt: 'asc' }, - }, - }, }); if (!conversation) { @@ -432,7 +435,18 @@ export async function GET(_request: NextRequest, context: RouteContext): Promise ); } - const mappedMessages = conversation.messages.map((m) => ({ + // Fetch messages with pagination + const messages = await prisma.message.findMany({ + where: { conversationId: conversation.id }, + orderBy: { createdAt: 'asc' }, + take: limit + 1, + skip: offset, + }); + + const hasMore = messages.length > limit; + const paginatedMessages = hasMore ? messages.slice(0, limit) : messages; + + const mappedMessages = paginatedMessages.map((m) => ({ id: m.id, role: m.role, content: m.content, @@ -455,6 +469,11 @@ export async function GET(_request: NextRequest, context: RouteContext): Promise updatedAt: conversation.updatedAt, messages: mappedMessages, }, + pagination: { + limit, + offset, + hasMore, + }, }); } catch (error) { console.error('Failed to fetch conversation:', error); diff --git a/apps/web/src/app/dashboard/agents/[id]/page.tsx b/apps/web/src/app/dashboard/agents/[id]/page.tsx index 45d6f82..5fb8d06 100644 --- a/apps/web/src/app/dashboard/agents/[id]/page.tsx +++ b/apps/web/src/app/dashboard/agents/[id]/page.tsx @@ -89,6 +89,157 @@ const CODE_TABS = [ { id: 'aisdk', label: 'AI SDK' }, ]; +const FETCH_TABS = [ + { id: 'curl', label: 'cURL' }, + { id: 'typescript', label: 'TypeScript' }, + { id: 'python', label: 'Python' }, +]; + +function ConversationFetchSection({ agent }: { agent: Agent }) { + const [activeTab, setActiveTab] = useState('curl'); + const baseUrl = typeof window !== 'undefined' ? window.location.origin : 'https://tpmjs.com'; + const listEndpoint = `${baseUrl}/api/agents/${agent.uid}/conversations`; + const getEndpoint = `${baseUrl}/api/agents/${agent.uid}/conversation/my-conv-1`; + + const codeExamples: Record = { + curl: { + language: 'bash', + code: `# List all conversations (with pagination) +curl '${listEndpoint}?limit=20&offset=0' + +# Get a specific conversation with messages +curl '${getEndpoint}?limit=50&offset=0' + +# Delete a conversation +curl -X DELETE '${getEndpoint}'`, + }, + typescript: { + language: 'typescript', + code: `// List all conversations with pagination +const listConversations = async (limit = 20, offset = 0) => { + const response = await fetch( + \`${listEndpoint}?limit=\${limit}&offset=\${offset}\` + ); + const data = await response.json(); + + // data.data: [{ id, slug, title, messageCount, createdAt, updatedAt }] + // data.pagination: { limit, offset, hasMore } + return data; +}; + +// Get conversation with paginated messages +const getConversation = async ( + conversationId: string, + limit = 50, + offset = 0 +) => { + const response = await fetch( + \`${baseUrl}/api/agents/${agent.uid}/conversation/\${conversationId}?limit=\${limit}&offset=\${offset}\` + ); + const data = await response.json(); + + // data.data: { id, slug, title, messages: [...], createdAt, updatedAt } + // data.pagination: { limit, offset, hasMore } + return data; +}; + +// Fetch all messages (handling pagination) +const getAllMessages = async (conversationId: string) => { + const messages = []; + let offset = 0; + const limit = 50; + + while (true) { + const { data, pagination } = await getConversation( + conversationId, limit, offset + ); + messages.push(...data.messages); + + if (!pagination.hasMore) break; + offset += limit; + } + + return messages; +};`, + }, + python: { + language: 'python', + code: `import requests + +BASE_URL = '${baseUrl}/api/agents/${agent.uid}' + +# List all conversations with pagination +def list_conversations(limit=20, offset=0): + response = requests.get( + f'{BASE_URL}/conversations', + params={'limit': limit, 'offset': offset} + ) + return response.json() + +# Get conversation with paginated messages +def get_conversation(conversation_id, limit=50, offset=0): + response = requests.get( + f'{BASE_URL}/conversation/{conversation_id}', + params={'limit': limit, 'offset': offset} + ) + return response.json() + +# Fetch all messages (handling pagination) +def get_all_messages(conversation_id): + messages = [] + offset = 0 + limit = 50 + + while True: + result = get_conversation(conversation_id, limit, offset) + messages.extend(result['data']['messages']) + + if not result['pagination']['hasMore']: + break + offset += limit + + return messages + +# Example usage +conversations = list_conversations() +for conv in conversations['data']: + print(f"{conv['slug']}: {conv['title']} ({conv['messageCount']} messages)")`, + }, + }; + + const currentExample = codeExamples[activeTab] ?? { + language: 'bash', + code: codeExamples.curl?.code ?? '', + }; + + return ( +
+
+

Fetch Conversations

+ + GET /api/agents/{agent.uid}/conversations + +
+ +
+ +
+ +
+ +
+ +
+

+ Use limit and{' '} + offset query params for pagination. Check{' '} + hasMore to know if more results exist. +

+
+
+ ); +} + function ApiUsageSection({ agent, agentTools }: { agent: Agent; agentTools: AgentTool[] }) { const [activeTab, setActiveTab] = useState('curl'); const baseUrl = typeof window !== 'undefined' ? window.location.origin : 'https://tpmjs.com'; @@ -654,6 +805,9 @@ export default function AgentDetailPage(): React.ReactElement { {/* API Usage */} + {/* Fetch Conversations */} + + {/* Tools Section */}