feat: add API usage code snippets with tabs on agent details page
- Added CodeBlock import for syntax-highlighted code examples - Added Tabs for switching between cURL, TypeScript, Python, and AI SDK - Shows working examples with the agent's actual endpoint URL - AI SDK tab shows both hosted usage and self-hosted option with tool packages - Includes helpful note about conversation IDs 🤖 Generated with [Claude Code](https://claude.ai/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
42dac85d92
commit
d156b29286
1 changed files with 134 additions and 22 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
import type { AIProvider } from '@tpmjs/types/agent';
|
import type { AIProvider } from '@tpmjs/types/agent';
|
||||||
import { PROVIDER_MODELS, SUPPORTED_PROVIDERS } from '@tpmjs/types/agent';
|
import { PROVIDER_MODELS, SUPPORTED_PROVIDERS } from '@tpmjs/types/agent';
|
||||||
import { Button } from '@tpmjs/ui/Button/Button';
|
import { Button } from '@tpmjs/ui/Button/Button';
|
||||||
|
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
|
||||||
import { Icon } from '@tpmjs/ui/Icon/Icon';
|
import { Icon } from '@tpmjs/ui/Icon/Icon';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
|
|
@ -13,6 +14,7 @@ import {
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from '@tpmjs/ui/Table/Table';
|
} from '@tpmjs/ui/Table/Table';
|
||||||
|
import { Tabs } from '@tpmjs/ui/Tabs/Tabs';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
@ -80,6 +82,136 @@ const PROVIDER_DISPLAY_NAMES: Record<AIProvider, string> = {
|
||||||
MISTRAL: 'Mistral',
|
MISTRAL: 'Mistral',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CODE_TABS = [
|
||||||
|
{ id: 'curl', label: 'cURL' },
|
||||||
|
{ id: 'typescript', label: 'TypeScript' },
|
||||||
|
{ id: 'python', label: 'Python' },
|
||||||
|
{ id: 'aisdk', label: 'AI SDK' },
|
||||||
|
];
|
||||||
|
|
||||||
|
function ApiUsageSection({ agent, agentTools }: { agent: Agent; agentTools: AgentTool[] }) {
|
||||||
|
const [activeTab, setActiveTab] = useState('curl');
|
||||||
|
const baseUrl = typeof window !== 'undefined' ? window.location.origin : 'https://tpmjs.com';
|
||||||
|
const endpoint = `${baseUrl}/api/agents/${agent.uid}/conversation/my-conv-1`;
|
||||||
|
|
||||||
|
const toolPackages = agentTools.map((t) => t.tool.npmPackageName).join(' ') || '@tpmjs/hello';
|
||||||
|
|
||||||
|
const codeExamples: Record<string, { language: string; code: string }> = {
|
||||||
|
curl: {
|
||||||
|
language: 'bash',
|
||||||
|
code: `curl -X POST '${endpoint}' \\
|
||||||
|
-H 'Content-Type: application/json' \\
|
||||||
|
-d '{
|
||||||
|
"message": "Hello, what can you help me with?"
|
||||||
|
}'`,
|
||||||
|
},
|
||||||
|
typescript: {
|
||||||
|
language: 'typescript',
|
||||||
|
code: `const response = await fetch(
|
||||||
|
'${endpoint}',
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
message: 'Hello, what can you help me with?'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// The response is a streaming SSE response
|
||||||
|
const reader = response.body?.getReader();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader!.read();
|
||||||
|
if (done) break;
|
||||||
|
|
||||||
|
const chunk = decoder.decode(value);
|
||||||
|
// Parse SSE events: data: {...}
|
||||||
|
console.log(chunk);
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
python: {
|
||||||
|
language: 'python',
|
||||||
|
code: `import requests
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
'${endpoint}',
|
||||||
|
json={
|
||||||
|
'message': 'Hello, what can you help me with?'
|
||||||
|
},
|
||||||
|
stream=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Process streaming response
|
||||||
|
for line in response.iter_lines():
|
||||||
|
if line:
|
||||||
|
# Parse SSE events: data: {...}
|
||||||
|
print(line.decode('utf-8'))`,
|
||||||
|
},
|
||||||
|
aisdk: {
|
||||||
|
language: 'typescript',
|
||||||
|
code: `import { streamText } from 'ai';
|
||||||
|
|
||||||
|
// Option 1: Use the hosted agent directly via fetch
|
||||||
|
const response = await fetch(
|
||||||
|
'${endpoint}',
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ message: 'Hello!' })
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Option 2: Build your own agent with the same tools
|
||||||
|
// Install tools: npm install ${toolPackages}
|
||||||
|
import { createAnthropic } from '@ai-sdk/anthropic';
|
||||||
|
|
||||||
|
const { textStream } = streamText({
|
||||||
|
model: createAnthropic()('${agent.modelId}'),
|
||||||
|
system: \`${agent.systemPrompt || 'You are a helpful assistant.'}\`,
|
||||||
|
prompt: 'Hello, what can you help me with?',
|
||||||
|
// Add your tools here
|
||||||
|
});
|
||||||
|
|
||||||
|
for await (const text of textStream) {
|
||||||
|
process.stdout.write(text);
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default to curl example if activeTab is not found (should not happen with controlled state)
|
||||||
|
const currentExample = codeExamples[activeTab] ?? {
|
||||||
|
language: 'bash',
|
||||||
|
code: codeExamples.curl?.code ?? '',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-background border border-border rounded-lg overflow-hidden mb-8">
|
||||||
|
<div className="flex items-center justify-between p-4 border-b border-border">
|
||||||
|
<h2 className="text-lg font-medium text-foreground">API Usage</h2>
|
||||||
|
<code className="text-xs text-foreground-secondary font-mono bg-surface px-2 py-1 rounded">
|
||||||
|
POST /api/agents/{agent.uid}/conversation/:id
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-b border-border px-4 py-2">
|
||||||
|
<Tabs tabs={CODE_TABS} activeTab={activeTab} onTabChange={setActiveTab} size="sm" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-4">
|
||||||
|
<CodeBlock language={currentExample.language} showCopy code={currentExample.code} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="px-4 pb-4">
|
||||||
|
<p className="text-xs text-foreground-tertiary">
|
||||||
|
Use any unique string as the conversation ID to maintain chat history across requests.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Agent detail page has multiple interconnected features
|
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Agent detail page has multiple interconnected features
|
||||||
export default function AgentDetailPage(): React.ReactElement {
|
export default function AgentDetailPage(): React.ReactElement {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|
@ -519,28 +651,8 @@ export default function AgentDetailPage(): React.ReactElement {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* API Endpoint */}
|
{/* API Usage */}
|
||||||
<div className="bg-background border border-border rounded-lg p-4 mb-8">
|
<ApiUsageSection agent={agent} agentTools={agentTools} />
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium text-foreground">API Endpoint</p>
|
|
||||||
<code className="text-sm text-foreground-secondary font-mono">
|
|
||||||
POST /api/agents/{agent.uid}/conversation/{'<conversation-id>'}
|
|
||||||
</code>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="secondary"
|
|
||||||
onClick={() => {
|
|
||||||
navigator.clipboard.writeText(
|
|
||||||
`${window.location.origin}/api/agents/${agent.uid}/conversation/<conversation-id>`
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon icon="copy" size="xs" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Tools Section */}
|
{/* Tools Section */}
|
||||||
<div className="bg-background border border-border rounded-lg overflow-hidden mb-8">
|
<div className="bg-background border border-border rounded-lg overflow-hidden mb-8">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue