docs: update all URL references to new username/slug format

Update all documentation, code, and tests to use the new endpoint formats:

- MCP: /api/mcp/{username}/{collection-slug}/{transport}
- Agent: /api/{username}/agents/{agent-uid}/conversation/{id}

Changes include:
- Update MCP URLs in collections page, docs, and test script
- Update agent API URLs in chat page, docs, tests, and cron job
- Add API key authentication requirements to all examples
- Update ARCHITECTURE.md with correct endpoint formats
- Update discord cron job to fetch owner username for new URL format
This commit is contained in:
Ajax Davis 2026-01-13 23:14:36 +10:00
parent 2b4526ba95
commit 2fb790a847
9 changed files with 163 additions and 93 deletions

View file

@ -635,10 +635,10 @@ The API is built on Next.js 16 App Router with standardized response formats.
| **Tools** | `GET /api/tools` | List/search tools |
| | `POST /api/tools/execute/[...slug]` | Execute tool (SSE) |
| **Agents** | `GET /api/agents` | List user agents |
| | `POST /api/agents/[id]/conversation/[convId]` | Chat with agent (SSE) |
| | `POST /api/{username}/agents/{uid}/conversation/{convId}` | Chat with agent (SSE) |
| **Collections** | `GET /api/collections` | List user collections |
| | `POST /api/collections/[id]/tools` | Add tool to collection |
| **MCP** | `POST /api/mcp/{user}/{slug}/{transport}` | MCP protocol |
| **MCP** | `POST /api/mcp/{username}/{slug}/{transport}` | MCP protocol |
| **Sync** | `POST /api/sync/changes` | Cron: npm changes |
| **Stats** | `GET /api/stats` | Registry statistics |

View file

