From 77204577c14d1fb3caf489f1a37fe43e6977d417 Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Sat, 17 Jan 2026 01:39:53 +1000 Subject: [PATCH] feat(web): redesign agent API reference with design system - Replace minimal tabs with comprehensive API documentation - Add fieldset-style containers with dashed borders per design system - Document all 4 endpoints: send message, list, get, delete conversations - Add authentication section with clear instructions - Add parameter tables with types, defaults, and descriptions - Document SSE event types for streaming responses - Add conversation ID explanation section - Use lowercase headings and monospace fonts per design guide - Code examples in cURL, TypeScript, and Python --- .../src/app/dashboard/agents/[id]/page.tsx | 590 ++++++++++++++---- 1 file changed, 476 insertions(+), 114 deletions(-) diff --git a/apps/web/src/app/dashboard/agents/[id]/page.tsx b/apps/web/src/app/dashboard/agents/[id]/page.tsx index b8bda94..1c43d0a 100644 --- a/apps/web/src/app/dashboard/agents/[id]/page.tsx +++ b/apps/web/src/app/dashboard/agents/[id]/page.tsx @@ -12,7 +12,6 @@ import { Label } from '@tpmjs/ui/Label/Label'; import { Select } from '@tpmjs/ui/Select/Select'; import { Spinner } from '@tpmjs/ui/Spinner/Spinner'; import { Switch } from '@tpmjs/ui/Switch/Switch'; -import { Textarea } from '@tpmjs/ui/Textarea/Textarea'; import { Table, TableBody, @@ -23,6 +22,7 @@ import { TableRow, } from '@tpmjs/ui/Table/Table'; import { Tabs } from '@tpmjs/ui/Tabs/Tabs'; +import { Textarea } from '@tpmjs/ui/Textarea/Textarea'; import Link from 'next/link'; import { useParams, useRouter, useSearchParams } from 'next/navigation'; import { useCallback, useEffect, useRef, useState } from 'react'; @@ -102,186 +102,550 @@ const PROVIDER_DISPLAY_NAMES: Record = { MISTRAL: 'Mistral', }; -const API_SECTION_TABS = [ - { id: 'send', label: 'Send Message' }, - { id: 'fetch', label: 'Fetch Conversations' }, -]; - const LANG_OPTIONS = [ { id: 'curl', label: 'cURL' }, { id: 'typescript', label: 'TypeScript' }, { id: 'python', label: 'Python' }, - { id: 'aisdk', label: 'AI SDK' }, -]; - -const FETCH_LANG_OPTIONS = [ - { id: 'curl', label: 'cURL' }, - { id: 'typescript', label: 'TypeScript' }, - { id: 'python', label: 'Python' }, ]; function ApiDocsSection({ agent, agentTools }: { agent: Agent; agentTools: AgentTool[] }) { - const [activeSection, setActiveSection] = useState('send'); const [activeLang, setActiveLang] = useState('curl'); + const [expandedEndpoint, setExpandedEndpoint] = useState('send-message'); const baseUrl = typeof window !== 'undefined' ? window.location.origin : 'https://tpmjs.com'; const username = agent.user.username; - const endpoint = `${baseUrl}/api/${username}/agents/${agent.uid}/conversation/my-conv-1`; - const listEndpoint = `${baseUrl}/api/${username}/agents/${agent.uid}/conversations`; - const toolPackages = agentTools.map((t) => t.tool.npmPackageName).join(' ') || '@tpmjs/hello'; + const conversationEndpoint = `/api/${username}/agents/${agent.uid}/conversation`; + const listEndpoint = `/api/${username}/agents/${agent.uid}/conversations`; + const toolPackages = agentTools.map((t) => t.tool.npmPackageName).join(', ') || 'none'; - const sendExamples: Record = { + const toggleEndpoint = (id: string) => { + setExpandedEndpoint(expandedEndpoint === id ? null : id); + }; + + // Code examples for each endpoint + const sendMessageExamples: Record = { curl: { language: 'bash', - code: `curl -X POST '${endpoint}' \\ + code: `curl -X POST '${baseUrl}${conversationEndpoint}/my-conversation' \\ -H 'Content-Type: application/json' \\ -H 'Authorization: Bearer YOUR_TPMJS_API_KEY' \\ - -d '{ "message": "Hello, what can you help me with?" }'`, + -d '{ + "message": "Hello, what can you help me with?" + }'`, }, typescript: { language: 'typescript', - code: `const response = await fetch('${endpoint}', { + code: `const response = await fetch('${baseUrl}${conversationEndpoint}/my-conversation', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_TPMJS_API_KEY' }, - body: JSON.stringify({ message: 'Hello, what can you help me with?' }) + body: JSON.stringify({ + message: 'Hello, what can you help me with?' + }) }); // Stream SSE response const reader = response.body?.getReader(); const decoder = new TextDecoder(); + while (true) { const { done, value } = await reader!.read(); if (done) break; - console.log(decoder.decode(value)); + + const text = decoder.decode(value); + const lines = text.split('\\n'); + + for (const line of lines) { + if (line.startsWith('data: ')) { + const data = JSON.parse(line.slice(6)); + // Handle: text-delta, tool-call, tool-result, finish, error + console.log(data); + } + } }`, }, python: { language: 'python', code: `import requests +import json -response = requests.post('${endpoint}', - headers={'Authorization': 'Bearer YOUR_TPMJS_API_KEY'}, +response = requests.post( + '${baseUrl}${conversationEndpoint}/my-conversation', + headers={ + 'Authorization': 'Bearer YOUR_TPMJS_API_KEY', + 'Content-Type': 'application/json' + }, json={'message': 'Hello, what can you help me with?'}, - stream=True) + stream=True +) for line in response.iter_lines(): - if line: print(line.decode('utf-8'))`, - }, - aisdk: { - language: 'typescript', - code: `import { streamText } from 'ai'; -import { createAnthropic } from '@ai-sdk/anthropic'; - -// Option 1: Use hosted agent via fetch -const response = await fetch('${endpoint}', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer YOUR_TPMJS_API_KEY' - }, - body: JSON.stringify({ message: 'Hello!' }) -}); - -// Option 2: Build your own with same tools -// npm install ${toolPackages} -const { textStream } = streamText({ - model: createAnthropic()('${agent.modelId}'), - system: \`${agent.systemPrompt || 'You are a helpful assistant.'}\`, - prompt: 'Hello!', -});`, + if line: + line = line.decode('utf-8') + if line.startswith('data: '): + data = json.loads(line[6:]) + # Handle: text-delta, tool-call, tool-result, finish, error + print(data)`, }, }; - const fetchExamples: Record = { + const listConversationsExamples: Record = { curl: { language: 'bash', - code: `# List conversations -curl -H 'Authorization: Bearer YOUR_TPMJS_API_KEY' \\ - '${listEndpoint}?limit=20&offset=0' - -# Get conversation with messages -curl -H 'Authorization: Bearer YOUR_TPMJS_API_KEY' \\ - '${endpoint}?limit=50&offset=0' - -# Delete conversation -curl -X DELETE -H 'Authorization: Bearer YOUR_TPMJS_API_KEY' \\ - '${endpoint}'`, + code: `curl '${baseUrl}${listEndpoint}?limit=20&offset=0' \\ + -H 'Authorization: Bearer YOUR_TPMJS_API_KEY'`, }, typescript: { language: 'typescript', - code: `const headers = { 'Authorization': 'Bearer YOUR_TPMJS_API_KEY' }; + code: `const response = await fetch( + '${baseUrl}${listEndpoint}?limit=20&offset=0', + { headers: { 'Authorization': 'Bearer YOUR_TPMJS_API_KEY' } } +); -// List conversations -const list = await fetch('${listEndpoint}?limit=20&offset=0', { headers }); -const { data, pagination } = await list.json(); -// data: [{ id, slug, title, messageCount }], pagination: { hasMore } - -// Get conversation with messages -const conv = await fetch('${endpoint}?limit=50&offset=0', { headers }); -const { data: conversation } = await conv.json(); -// conversation: { id, slug, title, messages: [...] }`, +const { success, data, pagination } = await response.json(); +// data: [{ id, slug, title, messageCount, createdAt, updatedAt }] +// pagination: { limit, offset, hasMore }`, }, python: { language: 'python', code: `import requests -headers = {'Authorization': 'Bearer YOUR_TPMJS_API_KEY'} +response = requests.get( + '${baseUrl}${listEndpoint}', + headers={'Authorization': 'Bearer YOUR_TPMJS_API_KEY'}, + params={'limit': 20, 'offset': 0} +) -# List conversations -resp = requests.get('${listEndpoint}', headers=headers, params={'limit': 20, 'offset': 0}) -data = resp.json() # data['data'], data['pagination']['hasMore'] - -# Get conversation with messages -resp = requests.get('${endpoint}', headers=headers, params={'limit': 50, 'offset': 0}) -conv = resp.json() # conv['data']['messages']`, +data = response.json() +# data['data']: list of conversations +# data['pagination']['hasMore']: boolean`, }, }; - const isSend = activeSection === 'send'; - const examples = isSend ? sendExamples : fetchExamples; - const langOptions = isSend ? LANG_OPTIONS : FETCH_LANG_OPTIONS; - const effectiveLang = isSend || activeLang !== 'aisdk' ? activeLang : 'curl'; - const currentExample = examples[effectiveLang] ?? examples.curl ?? { language: 'bash', code: '' }; + const getConversationExamples: Record = { + curl: { + language: 'bash', + code: `curl '${baseUrl}${conversationEndpoint}/my-conversation?limit=50&offset=0' \\ + -H 'Authorization: Bearer YOUR_TPMJS_API_KEY'`, + }, + typescript: { + language: 'typescript', + code: `const response = await fetch( + '${baseUrl}${conversationEndpoint}/my-conversation?limit=50&offset=0', + { headers: { 'Authorization': 'Bearer YOUR_TPMJS_API_KEY' } } +); + +const { success, data } = await response.json(); +// data: { id, slug, title, messages: [...], pagination } +// messages: [{ id, role, content, toolCalls, createdAt }]`, + }, + python: { + language: 'python', + code: `import requests + +response = requests.get( + '${baseUrl}${conversationEndpoint}/my-conversation', + headers={'Authorization': 'Bearer YOUR_TPMJS_API_KEY'}, + params={'limit': 50, 'offset': 0} +) + +data = response.json() +# data['data']['messages']: list of messages +# data['data']['pagination']: { limit, offset, hasMore }`, + }, + }; + + const deleteConversationExamples: Record = { + curl: { + language: 'bash', + code: `curl -X DELETE '${baseUrl}${conversationEndpoint}/my-conversation' \\ + -H 'Authorization: Bearer YOUR_TPMJS_API_KEY'`, + }, + typescript: { + language: 'typescript', + code: `const response = await fetch( + '${baseUrl}${conversationEndpoint}/my-conversation', + { + method: 'DELETE', + headers: { 'Authorization': 'Bearer YOUR_TPMJS_API_KEY' } + } +); + +const { success } = await response.json();`, + }, + python: { + language: 'python', + code: `import requests + +response = requests.delete( + '${baseUrl}${conversationEndpoint}/my-conversation', + headers={'Authorization': 'Bearer YOUR_TPMJS_API_KEY'} +) + +data = response.json() +# data['success']: boolean`, + }, + }; + + const endpoints = [ + { + id: 'send-message', + method: 'POST', + path: `${conversationEndpoint}/:conversationId`, + title: 'send message', + description: + 'Send a message to the agent and receive a streaming response. If the conversation does not exist, it will be created automatically.', + examples: sendMessageExamples, + requestBody: [ + { + name: 'message', + type: 'string', + required: true, + description: 'The message to send to the agent', + }, + { + name: 'env', + type: 'object', + required: false, + description: 'Environment variables to pass to tools at runtime', + }, + ], + responseEvents: [ + { type: 'text-delta', description: 'Partial text content from the agent' }, + { type: 'tool-call', description: 'Agent is calling a tool with arguments' }, + { type: 'tool-result', description: 'Result returned from a tool execution' }, + { type: 'finish', description: 'Stream completed successfully' }, + { type: 'error', description: 'An error occurred during processing' }, + ], + }, + { + id: 'list-conversations', + method: 'GET', + path: listEndpoint, + title: 'list conversations', + description: + 'List all conversations for this agent. Results are paginated and sorted by most recently updated.', + examples: listConversationsExamples, + queryParams: [ + { + name: 'limit', + type: 'number', + default: '20', + description: 'Maximum number of results to return (1-100)', + }, + { + name: 'offset', + type: 'number', + default: '0', + description: 'Number of results to skip for pagination', + }, + ], + }, + { + id: 'get-conversation', + method: 'GET', + path: `${conversationEndpoint}/:conversationId`, + title: 'get conversation', + description: + 'Retrieve a conversation with its messages. Messages are paginated from newest to oldest.', + examples: getConversationExamples, + queryParams: [ + { + name: 'limit', + type: 'number', + default: '50', + description: 'Maximum number of messages to return', + }, + { name: 'offset', type: 'number', default: '0', description: 'Number of messages to skip' }, + ], + }, + { + id: 'delete-conversation', + method: 'DELETE', + path: `${conversationEndpoint}/:conversationId`, + title: 'delete conversation', + description: + 'Permanently delete a conversation and all its messages. This action cannot be undone.', + examples: deleteConversationExamples, + }, + ]; + + const methodColors: Record = { + GET: 'text-success', + POST: 'text-primary', + DELETE: 'text-error', + }; return ( -
-
-

API Reference

- - {isSend - ? `POST /api/${username}/agents/${agent.uid}/conversation/:id` - : `GET /api/${username}/agents/${agent.uid}/conversations`} - -
+
+ {/* Overview Section */} +
+ + overview + +
+

+ The Agent Conversation API allows you to interact with this agent programmatically. Send + messages, manage conversations, and integrate the agent into your applications. +

+
+
+

+ base url +

+ {baseUrl} +
+
+

+ tools attached +

+ {toolPackages} +
+
+
+
-
- + {/* Authentication Section */} +
+ + authentication + +
+

+ All API requests require authentication using a TPMJS API key. Include your key in the + + Authorization + + header as a Bearer token. +

+
+ Authorization:{' '} + Bearer YOUR_TPMJS_API_KEY +
+

+ Get your API key from the{' '} + + API Keys settings page + + . +

+
+
+ + {/* Language Selector */} +
+

endpoints