@promptbook/cli 0.103.0-54 → 0.103.0-56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/agents-server/config.ts +0 -2
- package/apps/agents-server/package-lock.json +1163 -0
- package/apps/agents-server/package.json +6 -0
- package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +79 -6
- package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +171 -69
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +3 -1
- package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +216 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +78 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileView.tsx +233 -0
- package/apps/agents-server/src/app/agents/[agentName]/CloneAgentButton.tsx +4 -4
- package/apps/agents-server/src/app/agents/[agentName]/InstallPwaButton.tsx +2 -2
- package/apps/agents-server/src/app/agents/[agentName]/QrCodeModal.tsx +90 -0
- package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +80 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +3 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +11 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +203 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/route.ts +3 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/systemMessage/route.ts +3 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/openai/chat/completions/route.ts +3 -169
- package/apps/agents-server/src/app/agents/[agentName]/api/openai/models/route.ts +93 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/chat/completions/route.ts +10 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/models/route.ts +93 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/openrouter/chat/completions/route.ts +10 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +4 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +9 -2
- package/apps/agents-server/src/app/agents/[agentName]/integration/SdkCodeTabs.tsx +31 -0
- package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +271 -30
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +182 -0
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +108 -165
- package/apps/agents-server/src/app/agents/[agentName]/website-integration/page.tsx +61 -0
- package/apps/agents-server/src/app/api/auth/change-password/route.ts +75 -0
- package/apps/agents-server/src/app/api/chat-feedback/export/route.ts +55 -0
- package/apps/agents-server/src/app/api/chat-history/export/route.ts +55 -0
- package/apps/agents-server/src/app/api/openai/v1/chat/completions/route.ts +6 -0
- package/apps/agents-server/src/app/api/openai/v1/models/route.ts +65 -0
- package/apps/agents-server/src/app/docs/[docId]/page.tsx +12 -32
- package/apps/agents-server/src/app/docs/page.tsx +42 -17
- package/apps/agents-server/src/app/globals.css +129 -0
- package/apps/agents-server/src/app/layout.tsx +8 -2
- package/apps/agents-server/src/app/manifest.ts +1 -1
- package/apps/agents-server/src/components/ChangePasswordDialog/ChangePasswordDialog.tsx +41 -0
- package/apps/agents-server/src/components/ChangePasswordForm/ChangePasswordForm.tsx +159 -0
- package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +87 -0
- package/apps/agents-server/src/components/Header/Header.tsx +94 -38
- package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +20 -0
- package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +18 -0
- package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +18 -0
- package/apps/agents-server/src/database/migrations/2025-12-0070-chat-history-source.sql +2 -0
- package/apps/agents-server/src/database/schema.ts +6 -0
- package/apps/agents-server/src/middleware.ts +1 -1
- package/apps/agents-server/src/utils/convertToCsv.ts +31 -0
- package/apps/agents-server/src/utils/handleChatCompletion.ts +355 -0
- package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +100 -0
- package/apps/agents-server/src/utils/validateApiKey.ts +128 -0
- package/apps/agents-server/tailwind.config.ts +1 -1
- package/esm/index.es.js +1188 -175
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +4 -0
- package/esm/typings/src/book-components/Chat/LlmChat/LlmChatProps.d.ts +5 -0
- package/esm/typings/src/commitments/CLOSED/CLOSED.d.ts +35 -0
- package/esm/typings/src/commitments/COMPONENT/COMPONENT.d.ts +28 -0
- package/esm/typings/src/commitments/FROM/FROM.d.ts +34 -0
- package/esm/typings/src/commitments/LANGUAGE/LANGUAGE.d.ts +35 -0
- package/esm/typings/src/commitments/META_COLOR/META_COLOR.d.ts +6 -0
- package/esm/typings/src/commitments/META_FONT/META_FONT.d.ts +42 -0
- package/esm/typings/src/commitments/OPEN/OPEN.d.ts +35 -0
- package/esm/typings/src/commitments/USE/USE.d.ts +53 -0
- package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.d.ts +38 -0
- package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.test.d.ts +1 -0
- package/esm/typings/src/commitments/USE_MCP/USE_MCP.d.ts +37 -0
- package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.d.ts +38 -0
- package/esm/typings/src/commitments/index.d.ts +12 -1
- package/esm/typings/src/playground/playground.d.ts +3 -0
- package/esm/typings/src/utils/color/Color.d.ts +8 -0
- package/esm/typings/src/utils/color/css-colors.d.ts +1 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/umd/index.umd.js +1180 -167
- package/umd/index.umd.js.map +1 -1
- package/esm/typings/src/playground/playground1.d.ts +0 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
2
|
+
import { validateApiKey } from '@/src/utils/validateApiKey';
|
|
3
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* GET /agents/[agentName]/api/openai/v1/models
|
|
7
|
+
*
|
|
8
|
+
* Lists available models for the OpenAI-compatible API.
|
|
9
|
+
* This endpoint is required for OpenAI-compatible clients (like Jan, LM Studio, etc.)
|
|
10
|
+
* to discover available models.
|
|
11
|
+
*/
|
|
12
|
+
export async function GET(request: NextRequest, { params }: { params: Promise<{ agentName: string }> }) {
|
|
13
|
+
const { agentName } = await params;
|
|
14
|
+
|
|
15
|
+
// Validate API key explicitly (in addition to middleware)
|
|
16
|
+
const apiKeyValidation = await validateApiKey(request);
|
|
17
|
+
if (!apiKeyValidation.isValid) {
|
|
18
|
+
return NextResponse.json(
|
|
19
|
+
{
|
|
20
|
+
error: {
|
|
21
|
+
message: apiKeyValidation.error || 'Invalid API key',
|
|
22
|
+
type: 'authentication_error',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{ status: 401 },
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const collection = await $provideAgentCollectionForServer();
|
|
31
|
+
|
|
32
|
+
let agentSource;
|
|
33
|
+
try {
|
|
34
|
+
agentSource = await collection.getAgentSource(agentName);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return NextResponse.json(
|
|
37
|
+
{ error: { message: `Agent '${agentName}' not found.`, type: 'invalid_request_error' } },
|
|
38
|
+
{ status: 404 },
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!agentSource) {
|
|
43
|
+
return NextResponse.json(
|
|
44
|
+
{ error: { message: `Agent '${agentName}' not found.`, type: 'invalid_request_error' } },
|
|
45
|
+
{ status: 404 },
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Return the agent as a single model in OpenAI format
|
|
50
|
+
// The model ID is the agent name, which clients will use when making chat completion requests
|
|
51
|
+
const models = [
|
|
52
|
+
{
|
|
53
|
+
id: agentName,
|
|
54
|
+
object: 'model',
|
|
55
|
+
created: Math.floor(Date.now() / 1000),
|
|
56
|
+
owned_by: 'promptbook',
|
|
57
|
+
permission: [
|
|
58
|
+
{
|
|
59
|
+
id: `modelperm-${agentName}`,
|
|
60
|
+
object: 'model_permission',
|
|
61
|
+
created: Math.floor(Date.now() / 1000),
|
|
62
|
+
allow_create_engine: false,
|
|
63
|
+
allow_sampling: true,
|
|
64
|
+
allow_logprobs: false,
|
|
65
|
+
allow_search_indices: false,
|
|
66
|
+
allow_view: true,
|
|
67
|
+
allow_fine_tuning: false,
|
|
68
|
+
organization: '*',
|
|
69
|
+
group: null,
|
|
70
|
+
is_blocking: false,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
root: agentName,
|
|
74
|
+
parent: null,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
return NextResponse.json({
|
|
79
|
+
object: 'list',
|
|
80
|
+
data: models,
|
|
81
|
+
});
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error('Error in models listing handler:', error);
|
|
84
|
+
return NextResponse.json(
|
|
85
|
+
{ error: { message: (error as Error).message || 'Internal Server Error', type: 'server_error' } },
|
|
86
|
+
{ status: 500 },
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* TODO: [🧠] Consider listing all available agents as models when agentName is a wildcard or special value
|
|
93
|
+
*/
|
package/apps/agents-server/src/app/agents/[agentName]/api/openrouter/chat/completions/route.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { handleChatCompletion } from '@/src/utils/handleChatCompletion';
|
|
2
|
+
import { NextRequest } from 'next/server';
|
|
3
|
+
|
|
4
|
+
export async function POST(
|
|
5
|
+
request: NextRequest,
|
|
6
|
+
{ params }: { params: Promise<{ agentName: string }> },
|
|
7
|
+
) {
|
|
8
|
+
const { agentName } = await params;
|
|
9
|
+
return handleChatCompletion(request, { agentName }, 'OpenRouter API Chat Completion');
|
|
10
|
+
}
|
|
@@ -98,6 +98,8 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
98
98
|
userAgent,
|
|
99
99
|
language,
|
|
100
100
|
platform,
|
|
101
|
+
source: 'AGENT_PAGE_CHAT',
|
|
102
|
+
apiKey: null,
|
|
101
103
|
});
|
|
102
104
|
|
|
103
105
|
// Call Agent
|
|
@@ -131,6 +133,8 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
131
133
|
userAgent,
|
|
132
134
|
language,
|
|
133
135
|
platform,
|
|
136
|
+
source: 'AGENT_PAGE_CHAT',
|
|
137
|
+
apiKey: null,
|
|
134
138
|
});
|
|
135
139
|
|
|
136
140
|
// Learning
|
|
@@ -7,16 +7,23 @@ import { AgentChatWrapper } from '../AgentChatWrapper';
|
|
|
7
7
|
|
|
8
8
|
export const generateMetadata = generateAgentMetadata;
|
|
9
9
|
|
|
10
|
-
export default async function AgentChatPage({
|
|
10
|
+
export default async function AgentChatPage({
|
|
11
|
+
params,
|
|
12
|
+
searchParams,
|
|
13
|
+
}: {
|
|
14
|
+
params: Promise<{ agentName: string }>;
|
|
15
|
+
searchParams: Promise<{ message?: string }>;
|
|
16
|
+
}) {
|
|
11
17
|
$sideEffect(headers());
|
|
12
18
|
let { agentName } = await params;
|
|
13
19
|
agentName = decodeURIComponent(agentName);
|
|
20
|
+
const { message } = await searchParams;
|
|
14
21
|
|
|
15
22
|
const agentUrl = `/agents/${agentName}`;
|
|
16
23
|
|
|
17
24
|
return (
|
|
18
25
|
<main className={`w-screen h-screen`}>
|
|
19
|
-
<AgentChatWrapper agentUrl={agentUrl} />
|
|
26
|
+
<AgentChatWrapper agentUrl={agentUrl} autoExecuteMessage={message} />
|
|
20
27
|
</main>
|
|
21
28
|
);
|
|
22
29
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { CodePreview } from '../../../../../../_common/components/CodePreview/CodePreview';
|
|
4
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../../../../../_common/components/Tabs/Tabs';
|
|
5
|
+
|
|
6
|
+
type SdkCodeTabsProps = {
|
|
7
|
+
curlCode: string;
|
|
8
|
+
pythonCode: string;
|
|
9
|
+
jsCode: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function SdkCodeTabs({ curlCode, pythonCode, jsCode }: SdkCodeTabsProps) {
|
|
13
|
+
return (
|
|
14
|
+
<Tabs defaultValue="curl" className="w-full">
|
|
15
|
+
<TabsList>
|
|
16
|
+
<TabsTrigger value="curl">cURL</TabsTrigger>
|
|
17
|
+
<TabsTrigger value="python">Python SDK</TabsTrigger>
|
|
18
|
+
<TabsTrigger value="javascript">JavaScript/TypeScript SDK</TabsTrigger>
|
|
19
|
+
</TabsList>
|
|
20
|
+
<TabsContent value="curl">
|
|
21
|
+
<CodePreview code={curlCode} language="bash" />
|
|
22
|
+
</TabsContent>
|
|
23
|
+
<TabsContent value="python">
|
|
24
|
+
<CodePreview code={pythonCode} language="python" />
|
|
25
|
+
</TabsContent>
|
|
26
|
+
<TabsContent value="javascript">
|
|
27
|
+
<CodePreview code={jsCode} language="typescript" />
|
|
28
|
+
</TabsContent>
|
|
29
|
+
</Tabs>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -1,61 +1,302 @@
|
|
|
1
1
|
'use server';
|
|
2
2
|
|
|
3
|
-
import { $
|
|
3
|
+
import { $getTableName } from '@/src/database/$getTableName';
|
|
4
|
+
import { $provideSupabase } from '@/src/database/$provideSupabase';
|
|
4
5
|
import { $provideServer } from '@/src/tools/$provideServer';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
6
|
+
import { isUserAdmin } from '@/src/utils/isUserAdmin';
|
|
7
|
+
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
8
|
+
import { ArrowLeftIcon, BoxIcon, CodeIcon, GlobeIcon, ServerIcon, TerminalIcon } from 'lucide-react';
|
|
7
9
|
import { headers } from 'next/headers';
|
|
10
|
+
import Link from 'next/link';
|
|
11
|
+
import { notFound } from 'next/navigation';
|
|
8
12
|
import spaceTrim from 'spacetrim';
|
|
13
|
+
import { Color } from '../../../../../../../src/utils/color/Color';
|
|
14
|
+
import { withAlpha } from '../../../../../../../src/utils/color/operators/withAlpha';
|
|
9
15
|
import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
|
|
10
16
|
import { CodePreview } from '../../../../../../_common/components/CodePreview/CodePreview';
|
|
17
|
+
import { getAgentLinks } from '../agentLinks';
|
|
18
|
+
import { CopyField } from '../CopyField';
|
|
19
|
+
import { getAgentName, getAgentProfile } from '../_utils';
|
|
11
20
|
import { generateAgentMetadata } from '../generateAgentMetadata';
|
|
21
|
+
import { SdkCodeTabs } from './SdkCodeTabs';
|
|
12
22
|
|
|
13
23
|
export const generateMetadata = generateAgentMetadata;
|
|
14
24
|
|
|
15
|
-
export default async function
|
|
25
|
+
export default async function AgentIntegrationPage({ params }: { params: Promise<{ agentName: string }> }) {
|
|
16
26
|
$sideEffect(headers());
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
const agentName = await getAgentName(params);
|
|
28
|
+
const isAdmin = await isUserAdmin();
|
|
29
|
+
|
|
30
|
+
let agentProfile;
|
|
31
|
+
try {
|
|
32
|
+
agentProfile = await getAgentProfile(agentName);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (
|
|
35
|
+
error instanceof Error &&
|
|
36
|
+
(error.message.includes('Cannot coerce the result to a single JSON object') ||
|
|
37
|
+
error.message.includes('JSON object requested, multiple (or no) results returned'))
|
|
38
|
+
) {
|
|
39
|
+
notFound();
|
|
40
|
+
}
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
19
43
|
|
|
20
|
-
const collection = await $provideAgentCollectionForServer();
|
|
21
|
-
const agentSource = await collection.getAgentSource(agentName);
|
|
22
|
-
const { meta } = parseAgentSource(agentSource);
|
|
23
|
-
const { fullname, color, image, ...restMeta } = meta;
|
|
24
44
|
const { publicUrl } = await $provideServer();
|
|
25
|
-
const
|
|
45
|
+
const baseUrl = `${publicUrl.href}agents/${encodeURIComponent(agentName)}`;
|
|
46
|
+
const agentApiBase = `${publicUrl.href}agents/${encodeURIComponent(agentName)}`;
|
|
47
|
+
const rootUrl = publicUrl.href.replace(/\/$/, '');
|
|
26
48
|
|
|
27
|
-
|
|
28
|
-
|
|
49
|
+
// Get API Key if admin
|
|
50
|
+
let apiKey = 'ptbk_...';
|
|
51
|
+
if (isAdmin) {
|
|
52
|
+
const supabase = $provideSupabase();
|
|
53
|
+
const table = await $getTableName('ApiTokens');
|
|
54
|
+
const { data } = await supabase
|
|
55
|
+
.from(table)
|
|
56
|
+
.select('token')
|
|
57
|
+
.eq('isRevoked', false)
|
|
58
|
+
.order('createdAt', { ascending: false })
|
|
59
|
+
.limit(1);
|
|
60
|
+
|
|
61
|
+
if (data && data.length > 0) {
|
|
62
|
+
apiKey = data[0].token;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
29
65
|
|
|
66
|
+
// Extract brand color from meta
|
|
67
|
+
const brandColor = Color.from(agentProfile.meta.color || PROMPTBOOK_COLOR);
|
|
68
|
+
const backgroundColor = (await brandColor.then(withAlpha(0.05))).toHex();
|
|
69
|
+
const borderColor = (await brandColor.then(withAlpha(0.1))).toHex();
|
|
70
|
+
const primaryColor = (await brandColor).toHex();
|
|
71
|
+
|
|
72
|
+
// Website Integration Code
|
|
73
|
+
const { fullname, color, image, ...restMeta } = agentProfile.meta;
|
|
74
|
+
const websiteIntegrationCode = spaceTrim(
|
|
75
|
+
(block) => `
|
|
30
76
|
import { PromptbookAgent } from '@promptbook/components';
|
|
31
77
|
|
|
32
78
|
export function YourComponent() {
|
|
33
79
|
return(
|
|
34
80
|
<PromptbookAgent
|
|
35
|
-
agentUrl="${
|
|
81
|
+
agentUrl="${baseUrl}"
|
|
36
82
|
meta={${block(JSON.stringify({ fullname, color, image, ...restMeta }, null, 4))}}
|
|
37
83
|
/>
|
|
38
84
|
);
|
|
39
85
|
}
|
|
40
|
-
|
|
41
86
|
`,
|
|
42
87
|
);
|
|
43
88
|
|
|
89
|
+
// OpenAI Compatible Curl
|
|
90
|
+
const curlCode = spaceTrim(`
|
|
91
|
+
curl ${agentApiBase}/api/openai/v1/chat/completions \\
|
|
92
|
+
-H "Content-Type: application/json" \\
|
|
93
|
+
-H "Authorization: Bearer ${apiKey}" \\
|
|
94
|
+
-d '{
|
|
95
|
+
"model": "agent:${agentName}",
|
|
96
|
+
"messages": [
|
|
97
|
+
{"role": "user", "content": "Hello!"}
|
|
98
|
+
]
|
|
99
|
+
}'
|
|
100
|
+
`);
|
|
101
|
+
|
|
102
|
+
// OpenAI Compatible Python
|
|
103
|
+
const pythonCode = spaceTrim(`
|
|
104
|
+
from openai import OpenAI
|
|
105
|
+
|
|
106
|
+
client = OpenAI(
|
|
107
|
+
base_url="${agentApiBase}/api/openai/v1",
|
|
108
|
+
api_key="${apiKey}",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
response = client.chat.completions.create(
|
|
112
|
+
model="agent:${agentName}",
|
|
113
|
+
messages=[
|
|
114
|
+
{"role": "user", "content": "Hello!"}
|
|
115
|
+
]
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
print(response.choices[0].message.content)
|
|
119
|
+
`);
|
|
120
|
+
|
|
121
|
+
// OpenAI Compatible JS
|
|
122
|
+
const jsCode = spaceTrim(`
|
|
123
|
+
import OpenAI from 'openai';
|
|
124
|
+
|
|
125
|
+
const client = new OpenAI({
|
|
126
|
+
baseURL: '${agentApiBase}/api/openai/v1',
|
|
127
|
+
apiKey: '${apiKey}',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
async function main() {
|
|
131
|
+
const response = await client.chat.completions.create({
|
|
132
|
+
model: 'agent:${agentName}',
|
|
133
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
console.log(response.choices[0].message.content);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
main();
|
|
140
|
+
`);
|
|
141
|
+
|
|
142
|
+
// MCP Config
|
|
143
|
+
const mcpConfigCode = spaceTrim(`
|
|
144
|
+
{
|
|
145
|
+
"mcpServers": {
|
|
146
|
+
"${agentName}": {
|
|
147
|
+
"command": "npx",
|
|
148
|
+
"args": [
|
|
149
|
+
"-y",
|
|
150
|
+
"@promptbook/cli",
|
|
151
|
+
"mcp",
|
|
152
|
+
"${baseUrl}"
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
`);
|
|
158
|
+
|
|
159
|
+
const agentLinks = getAgentLinks(agentName);
|
|
160
|
+
const chatLink = agentLinks.find((l) => l.title === 'Chat with Agent')!;
|
|
161
|
+
const websiteIntegrationLink = agentLinks.find((l) => l.title === 'Website Integration')!;
|
|
162
|
+
|
|
44
163
|
return (
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
164
|
+
<div
|
|
165
|
+
className="min-h-screen p-6 md:p-12 flex flex-col items-center"
|
|
166
|
+
style={{
|
|
167
|
+
backgroundColor,
|
|
168
|
+
}}
|
|
169
|
+
>
|
|
170
|
+
<div className="w-full max-w-5xl bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
|
|
171
|
+
{/* Header */}
|
|
172
|
+
<div className="p-6 border-b flex items-center gap-4" style={{ borderColor }}>
|
|
173
|
+
{agentProfile.meta.image && (
|
|
174
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
175
|
+
<img
|
|
176
|
+
src={agentProfile.meta.image as string}
|
|
177
|
+
alt={agentProfile.meta.fullname || agentName}
|
|
178
|
+
className="w-16 h-16 rounded-full object-cover border-2"
|
|
179
|
+
style={{ borderColor: primaryColor }}
|
|
180
|
+
/>
|
|
181
|
+
)}
|
|
182
|
+
<div className="flex-1">
|
|
183
|
+
<h1 className="text-2xl font-bold text-gray-900">{agentProfile.meta.fullname || agentName}</h1>
|
|
184
|
+
<p className="text-gray-500 flex items-center gap-2">
|
|
185
|
+
<CodeIcon className="w-4 h-4" />
|
|
186
|
+
Integration Options
|
|
187
|
+
</p>
|
|
188
|
+
</div>
|
|
189
|
+
<Link
|
|
190
|
+
href={chatLink.href}
|
|
191
|
+
className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full transition-colors"
|
|
192
|
+
title="Back to Agent"
|
|
193
|
+
>
|
|
194
|
+
<ArrowLeftIcon className="w-6 h-6" />
|
|
195
|
+
</Link>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<div className="p-6 space-y-6">
|
|
199
|
+
{/* Website Integration */}
|
|
200
|
+
<div className="p-6 rounded-xl border-2 border-green-200 bg-green-50/30 shadow-sm">
|
|
201
|
+
<div className="flex items-start gap-4 mb-4">
|
|
202
|
+
<div className="p-3 rounded-xl bg-green-100 text-green-600 shadow-sm">
|
|
203
|
+
<GlobeIcon className="w-6 h-6" />
|
|
204
|
+
</div>
|
|
205
|
+
<div>
|
|
206
|
+
<h2 className="text-xl font-bold text-gray-900">Website Integration</h2>
|
|
207
|
+
<p className="text-gray-600">
|
|
208
|
+
Embed the agent chat widget directly into your React application.
|
|
209
|
+
</p>
|
|
210
|
+
<p className="text-sm text-gray-500 mt-1">
|
|
211
|
+
<Link href={websiteIntegrationLink.href} className="text-blue-600 hover:underline">
|
|
212
|
+
View detailed guide →
|
|
213
|
+
</Link>
|
|
214
|
+
</p>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
<CodePreview code={websiteIntegrationCode} language="typescript" />
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
{/* OpenAI API Compatible Endpoint */}
|
|
221
|
+
<div className="p-6 rounded-xl border-2 border-blue-200 bg-blue-50/30 shadow-sm">
|
|
222
|
+
<div className="flex items-start gap-4 mb-4">
|
|
223
|
+
<div className="p-3 rounded-xl bg-blue-100 text-blue-600 shadow-sm">
|
|
224
|
+
<TerminalIcon className="w-6 h-6" />
|
|
225
|
+
</div>
|
|
226
|
+
<div className="flex-1">
|
|
227
|
+
<h2 className="text-xl font-bold text-gray-900">OpenAI Compatible API</h2>
|
|
228
|
+
<p className="text-gray-600">
|
|
229
|
+
Use the agent as a drop-in replacement for OpenAI API in your existing applications.
|
|
230
|
+
</p>
|
|
231
|
+
<div className="grid md:grid-cols-3 gap-4 mt-4 mb-2">
|
|
232
|
+
<CopyField label="Endpoint URL" value={`${agentApiBase}/api/openai/v1`} />
|
|
233
|
+
<CopyField label="Model Name" value={`agent:${agentName}`} />
|
|
234
|
+
{isAdmin ? (
|
|
235
|
+
<CopyField label="API Key" value={apiKey} />
|
|
236
|
+
) : (
|
|
237
|
+
<div className="flex flex-col gap-1">
|
|
238
|
+
<span className="text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
239
|
+
API Key
|
|
240
|
+
</span>
|
|
241
|
+
<div className="text-sm text-gray-500 italic bg-gray-50 p-2 rounded border border-gray-200">
|
|
242
|
+
Contact admin for API Key
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
)}
|
|
246
|
+
</div>
|
|
247
|
+
{isAdmin && apiKey === 'ptbk_...' && (
|
|
248
|
+
<p className="text-sm text-amber-600 mt-2">
|
|
249
|
+
No API token found.{' '}
|
|
250
|
+
<Link href="/admin/api-tokens" className="underline font-medium">
|
|
251
|
+
Create one in settings
|
|
252
|
+
</Link>
|
|
253
|
+
.
|
|
254
|
+
</p>
|
|
255
|
+
)}
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<SdkCodeTabs curlCode={curlCode} pythonCode={pythonCode} jsCode={jsCode} />
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
{/* OpenRouter Integration */}
|
|
263
|
+
<div className="p-6 rounded-xl border-2 border-purple-200 bg-purple-50/30 shadow-sm">
|
|
264
|
+
<div className="flex items-start gap-4 mb-4">
|
|
265
|
+
<div className="p-3 rounded-xl bg-purple-100 text-purple-600 shadow-sm">
|
|
266
|
+
<ServerIcon className="w-6 h-6" />
|
|
267
|
+
</div>
|
|
268
|
+
<div>
|
|
269
|
+
<h2 className="text-xl font-bold text-gray-900">OpenRouter Integration</h2>
|
|
270
|
+
<p className="text-gray-600">Connect via OpenRouter compatible endpoint.</p>
|
|
271
|
+
<div className="grid md:grid-cols-2 gap-4 mt-4">
|
|
272
|
+
<CopyField label="Endpoint URL" value={`${agentApiBase}/api/openrouter`} />
|
|
273
|
+
<CopyField label="Model Name" value={`agent:${agentName}`} />
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
{/* MCP Integration */}
|
|
280
|
+
<div className="p-6 rounded-xl border-2 border-orange-200 bg-orange-50/30 shadow-sm">
|
|
281
|
+
<div className="flex items-start gap-4 mb-4">
|
|
282
|
+
<div className="p-3 rounded-xl bg-orange-100 text-orange-600 shadow-sm">
|
|
283
|
+
<BoxIcon className="w-6 h-6" />
|
|
284
|
+
</div>
|
|
285
|
+
<div>
|
|
286
|
+
<h2 className="text-xl font-bold text-gray-900">MCP Integration</h2>
|
|
287
|
+
<p className="text-gray-600">
|
|
288
|
+
Use Model Context Protocol to connect this agent with compatible tools and IDEs
|
|
289
|
+
(like Claude Desktop, Cursor, etc.).
|
|
290
|
+
</p>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
<CodePreview
|
|
294
|
+
code={mcpConfigCode.replace(rootUrl + '/api', agentApiBase + '/api')}
|
|
295
|
+
language="json"
|
|
296
|
+
/>
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
55
301
|
);
|
|
56
302
|
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* TODO: Make this page better, bring from Promptbook.Studio
|
|
60
|
-
* TODO: [🚗] Components and pages here should be just tiny UI wraper around proper agent logic and conponents
|
|
61
|
-
*/
|