@ -1,49 +1,67 @@
#!/bin/bash
# Test script for MCP endpoints
# Usage: ./test-mcp.sh <collection-id> [base-url]
# Usage: ./test-mcp.sh <username> <collection-slug> [base-url] [api-key]
#
# The new MCP URL format is: /api/mcp/{username}/{slug}/{transport}
# Collection ID is also supported as slug for backwards compatibility
COLLECTION_ID=${1:-""}
BASE_URL=${2:-"https://tpmjs.com"}
USERNAME=${1:-""}
COLLECTION_SLUG=${2:-""}
BASE_URL=${3:-"https://tpmjs.com"}
API_KEY=${4:-""}
if [ -z "$COLLECTION_ID" ]; then
echo "Usage: ./test-mcp.sh <collection-id> [base-url]"
echo "Example: ./test-mcp.sh clx123abc https://tpmjs.com"
if [ -z "$USERNAME" ] || [ -z "$COLLECTION_SLUG" ]; then
echo "Usage: ./test-mcp.sh <username> <collection-slug> [base-url] [api-key]"
echo "Example: ./test-mcp.sh ajax my-collection https://tpmjs.com tpmjs_sk_xxx"
echo ""
echo "Note: Collection ID can also be used as slug for backwards compatibility"
exit 1
fi
# Build auth header if API key provided
AUTH_HEADER=""
if [ -n "$API_KEY" ]; then
AUTH_HEADER="-H \"Authorization: Bearer $API_KEY\""
fi
echo "================================================"
echo "Testing MCP endpoints for collection: $COLLECTION_ID"
echo "Testing MCP endpoints"
echo "Username: $USERNAME"
echo "Collection: $COLLECTION_SLUG"
echo "Base URL: $BASE_URL"
echo "Auth: ${API_KEY:+API key provided}"
echo "================================================"
echo ""
# Test 1: HTTP transport - GET (server info)
echo "1. Testing HTTP GET (server info)..."
echo " GET $BASE_URL/api/collections/$COLLECTION_ID/mcp/http"
curl -s "$BASE_URL/api/collections/$COLLECTION_ID/mcp/http" | jq .
echo " GET $BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/http"
eval curl -s "$BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/http" $AUTH_HEADER | jq .
echo ""
# Test 2: HTTP transport - initialize
echo "2. Testing HTTP POST (initialize)..."
echo " POST $BASE_URL/api/collections/$COLLECTION_ID/mcp/http"
curl -s -X POST "$BASE_URL/api/collections/$COLLECTION_ID/mcp/http" \
echo " POST $BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/http"
eval curl -s -X POST "$BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/http" \
-H "Content-Type: application/json" \
$AUTH_HEADER \
-d '{"jsonrpc":"2.0","method":"initialize","id":1}' | jq .
echo ""
# Test 3: HTTP transport - tools/list
echo "3. Testing HTTP POST (tools/list)..."
echo " POST $BASE_URL/api/collections/$COLLECTION_ID/mcp/http"
curl -s -X POST "$BASE_URL/api/collections/$COLLECTION_ID/mcp/http" \
echo " POST $BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/http"
eval curl -s -X POST "$BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/http" \
-H "Content-Type: application/json" \
$AUTH_HEADER \
-d '{"jsonrpc":"2.0","method":"tools/list","id":2}' | jq .
echo ""
# Test 4: SSE transport - GET (event stream)
echo "4. Testing SSE GET (event stream)..."
echo " GET $BASE_URL/api/collections/$COLLECTION_ID/mcp/sse"
curl -s -N "$BASE_URL/api/collections/$COLLECTION_ID/mcp/sse" &
echo " GET $BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/sse"
eval curl -s -N "$BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/sse" $AUTH_HEADER &
SSE_PID=$!
sleep 2
kill $SSE_PID 2>/dev/null
@ -52,26 +70,28 @@ echo ""
# Test 5: SSE transport - initialize
echo "5. Testing SSE POST (initialize)..."
echo " POST $BASE_URL/api/collections/$COLLECTION_ID/mcp/sse"
curl -s -X POST "$BASE_URL/api/collections/$COLLECTION_ID/mcp/sse" \
echo " POST $BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/sse"
eval curl -s -X POST "$BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/sse" \
-H "Content-Type: application/json" \
$AUTH_HEADER \
-d '{"jsonrpc":"2.0","method":"initialize","id":1}'
echo ""
echo ""
# Test 6: SSE transport - tools/list
echo "6. Testing SSE POST (tools/list)..."
echo " POST $BASE_URL/api/collections/$COLLECTION_ID/mcp/sse"
curl -s -X POST "$BASE_URL/api/collections/$COLLECTION_ID/mcp/sse" \
echo " POST $BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/sse"
eval curl -s -X POST "$BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/sse" \
-H "Content-Type: application/json" \
$AUTH_HEADER \
-d '{"jsonrpc":"2.0","method":"tools/list","id":2}'
echo ""
echo ""
# Test 7: Invalid transport
echo "7. Testing invalid transport..."
echo " GET $BASE_URL/api/collections/$COLLECTION_ID/mcp/invalid"
curl -s "$BASE_URL/api/collections/$COLLECTION_ID/mcp/invalid" | jq .
echo " GET $BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/invalid"
eval curl -s "$BASE_URL/api/mcp/$USERNAME/$COLLECTION_SLUG/invalid" $AUTH_HEADER | jq .
echo ""
echo "================================================"

View file

@ -55,6 +55,7 @@ interface Agent {
collectionCount: number;
createdBy: {
id: string;
username: string | null;
name: string;
image: string | null;
};
@ -266,11 +267,11 @@ export default function PublicAgentChatPage(): React.ReactElement {
// Fetch messages for conversation (initial load - gets most recent 50)
const fetchMessages = useCallback(async () => {
if (!agent) return;
if (!agent || !agent.createdBy.username) return;
try {
const response = await fetch(
`/api/agents/${agent.uid}/conversation/${conversationId}?limit=50`
`/api/${agent.createdBy.username}/agents/${agent.uid}/conversation/${conversationId}?limit=50`
);
if (response.status === 404) {
// Conversation doesn't exist yet, that's fine
@ -294,7 +295,14 @@ export default function PublicAgentChatPage(): React.ReactElement {
// Load older messages when scrolling up
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Virtuoso scroll handler with pagination logic
const loadMoreMessages = useCallback(async () => {
if (!agent || isLoadingMore || !hasMoreMessages || messages.length === 0) return;
if (
!agent ||
!agent.createdBy.username ||
isLoadingMore ||
!hasMoreMessages ||
messages.length === 0
)
return;
setIsLoadingMore(true);
try {
@ -305,7 +313,7 @@ export default function PublicAgentChatPage(): React.ReactElement {
if (!beforeTimestamp) return;
const response = await fetch(
`/api/agents/${agent.uid}/conversation/${conversationId}?limit=50&before=${encodeURIComponent(beforeTimestamp)}`
`/api/${agent.createdBy.username}/agents/${agent.uid}/conversation/${conversationId}?limit=50&before=${encodeURIComponent(beforeTimestamp)}`
);
if (!response.ok) return;
@ -344,7 +352,7 @@ export default function PublicAgentChatPage(): React.ReactElement {
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Chat send handler with streaming and tool calls
const handleSend = async () => {
if (!input.trim() || !agent || isSending) return;
if (!input.trim() || !agent || !agent.createdBy.username || isSending) return;
const messageContent = input.trim();
setInput('');
@ -363,11 +371,14 @@ export default function PublicAgentChatPage(): React.ReactElement {
setMessages((prev) => [...prev, userMessage]);
try {
const response = await fetch(`/api/agents/${agent.uid}/conversation/${conversationId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: messageContent }),
});
const response = await fetch(
`/api/${agent.createdBy.username}/agents/${agent.uid}/conversation/${conversationId}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: messageContent }),
}
);
if (!response.ok) {
const errorData = await response.json();

View file

@ -47,10 +47,15 @@ export async function POST(request: NextRequest) {
}
try {
// 3. Verify agent exists
// 3. Verify agent exists and get owner info
const agent = await prisma.agent.findUnique({
where: { id: agentId },
select: { id: true, name: true },
select: {
id: true,
uid: true,
name: true,
user: { select: { username: true } },
},
});
if (!agent) {
@ -60,6 +65,13 @@ export async function POST(request: NextRequest) {
);
}
if (!agent.user.username || !agent.uid) {
return NextResponse.json(
{ success: false, error: 'Agent owner has no username or agent has no UID' },
{ status: 500 }
);
}
// 4. Get or create a conversation for this cron job
// Use a fixed slug for the cron job so we reuse the same conversation
const cronSlug = 'discord-summary-cron';
@ -100,10 +112,10 @@ Then use the discordPostTool to post the summary to channel "${summaryChannelId}
If there are no messages in the past 24 hours, post a brief message saying the server was quiet.`;
// 6. Call the agent conversation endpoint
// 6. Call the agent conversation endpoint (new URL format)
const baseUrl = env.BETTER_AUTH_URL || `http://localhost:${process.env.PORT || 3000}`;
const response = await fetch(
`${baseUrl}/api/agents/${agentId}/conversation/${conversation.id}`,
`${baseUrl}/api/${agent.user.username}/agents/${agent.uid}/conversation/${conversation.id}`,
{
method: 'POST',
headers: {

View file

@ -46,13 +46,13 @@ interface PublicCollection {
tools: CollectionTool[];
}
function McpUrlSection({ collectionId }: { collectionId: string }) {
function McpUrlSection({ username, slug }: { username: string; slug: string }) {
const [copiedUrl, setCopiedUrl] = useState<'http' | 'sse' | null>(null);
const [showConfig, setShowConfig] = useState(false);
const baseUrl = typeof window !== 'undefined' ? window.location.origin : 'https://tpmjs.com';
const httpUrl = `${baseUrl}/api/collections/${collectionId}/mcp/http`;
const sseUrl = `${baseUrl}/api/collections/${collectionId}/mcp/sse`;
const httpUrl = `${baseUrl}/api/mcp/${username}/${slug}/http`;
const sseUrl = `${baseUrl}/api/mcp/${username}/${slug}/sse`;
const copyToClipboard = async (url: string, type: 'http' | 'sse') => {
await navigator.clipboard.writeText(url);
@ -66,7 +66,9 @@ function McpUrlSection({ collectionId }: { collectionId: string }) {
"command": "npx",
"args": [
"mcp-remote",
"${httpUrl}"
"${httpUrl}",
"--header",
"Authorization: Bearer YOUR_TPMJS_API_KEY"
]
}
}
@ -309,7 +311,9 @@ export default function PublicCollectionDetailPage(): React.ReactElement {
</div>
{/* MCP URLs */}
<McpUrlSection collectionId={collection.id} />
{collection.createdBy?.username && collection.slug && (
<McpUrlSection username={collection.createdBy.username} slug={collection.slug} />
)}
{/* Tools */}
<div>

View file

@ -692,18 +692,30 @@ Always cite your sources and be transparent about limitations.`}
<DocSubSection title="Endpoint">
<CodeBlock
language="text"
code="POST /api/agents/[uid]/conversation/[conversationId]"
code="POST /api/{username}/agents/{agent-uid}/conversation/{conversationId}"
/>
<div className="mt-4 space-y-2 text-foreground-secondary text-sm">
<p>
<strong className="text-foreground">uid:</strong> Your agent&apos;s unique
identifier
<strong className="text-foreground">username:</strong> The agent owner&apos;s
username
</p>
<p>
<strong className="text-foreground">agent-uid:</strong> The agent&apos;s unique
identifier (slug)
</p>
<p>
<strong className="text-foreground">conversationId:</strong> Unique ID for the
conversation (create your own or use a new ID to start a new conversation)
</p>
</div>
<div className="mt-4 p-4 border border-primary/30 rounded-lg bg-primary/5">
<p className="text-sm text-foreground-secondary">
<strong className="text-foreground">Authentication Required:</strong> Include
the header{' '}
<code className="text-primary">Authorization: Bearer YOUR_TPMJS_API_KEY</code>{' '}
in all requests. Get your API key from the dashboard.
</p>
</div>
</DocSubSection>
<DocSubSection title="Request Body">
<ParamTable
@ -726,13 +738,19 @@ Always cite your sources and be transparent about limitations.`}
<DocSubSection title="Example: JavaScript Client">
<CodeBlock
language="typescript"
code={`const conversationId = 'conv-' + Date.now();
code={`const username = 'ajax'; // Agent owner's username
const agentUid = 'research-assistant'; // Agent UID
const conversationId = 'conv-' + Date.now();
const apiKey = 'tpmjs_sk_...'; // Your TPMJS API key
const response = await fetch(
\`https://tpmjs.com/api/agents/\${agentUid}/conversation/\${conversationId}\`,
\`https://tpmjs.com/api/\${username}/agents/\${agentUid}/conversation/\${conversationId}\`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
'Authorization': \`Bearer \${apiKey}\`,
},
body: JSON.stringify({ message: 'Search for AI tools' }),
}
);
@ -825,11 +843,11 @@ while (true) {
POST
</Badge>
<code className="text-foreground font-mono">
/api/agents/[uid]/conversation/[conversationId]
/api/[username]/agents/[uid]/conversation/[conversationId]
</code>
</div>
<p className="text-sm text-foreground-secondary">
Send a message and stream the AI response via SSE.
Send a message and stream the AI response via SSE. Requires TPMJS API key.
</p>
</div>
<div className="p-4 border border-border rounded-lg bg-surface">
@ -838,11 +856,11 @@ while (true) {
GET
</Badge>
<code className="text-foreground font-mono">
/api/agents/[uid]/conversation/[conversationId]
/api/[username]/agents/[uid]/conversation/[conversationId]
</code>
</div>
<p className="text-sm text-foreground-secondary">
Get the full conversation history with all messages.
Get the full conversation history with all messages. Requires TPMJS API key.
</p>
</div>
<div className="p-4 border border-border rounded-lg bg-surface">
@ -851,11 +869,11 @@ while (true) {
GET
</Badge>
<code className="text-foreground font-mono">
/api/agents/[uid]/conversations
/api/[username]/agents/[uid]/conversations
</code>
</div>
<p className="text-sm text-foreground-secondary">
List all conversations for an agent.
List all conversations for an agent. Requires TPMJS API key.
</p>
</div>
<div className="p-4 border border-border rounded-lg bg-surface">

View file

@ -1219,10 +1219,11 @@ export TPMJS_EXECUTOR_URL=https://executor.mycompany.com`}
</p>
<CodeBlock
language="text"
code="https://tpmjs.com/api/collections/<collection-id>/mcp/http"
code="https://tpmjs.com/api/mcp/<username>/<collection-slug>/http"
/>
<p className="text-foreground-secondary mt-4">
This URL is what you&apos;ll use to connect MCP clients to your collection.
You&apos;ll also need your TPMJS API key for authentication.
</p>
</DocSubSection>
</DocSection>
@ -1244,7 +1245,9 @@ export TPMJS_EXECUTOR_URL=https://executor.mycompany.com`}
"command": "npx",
"args": [
"mcp-remote",
"https://tpmjs.com/api/collections/<collection-id>/mcp/http"
"https://tpmjs.com/api/mcp/<username>/<collection-slug>/http",
"--header",
"Authorization: Bearer YOUR_TPMJS_API_KEY"
]
}
}
@ -1275,7 +1278,8 @@ export TPMJS_EXECUTOR_URL=https://executor.mycompany.com`}
<CodeBlock
language="bash"
code={`claude mcp add tpmjs-my-collection \\
-- npx mcp-remote https://tpmjs.com/api/collections/<collection-id>/mcp/http`}
-- npx mcp-remote https://tpmjs.com/api/mcp/<username>/<collection-slug>/http \\
--header "Authorization: Bearer YOUR_TPMJS_API_KEY"`}
/>
<p className="text-foreground-secondary mt-4">
This automatically adds the server to your Claude Code configuration.
@ -1305,7 +1309,7 @@ export TPMJS_EXECUTOR_URL=https://executor.mycompany.com`}
<DocSubSection title="Endpoint Format">
<CodeBlock
language="text"
code="POST https://tpmjs.com/api/collections/<collection-id>/mcp/http"
code="POST https://tpmjs.com/api/mcp/<username>/<collection-slug>/http"
/>
</DocSubSection>
<DocSubSection title="Request Headers">
@ -1318,6 +1322,9 @@ export TPMJS_EXECUTOR_URL=https://executor.mycompany.com`}
Accept: application/json, text/event-stream
</code>
</p>
<p>
<code className="text-primary">Authorization: Bearer YOUR_TPMJS_API_KEY</code>
</p>
</div>
</DocSubSection>
<DocSubSection title="Supported Methods">

View file

@ -370,7 +370,9 @@ Invalid usernames:
"command": "npx",
"args": [
"mcp-remote",
"https://tpmjs.com/api/collections/{collection-id}/mcp/http"
"https://tpmjs.com/api/mcp/{username}/{collection-slug}/http",
"--header",
"Authorization: Bearer YOUR_TPMJS_API_KEY"
]
}
}
@ -602,10 +604,10 @@ Invalid usernames:
<tr>
<td className="py-3 px-4 text-foreground">Agent Conversation</td>
<td className="py-3 px-4 font-mono text-primary text-xs">
/api/chat/{'{username}'}/{'{uid}'}/conversation/{'{id}'}
/api/{'{username}'}/agents/{'{uid}'}/conversation/{'{id}'}
</td>
<td className="py-3 px-4 font-mono text-foreground-secondary text-xs">
/api/chat/ajax/research-bot/conversation/abc123
/api/ajax/agents/research-bot/conversation/abc123
</td>
</tr>
</tbody>

View file

@ -87,6 +87,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
name: string;
userId: string;
provider: string;
user: { username: string | null };
} | null = null;
let testConversationId: string | null = null;
@ -110,11 +111,15 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
name: true,
userId: true,
provider: true,
user: { select: { username: true } },
},
});
if (!testAgent) {
console.warn(`⚠️ Test agent "${TEST_AGENT_UID}" not found. Skipping agent tests.`);
} else if (!testAgent.user.username) {
console.warn(`⚠️ Test agent owner has no username. Skipping agent tests.`);
testAgent = null;
}
} catch (error) {
console.warn('⚠️ Could not connect to database. Skipping agent tests.', error);
@ -139,7 +144,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
}
});
describe('POST /api/agents/[id]/conversation/[conversationId]', () => {
describe('POST /api/[username]/agents/[uid]/conversation/[conversationId]', () => {
it('should create a new conversation and receive a response', async () => {
if (!serverAvailable || !testAgent) {
console.log('Skipping: Server not available or no test agent');
@ -147,7 +152,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
}
const response = await fetch(
`${BASE_URL}/api/agents/${testAgent.uid}/conversation/${TEST_CONVERSATION_SLUG}`,
`${BASE_URL}/api/${testAgent.user.username}/agents/${testAgent.uid}/conversation/${TEST_CONVERSATION_SLUG}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@ -224,7 +229,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
}
const response = await fetch(
`${BASE_URL}/api/agents/${testAgent.uid}/conversation/${TEST_CONVERSATION_SLUG}`,
`${BASE_URL}/api/${testAgent.user.username}/agents/${testAgent.uid}/conversation/${TEST_CONVERSATION_SLUG}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@ -260,7 +265,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
const toolConvSlug = `tool-test-${Date.now()}`;
const response = await fetch(
`${BASE_URL}/api/agents/${testAgent.uid}/conversation/${toolConvSlug}`,
`${BASE_URL}/api/${testAgent.user.username}/agents/${testAgent.uid}/conversation/${toolConvSlug}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@ -312,7 +317,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
});
});
describe('GET /api/agents/[id]/conversation/[conversationId]', () => {
describe('GET /api/[username]/agents/[uid]/conversation/[conversationId]', () => {
it('should retrieve conversation history', async () => {
if (!serverAvailable || !testAgent || !testConversationId) {
console.log('Skipping: Server not available or no test conversation');
@ -320,7 +325,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
}
const response = await fetch(
`${BASE_URL}/api/agents/${testAgent.uid}/conversation/${TEST_CONVERSATION_SLUG}`,
`${BASE_URL}/api/${testAgent.user.username}/agents/${testAgent.uid}/conversation/${TEST_CONVERSATION_SLUG}`,
{ method: 'GET' }
);
@ -341,7 +346,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
}
const response = await fetch(
`${BASE_URL}/api/agents/${testAgent.uid}/conversation/non-existent-conv-12345`,
`${BASE_URL}/api/${testAgent.user.username}/agents/${testAgent.uid}/conversation/non-existent-conv-12345`,
{ method: 'GET' }
);
@ -349,16 +354,19 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
});
});
describe('GET /api/agents/[id]/conversations', () => {
describe('GET /api/[username]/agents/[uid]/conversations', () => {
it('should list all conversations for an agent', async () => {
if (!serverAvailable || !testAgent) {
console.log('Skipping: Server not available or no test agent');
return;
}
const response = await fetch(`${BASE_URL}/api/agents/${testAgent.id}/conversations`, {
method: 'GET',
});
const response = await fetch(
`${BASE_URL}/api/${testAgent.user.username}/agents/${testAgent.uid}/conversations`,
{
method: 'GET',
}
);
expect(response.ok).toBe(true);
@ -380,7 +388,7 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
}
const response = await fetch(
`${BASE_URL}/api/agents/${testAgent.id}/conversations?limit=1&offset=0`,
`${BASE_URL}/api/${testAgent.user.username}/agents/${testAgent.uid}/conversations?limit=1&offset=0`,
{ method: 'GET' }
);
@ -433,31 +441,19 @@ describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Agent Endpoints', () => {
});
});
describe('Agent with lookup by ID or UID', () => {
it('should accept agent ID in URL', async () => {
describe('Agent with username/uid lookup', () => {
it('should accept agent with username/uid format', async () => {
if (!serverAvailable || !testAgent) {
console.log('Skipping: Server not available or no test agent');
return;
}
const response = await fetch(`${BASE_URL}/api/agents/${testAgent.id}/conversations`, {
method: 'GET',
});
expect(response.ok).toBe(true);
const result = await response.json();
expect(result.success).toBe(true);
});
it('should accept agent UID in URL', async () => {
if (!serverAvailable || !testAgent) {
console.log('Skipping: Server not available or no test agent');
return;
}
const response = await fetch(`${BASE_URL}/api/agents/${testAgent.uid}/conversations`, {
method: 'GET',
});
const response = await fetch(
`${BASE_URL}/api/${testAgent.user.username}/agents/${testAgent.uid}/conversations`,
{
method: 'GET',
}
);
expect(response.ok).toBe(true);
const result = await response.json();