@promptbook/cli 0.104.0-7 → 0.104.0-9
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 +1 -3
- package/apps/agents-server/src/app/AddAgentButton.tsx +45 -19
- package/apps/agents-server/src/app/actions.ts +5 -0
- package/apps/agents-server/src/app/admin/browser-test/BrowserTestClient.tsx +108 -0
- package/apps/agents-server/src/app/admin/browser-test/page.tsx +13 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +49 -10
- package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +2 -4
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +4 -2
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +4 -2
- package/apps/agents-server/src/app/agents/[agentName]/history/page.tsx +10 -3
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +12 -5
- package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +10 -2
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +5 -5
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +5 -5
- package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +8 -2
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +8 -2
- package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +3 -5
- package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +15 -4
- package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +3 -2
- package/apps/agents-server/src/app/api/agents/[agentName]/restore/route.ts +2 -1
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +2 -1
- package/apps/agents-server/src/app/api/browser-test/screenshot/route.ts +30 -0
- package/apps/agents-server/src/app/api/browser-test/scroll-facebook/route.ts +62 -0
- package/apps/agents-server/src/app/humans.txt/route.ts +1 -1
- package/apps/agents-server/src/app/page.tsx +4 -2
- package/apps/agents-server/src/app/recycle-bin/page.tsx +3 -1
- package/apps/agents-server/src/app/robots.txt/route.ts +1 -1
- package/apps/agents-server/src/app/security.txt/route.ts +1 -1
- package/apps/agents-server/src/app/sitemap.xml/route.ts +4 -5
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +25 -20
- package/apps/agents-server/src/components/AgentProfile/AgentProfileImage.tsx +79 -0
- package/apps/agents-server/src/components/Header/Header.tsx +4 -0
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +46 -10
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +32 -14
- package/apps/agents-server/src/components/Homepage/DeletedAgentsList.tsx +22 -6
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSection.tsx +12 -3
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSectionClient.tsx +19 -10
- package/apps/agents-server/src/components/NewAgentDialog/NewAgentDialog.tsx +88 -0
- package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +2 -0
- package/apps/agents-server/src/components/_utils/generateMetaTxt.ts +12 -10
- package/apps/agents-server/src/database/migrations/2025-12-0820-agent-history-permanent-id.sql +29 -0
- package/apps/agents-server/src/database/schema.ts +6 -3
- package/apps/agents-server/src/tools/$provideBrowserForServer.ts +29 -0
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +1 -1
- package/esm/index.es.js +7 -2
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.closed.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +2 -2
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +10 -6
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +6 -3
- package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +7 -2
- package/umd/index.umd.js.map +1 -1
|
@@ -29,9 +29,7 @@ const config = ConfigChecker.from({
|
|
|
29
29
|
*
|
|
30
30
|
* Note: When `SERVERS` are used, this URL will be overridden by the server URL.
|
|
31
31
|
*/
|
|
32
|
-
export const NEXT_PUBLIC_SITE_URL = config
|
|
33
|
-
.get('NEXT_PUBLIC_SITE_URL')
|
|
34
|
-
.url()./* <- TODO: !!!! Is it ok not to be required().*/ value;
|
|
32
|
+
export const NEXT_PUBLIC_SITE_URL = config.get('NEXT_PUBLIC_SITE_URL').url().value;
|
|
35
33
|
|
|
36
34
|
/**
|
|
37
35
|
* [♐️] Vercel environment: "development" | "preview" | "production"
|
|
@@ -1,41 +1,67 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { string_book } from '@promptbook-local/types';
|
|
3
4
|
import { useRouter } from 'next/navigation';
|
|
4
5
|
import { useState } from 'react';
|
|
5
6
|
import { Card } from '../components/Homepage/Card';
|
|
6
|
-
import {
|
|
7
|
+
import { NewAgentDialog } from '../components/NewAgentDialog/NewAgentDialog';
|
|
8
|
+
import { $createAgentFromBookAction, $generateAgentBoilerplateAction } from './actions';
|
|
7
9
|
|
|
8
10
|
export function AddAgentButton() {
|
|
9
11
|
const router = useRouter();
|
|
10
12
|
const [isLoading, setIsLoading] = useState(false);
|
|
13
|
+
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
14
|
+
const [agentSource, setAgentSource] = useState<string_book>('' as string_book);
|
|
11
15
|
|
|
12
16
|
const handleAddAgent = async () => {
|
|
13
17
|
setIsLoading(true);
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
try {
|
|
19
|
+
const boilerplate = await $generateAgentBoilerplateAction();
|
|
20
|
+
setAgentSource(boilerplate);
|
|
21
|
+
setIsDialogOpen(true);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('Failed to generate agent boilerplate', error);
|
|
24
|
+
// TODO: Add proper error handling and UI feedback
|
|
25
|
+
} finally {
|
|
26
|
+
setIsLoading(false);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const handleCreate = async (source: string_book) => {
|
|
31
|
+
// Note: [🧠] Logic for creation is now handled inside the dialog (waiting for promise), here we just handle navigation
|
|
32
|
+
const { permanentId } = await $createAgentFromBookAction(source);
|
|
33
|
+
|
|
16
34
|
if (permanentId) {
|
|
17
35
|
router.push(`/agents/${permanentId}`);
|
|
18
36
|
} else {
|
|
19
37
|
router.refresh();
|
|
20
|
-
setIsLoading(false);
|
|
21
38
|
}
|
|
22
39
|
};
|
|
23
40
|
|
|
24
41
|
return (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
<>
|
|
43
|
+
<div
|
|
44
|
+
onClick={isLoading ? undefined : handleAddAgent}
|
|
45
|
+
className={`cursor-pointer h-full group ${isLoading ? 'pointer-events-none' : ''}`}
|
|
46
|
+
>
|
|
47
|
+
<Card className="flex items-center justify-center text-lg font-medium text-gray-500 group-hover:text-blue-500 group-hover:border-blue-400 border-dashed border-2">
|
|
48
|
+
{isLoading ? (
|
|
49
|
+
<>
|
|
50
|
+
<span className="mr-2 inline-block h-4 w-4 animate-spin rounded-full border-2 border-blue-500 border-t-transparent" />
|
|
51
|
+
Preparing...
|
|
52
|
+
</>
|
|
53
|
+
) : (
|
|
54
|
+
'+ Add New Agent'
|
|
55
|
+
)}
|
|
56
|
+
</Card>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<NewAgentDialog
|
|
60
|
+
isOpen={isDialogOpen}
|
|
61
|
+
onClose={() => setIsDialogOpen(false)}
|
|
62
|
+
initialAgentSource={agentSource}
|
|
63
|
+
onCreate={handleCreate}
|
|
64
|
+
/>
|
|
65
|
+
</>
|
|
40
66
|
);
|
|
41
67
|
}
|
|
@@ -25,6 +25,11 @@ export async function $createAgentAction(): Promise<{ agentName: string_agent_na
|
|
|
25
25
|
return { agentName, permanentId };
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
export async function $generateAgentBoilerplateAction(): Promise<string_book> {
|
|
29
|
+
const namePool = (await getMetadata('NAME_POOL')) || 'ENGLISH';
|
|
30
|
+
return $generateBookBoilerplate({ namePool });
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
export async function $createAgentFromBookAction(bookContent: string_book): Promise<{ agentName: string_agent_name; permanentId: string_agent_permanent_id }> {
|
|
29
34
|
// TODO: [👹] Check permissions here
|
|
30
35
|
if (!(await isUserAdmin())) {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { Card } from '../../../components/Homepage/Card';
|
|
5
|
+
|
|
6
|
+
export function BrowserTestClient() {
|
|
7
|
+
const [imageUrl, setImageUrl] = useState<string | null>(null);
|
|
8
|
+
const [facebookStreamUrl, setFacebookStreamUrl] = useState<string | null>(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
return () => {
|
|
12
|
+
if (imageUrl) {
|
|
13
|
+
URL.revokeObjectURL(imageUrl);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}, [imageUrl]);
|
|
17
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
18
|
+
const [error, setError] = useState<string | null>(null);
|
|
19
|
+
|
|
20
|
+
const handleTakeScreenshot = async () => {
|
|
21
|
+
setFacebookStreamUrl(null);
|
|
22
|
+
setIsLoading(true);
|
|
23
|
+
setError(null);
|
|
24
|
+
try {
|
|
25
|
+
const response = await fetch('/api/browser-test/screenshot');
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
const text = await response.text();
|
|
28
|
+
let errorMessage;
|
|
29
|
+
try {
|
|
30
|
+
const json = JSON.parse(text);
|
|
31
|
+
errorMessage = json.error || response.statusText;
|
|
32
|
+
} catch {
|
|
33
|
+
errorMessage = text || response.statusText;
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`Error: ${response.status} ${errorMessage}`);
|
|
36
|
+
}
|
|
37
|
+
const blob = await response.blob();
|
|
38
|
+
const url = URL.createObjectURL(blob);
|
|
39
|
+
setImageUrl(url);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
setError(String(err));
|
|
42
|
+
} finally {
|
|
43
|
+
setIsLoading(false);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleScrollFacebook = () => {
|
|
48
|
+
setImageUrl(null);
|
|
49
|
+
setError(null);
|
|
50
|
+
setFacebookStreamUrl(`/api/browser-test/scroll-facebook?t=${Date.now()}`);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div className="container mx-auto px-4 py-8 space-y-6">
|
|
55
|
+
<div className="mt-20 mb-4 flex flex-col gap-2 md:flex-row md:items-end md:justify-between">
|
|
56
|
+
<div>
|
|
57
|
+
<h1 className="text-3xl text-gray-900 font-light">Browser Test</h1>
|
|
58
|
+
<p className="mt-1 text-sm text-gray-500">
|
|
59
|
+
Launch a browser instance and take a screenshot to verify functionality.
|
|
60
|
+
</p>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<Card>
|
|
65
|
+
<div className="mb-4">
|
|
66
|
+
<p className="mb-2">Click the button below to launch a browser instance (if not running), navigate to ptbk.io, and take a screenshot.</p>
|
|
67
|
+
<button
|
|
68
|
+
onClick={handleTakeScreenshot}
|
|
69
|
+
disabled={isLoading}
|
|
70
|
+
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded disabled:opacity-50"
|
|
71
|
+
>
|
|
72
|
+
{isLoading ? 'Taking Screenshot...' : 'Take Screenshot'}
|
|
73
|
+
</button>
|
|
74
|
+
<button
|
|
75
|
+
onClick={handleScrollFacebook}
|
|
76
|
+
disabled={isLoading}
|
|
77
|
+
className="ml-2 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded disabled:opacity-50"
|
|
78
|
+
>
|
|
79
|
+
Scroll Facebook
|
|
80
|
+
</button>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{error && (
|
|
84
|
+
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4" role="alert">
|
|
85
|
+
<strong className="font-bold">Error: </strong>
|
|
86
|
+
<span className="block sm:inline">{error}</span>
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
|
|
90
|
+
{imageUrl && (
|
|
91
|
+
<div className="border rounded shadow-lg overflow-hidden">
|
|
92
|
+
<h2 className="text-xl font-semibold p-2 bg-gray-100">Screenshot</h2>
|
|
93
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
94
|
+
<img src={imageUrl} alt="Screenshot of ptbk.io" className="w-full h-auto" />
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
|
|
98
|
+
{facebookStreamUrl && (
|
|
99
|
+
<div className="border rounded shadow-lg overflow-hidden">
|
|
100
|
+
<h2 className="text-xl font-semibold p-2 bg-gray-100">Facebook Scroll Stream</h2>
|
|
101
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
102
|
+
<img src={facebookStreamUrl} alt="Live stream of Facebook scrolling" className="w-full h-auto" />
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
105
|
+
</Card>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ForbiddenPage } from '../../../components/ForbiddenPage/ForbiddenPage';
|
|
2
|
+
import { isUserAdmin } from '../../../utils/isUserAdmin';
|
|
3
|
+
import { BrowserTestClient } from './BrowserTestClient';
|
|
4
|
+
|
|
5
|
+
export default async function BrowserTestPage() {
|
|
6
|
+
const isAdmin = await isUserAdmin();
|
|
7
|
+
|
|
8
|
+
if (!isAdmin) {
|
|
9
|
+
return <ForbiddenPage />;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return <BrowserTestClient />;
|
|
13
|
+
}
|
|
@@ -5,19 +5,57 @@ import { AgentProfile } from '../../../components/AgentProfile/AgentProfile';
|
|
|
5
5
|
import { AgentOptionsMenu } from './AgentOptionsMenu';
|
|
6
6
|
|
|
7
7
|
type AgentProfileWrapperProps = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
/***
|
|
9
|
+
* @@@
|
|
10
|
+
*/
|
|
11
|
+
readonly agent: AgentBasicInformation;
|
|
12
|
+
|
|
13
|
+
/***
|
|
14
|
+
* @@@
|
|
15
|
+
*/
|
|
16
|
+
readonly agentUrl: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Base URL of the agents server
|
|
20
|
+
*/
|
|
21
|
+
readonly publicUrl: URL;
|
|
22
|
+
|
|
23
|
+
/***
|
|
24
|
+
* @@@
|
|
25
|
+
*/
|
|
26
|
+
readonly agentEmail: string;
|
|
27
|
+
|
|
28
|
+
/***
|
|
29
|
+
* @@@
|
|
30
|
+
*/
|
|
31
|
+
readonly agentName: string_agent_name;
|
|
32
|
+
|
|
33
|
+
/***
|
|
34
|
+
* @@@
|
|
35
|
+
*/
|
|
36
|
+
readonly brandColorHex: string;
|
|
37
|
+
|
|
38
|
+
/***
|
|
39
|
+
* @@@
|
|
40
|
+
*/
|
|
41
|
+
readonly isAdmin: boolean;
|
|
42
|
+
|
|
43
|
+
/***
|
|
44
|
+
* @@@
|
|
45
|
+
*/
|
|
46
|
+
readonly isHeadless: boolean;
|
|
47
|
+
|
|
48
|
+
readonly actions: React.ReactNode;
|
|
49
|
+
|
|
50
|
+
/***
|
|
51
|
+
* @@@
|
|
52
|
+
*/
|
|
53
|
+
readonly children: React.ReactNode;
|
|
17
54
|
};
|
|
18
55
|
|
|
19
56
|
export function AgentProfileWrapper(props: AgentProfileWrapperProps) {
|
|
20
|
-
const { agent, agentUrl, agentEmail, agentName, brandColorHex, isAdmin, isHeadless, actions, children } =
|
|
57
|
+
const { agent, agentUrl, publicUrl, agentEmail, agentName, brandColorHex, isAdmin, isHeadless, actions, children } =
|
|
58
|
+
props;
|
|
21
59
|
|
|
22
60
|
// Derived agentName from agent data
|
|
23
61
|
const derivedAgentName = agent.agentName;
|
|
@@ -27,6 +65,7 @@ export function AgentProfileWrapper(props: AgentProfileWrapperProps) {
|
|
|
27
65
|
<AgentProfile
|
|
28
66
|
agent={agent}
|
|
29
67
|
agentUrl={agentUrl}
|
|
68
|
+
publicUrl={publicUrl}
|
|
30
69
|
permanentId={permanentId || agentName}
|
|
31
70
|
agentEmail={agentEmail}
|
|
32
71
|
isHeadless={isHeadless}
|
|
@@ -12,11 +12,9 @@ export async function getAgentName(params: Promise<{ agentName: string }>) {
|
|
|
12
12
|
|
|
13
13
|
export async function getAgentProfile(agentName: string) {
|
|
14
14
|
const collection = await $provideAgentCollectionForServer();
|
|
15
|
-
const
|
|
15
|
+
const agentId = await collection.getAgentPermanentId(agentName);
|
|
16
|
+
const agentSource = await collection.getAgentSource(agentId);
|
|
16
17
|
const agentProfile = parseAgentSource(agentSource);
|
|
17
|
-
|
|
18
|
-
console.log('!!!!', { agentSource, agentProfile });
|
|
19
|
-
|
|
20
18
|
return agentProfile;
|
|
21
19
|
}
|
|
22
20
|
|
|
@@ -13,7 +13,8 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
13
13
|
|
|
14
14
|
try {
|
|
15
15
|
const collection = await $provideAgentCollectionForServer();
|
|
16
|
-
const
|
|
16
|
+
const agentId = await collection.getAgentPermanentId(agentName);
|
|
17
|
+
const agentSource = await collection.getAgentSource(agentId);
|
|
17
18
|
const effectiveAgentSource = await resolveInheritedAgentSource(agentSource, collection);
|
|
18
19
|
|
|
19
20
|
return new Response(effectiveAgentSource, {
|
|
@@ -52,7 +53,8 @@ export async function PUT(request: Request, { params }: { params: Promise<{ agen
|
|
|
52
53
|
let agentSource = validateBook(agentSourceUnchecked);
|
|
53
54
|
agentSource = padBook(agentSource);
|
|
54
55
|
|
|
55
|
-
await collection.
|
|
56
|
+
const agentId = await collection.getAgentPermanentId(agentName);
|
|
57
|
+
await collection.updateAgentSource(agentId, agentSource);
|
|
56
58
|
// <- TODO: [🐱🚀] Properly type as string_book
|
|
57
59
|
|
|
58
60
|
return new Response(
|
|
@@ -121,8 +121,10 @@ export default function AgentCodePage({ params }: { params: Promise<{ agentName:
|
|
|
121
121
|
<img
|
|
122
122
|
src={
|
|
123
123
|
agentProfile.meta.image ||
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
generatePlaceholderAgentProfileImageUrl(
|
|
125
|
+
agentProfile.permanentId || agentName,
|
|
126
|
+
NEXT_PUBLIC_SITE_URL, // <- TODO: !!!! Use here `const { publicUrl } = await $provideServer();`
|
|
127
|
+
)
|
|
126
128
|
}
|
|
127
129
|
alt={agentProfile.meta.fullname || agentName}
|
|
128
130
|
className="w-16 h-16 rounded-full object-cover border-2 border-gray-200"
|
|
@@ -10,7 +10,8 @@ export const metadata = {
|
|
|
10
10
|
export default async function AgentHistoryPage({ params }: { params: Promise<{ agentName: string }> }) {
|
|
11
11
|
const { agentName } = await params;
|
|
12
12
|
const collection = await $provideAgentCollectionForServer();
|
|
13
|
-
const
|
|
13
|
+
const agentId = await collection.getAgentPermanentId(agentName);
|
|
14
|
+
const history = await collection.listAgentHistory(agentId);
|
|
14
15
|
|
|
15
16
|
return (
|
|
16
17
|
<div className="container mx-auto p-6 max-w-4xl">
|
|
@@ -21,7 +22,10 @@ export default async function AgentHistoryPage({ params }: { params: Promise<{ a
|
|
|
21
22
|
<div>
|
|
22
23
|
<h1 className="text-3xl font-bold text-gray-900">History: {agentName}</h1>
|
|
23
24
|
<p className="text-gray-600">
|
|
24
|
-
Previous versions of this agent.
|
|
25
|
+
Previous versions of this agent.{' '}
|
|
26
|
+
<Link href={`/agents/${agentName}`} className="text-blue-600 hover:underline">
|
|
27
|
+
Back to agent
|
|
28
|
+
</Link>
|
|
25
29
|
</p>
|
|
26
30
|
</div>
|
|
27
31
|
</header>
|
|
@@ -47,7 +51,10 @@ export default async function AgentHistoryPage({ params }: { params: Promise<{ a
|
|
|
47
51
|
Version {history.length - index}
|
|
48
52
|
</h3>
|
|
49
53
|
<p className="text-sm text-gray-500">
|
|
50
|
-
Hash:
|
|
54
|
+
Hash:{' '}
|
|
55
|
+
<code className="bg-gray-100 px-1 rounded">
|
|
56
|
+
{item.agentHash.substring(0, 8)}
|
|
57
|
+
</code>
|
|
51
58
|
</p>
|
|
52
59
|
</div>
|
|
53
60
|
<RestoreVersionButton agentName={agentName} historyId={item.id} />
|
|
@@ -27,9 +27,13 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|
|
27
27
|
try {
|
|
28
28
|
agentSource = await collection.getAgentSource(agentName);
|
|
29
29
|
} catch (error) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return NextResponse.
|
|
30
|
+
assertsError(error);
|
|
31
|
+
|
|
32
|
+
return NextResponse.json({ error: serializeError(error) }, { status: 500 });
|
|
33
|
+
|
|
34
|
+
//> // If agent not found, redirect to pravatar with the agent name as unique identifier
|
|
35
|
+
//> const pravaratUrl = `https://i.pravatar.cc/1024?u=${encodeURIComponent(agentName)}`;
|
|
36
|
+
//> return NextResponse.redirect(pravaratUrl);
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
const agentProfile = parseAgentSource(agentSource);
|
|
@@ -58,7 +62,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|
|
58
62
|
// Image exists, fetch from CDN and return directly
|
|
59
63
|
const imageResponse = await fetch(existingImage.cdnUrl as string_url);
|
|
60
64
|
if (!imageResponse.ok) {
|
|
61
|
-
|
|
65
|
+
console.warn(`Failed to fetch image from CDN: ${imageResponse.status}`);
|
|
66
|
+
return NextResponse.redirect(existingImage.cdnUrl);
|
|
62
67
|
}
|
|
63
68
|
const imageBuffer = await imageResponse.arrayBuffer();
|
|
64
69
|
return new NextResponse(imageBuffer, {
|
|
@@ -88,6 +93,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|
|
88
93
|
modelVariant: 'IMAGE_GENERATION',
|
|
89
94
|
modelName: 'dall-e-3',
|
|
90
95
|
size: '1024x1792', // <- Vertical orientation
|
|
96
|
+
// <- TODO: [🤐] DRY
|
|
91
97
|
quality: 'hd',
|
|
92
98
|
style: 'natural',
|
|
93
99
|
},
|
|
@@ -133,7 +139,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|
|
133
139
|
// Return the newly created image directly
|
|
134
140
|
const finalImageResponse = await fetch(cdnUrl.href);
|
|
135
141
|
if (!finalImageResponse.ok) {
|
|
136
|
-
|
|
142
|
+
console.warn(`Failed to fetch newly created image from CDN: ${finalImageResponse.status}`);
|
|
143
|
+
return NextResponse.redirect(cdnUrl.href);
|
|
137
144
|
}
|
|
138
145
|
const finalImageBuffer = await finalImageResponse.arrayBuffer();
|
|
139
146
|
return new NextResponse(finalImageBuffer, {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { $provideServer } from '@/src/tools/$provideServer';
|
|
1
2
|
import { generatePlaceholderAgentProfileImageUrl, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
2
3
|
import { serializeError } from '@promptbook-local/utils';
|
|
3
4
|
import { ImageResponse } from 'next/og';
|
|
@@ -5,7 +6,6 @@ import { assertsError } from '../../../../../../../../src/errors/assertsError';
|
|
|
5
6
|
import { Color } from '../../../../../../../../src/utils/color/Color';
|
|
6
7
|
import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
|
|
7
8
|
import { getAgentName, getAgentProfile } from '../../_utils';
|
|
8
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
9
9
|
|
|
10
10
|
const size = {
|
|
11
11
|
width: 256,
|
|
@@ -19,6 +19,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
19
19
|
const agentName = await getAgentName(params);
|
|
20
20
|
const agentProfile = await getAgentProfile(agentName);
|
|
21
21
|
const agentColor = Color.from(agentProfile.meta.color || PROMPTBOOK_COLOR);
|
|
22
|
+
const { publicUrl } = await $provideServer();
|
|
22
23
|
|
|
23
24
|
return new ImageResponse(
|
|
24
25
|
(
|
|
@@ -31,6 +32,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
31
32
|
alignItems: 'center',
|
|
32
33
|
justifyContent: 'center',
|
|
33
34
|
borderRadius: '50%',
|
|
35
|
+
aspectRatio: '1 / 1',
|
|
34
36
|
overflow: 'hidden',
|
|
35
37
|
}}
|
|
36
38
|
>
|
|
@@ -47,7 +49,13 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
47
49
|
{/* Note: `next/image` is not working propperly with `next/og` */}
|
|
48
50
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
49
51
|
<img
|
|
50
|
-
src={
|
|
52
|
+
src={
|
|
53
|
+
agentProfile.meta.image ||
|
|
54
|
+
generatePlaceholderAgentProfileImageUrl(
|
|
55
|
+
agentProfile.permanentId || agentName,
|
|
56
|
+
publicUrl,
|
|
57
|
+
)
|
|
58
|
+
}
|
|
51
59
|
alt="Agent Icon"
|
|
52
60
|
/>
|
|
53
61
|
</div>
|
package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $provideServer } from '@/src/tools/$provideServer';
|
|
2
|
+
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
2
3
|
import { serializeError } from '@promptbook-local/utils';
|
|
3
4
|
import { ImageResponse } from 'next/og';
|
|
4
5
|
import { assertsError } from '../../../../../../../../src/errors/assertsError';
|
|
@@ -7,7 +8,6 @@ import { textColor } from '../../../../../../../../src/utils/color/operators/fur
|
|
|
7
8
|
import { grayscale } from '../../../../../../../../src/utils/color/operators/grayscale';
|
|
8
9
|
import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
|
|
9
10
|
import { getAgentName, getAgentProfile } from '../../_utils';
|
|
10
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
11
11
|
|
|
12
12
|
const size = {
|
|
13
13
|
width: 1920,
|
|
@@ -22,6 +22,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
22
22
|
const agentProfile = await getAgentProfile(agentName);
|
|
23
23
|
const agentColor = Color.from(agentProfile.meta.color || PROMPTBOOK_COLOR);
|
|
24
24
|
const backgroundColor = agentColor.then(grayscale(0.5));
|
|
25
|
+
const { publicUrl } = await $provideServer();
|
|
25
26
|
|
|
26
27
|
return new ImageResponse(
|
|
27
28
|
(
|
|
@@ -49,10 +50,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
49
50
|
<img
|
|
50
51
|
style={{
|
|
51
52
|
width: '80%',
|
|
52
|
-
backgroundColor: agentColor.toHex(),
|
|
53
|
-
borderRadius: '50%',
|
|
53
|
+
// backgroundColor: agentColor.toHex(),
|
|
54
54
|
}}
|
|
55
|
-
src={
|
|
55
|
+
src={`${publicUrl.href}agents/${agentProfile.permanentId || agentName}/images/icon-256.png`}
|
|
56
56
|
alt="Agent Icon"
|
|
57
57
|
/>
|
|
58
58
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $provideServer } from '@/src/tools/$provideServer';
|
|
2
|
+
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
2
3
|
import { serializeError } from '@promptbook-local/utils';
|
|
3
4
|
import { ImageResponse } from 'next/og';
|
|
4
5
|
import { assertsError } from '../../../../../../../../src/errors/assertsError';
|
|
@@ -7,7 +8,6 @@ import { textColor } from '../../../../../../../../src/utils/color/operators/fur
|
|
|
7
8
|
import { grayscale } from '../../../../../../../../src/utils/color/operators/grayscale';
|
|
8
9
|
import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
|
|
9
10
|
import { getAgentName, getAgentProfile } from '../../_utils';
|
|
10
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
11
11
|
|
|
12
12
|
const size = {
|
|
13
13
|
width: 1080,
|
|
@@ -22,6 +22,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
22
22
|
const agentProfile = await getAgentProfile(agentName);
|
|
23
23
|
const agentColor = Color.from(agentProfile.meta.color || PROMPTBOOK_COLOR);
|
|
24
24
|
const backgroundColor = agentColor.then(grayscale(0.5));
|
|
25
|
+
const { publicUrl } = await $provideServer();
|
|
25
26
|
|
|
26
27
|
return new ImageResponse(
|
|
27
28
|
(
|
|
@@ -49,10 +50,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
49
50
|
<img
|
|
50
51
|
style={{
|
|
51
52
|
width: '80%',
|
|
52
|
-
backgroundColor: agentColor.toHex(),
|
|
53
|
-
borderRadius: '50%',
|
|
53
|
+
// backgroundColor: agentColor.toHex(),
|
|
54
54
|
}}
|
|
55
|
-
src={
|
|
55
|
+
src={`${publicUrl.href}agents/${agentProfile.permanentId || agentName}/images/icon-256.png`}
|
|
56
56
|
alt="Agent Icon"
|
|
57
57
|
/>
|
|
58
58
|
</div>
|
|
@@ -20,12 +20,12 @@ import { CopyField } from '../CopyField';
|
|
|
20
20
|
import { generateAgentMetadata } from '../generateAgentMetadata';
|
|
21
21
|
import { SdkCodeTabs } from './SdkCodeTabs';
|
|
22
22
|
import { WebsiteIntegrationTabs } from './WebsiteIntegrationTabs';
|
|
23
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
24
23
|
|
|
25
24
|
export const generateMetadata = generateAgentMetadata;
|
|
26
25
|
|
|
27
26
|
export default async function AgentIntegrationPage({ params }: { params: Promise<{ agentName: string }> }) {
|
|
28
27
|
$sideEffect(headers());
|
|
28
|
+
|
|
29
29
|
const agentName = await getAgentName(params);
|
|
30
30
|
const isAdmin = await isUserAdmin();
|
|
31
31
|
|
|
@@ -188,7 +188,13 @@ export default async function AgentIntegrationPage({ params }: { params: Promise
|
|
|
188
188
|
{agentProfile.meta.image && (
|
|
189
189
|
// eslint-disable-next-line @next/next/no-img-element
|
|
190
190
|
<img
|
|
191
|
-
src={
|
|
191
|
+
src={
|
|
192
|
+
agentProfile.meta.image ||
|
|
193
|
+
generatePlaceholderAgentProfileImageUrl(
|
|
194
|
+
agentProfile.permanentId || agentName,
|
|
195
|
+
publicUrl,
|
|
196
|
+
)
|
|
197
|
+
}
|
|
192
198
|
alt={agentProfile.meta.fullname || agentName}
|
|
193
199
|
className="w-16 h-16 rounded-full object-cover border-2"
|
|
194
200
|
style={{ borderColor: primaryColor }}
|
|
@@ -13,12 +13,12 @@ import { getAgentName, getAgentProfile } from '../_utils';
|
|
|
13
13
|
import { getAgentExternalLinks, getAgentLinks } from '../agentLinks';
|
|
14
14
|
import { CopyField } from '../CopyField';
|
|
15
15
|
import { generateAgentMetadata } from '../generateAgentMetadata';
|
|
16
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
17
16
|
|
|
18
17
|
export const generateMetadata = generateAgentMetadata;
|
|
19
18
|
|
|
20
19
|
export default async function AgentLinksPage({ params }: { params: Promise<{ agentName: string }> }) {
|
|
21
20
|
$sideEffect(headers());
|
|
21
|
+
|
|
22
22
|
const agentName = await getAgentName(params);
|
|
23
23
|
|
|
24
24
|
let agentProfile;
|
|
@@ -57,7 +57,13 @@ export default async function AgentLinksPage({ params }: { params: Promise<{ age
|
|
|
57
57
|
{agentProfile.meta.image && (
|
|
58
58
|
// eslint-disable-next-line @next/next/no-img-element
|
|
59
59
|
<img
|
|
60
|
-
src={
|
|
60
|
+
src={
|
|
61
|
+
agentProfile.meta.image ||
|
|
62
|
+
generatePlaceholderAgentProfileImageUrl(
|
|
63
|
+
agentProfile.permanentId || agentName,
|
|
64
|
+
publicUrl,
|
|
65
|
+
)
|
|
66
|
+
}
|
|
61
67
|
alt={agentProfile.meta.fullname || agentName}
|
|
62
68
|
className="w-16 h-16 rounded-full object-cover border-2"
|
|
63
69
|
style={{ borderColor: primaryColor }}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $provideServer } from '@/src/tools/$provideServer';
|
|
2
2
|
import { generatePlaceholderAgentProfileImageUrl, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
3
3
|
import { serializeError } from '@promptbook-local/utils';
|
|
4
4
|
import { ImageResponse } from 'next/og';
|
|
@@ -25,6 +25,7 @@ export default async function Image({ params }: { params: Promise<{ agentName: s
|
|
|
25
25
|
const agentProfile = await getAgentProfile(agentName);
|
|
26
26
|
const agentColor = Color.from(agentProfile.meta.color || PROMPTBOOK_COLOR);
|
|
27
27
|
const backgroundColor = agentColor.then(grayscale(0.5));
|
|
28
|
+
const { publicUrl } = await $provideServer();
|
|
28
29
|
|
|
29
30
|
return new ImageResponse(
|
|
30
31
|
(
|
|
@@ -54,13 +55,13 @@ export default async function Image({ params }: { params: Promise<{ agentName: s
|
|
|
54
55
|
width: '80%',
|
|
55
56
|
backgroundColor: agentColor.toHex(),
|
|
56
57
|
borderRadius: '50%',
|
|
58
|
+
aspectRatio: '1 / 1',
|
|
57
59
|
}}
|
|
58
60
|
src={
|
|
59
61
|
agentProfile.meta.image ||
|
|
60
|
-
agentProfile.permanentId ||
|
|
61
62
|
generatePlaceholderAgentProfileImageUrl(
|
|
62
63
|
agentProfile.permanentId || agentName,
|
|
63
|
-
|
|
64
|
+
publicUrl,
|
|
64
65
|
)
|
|
65
66
|
}
|
|
66
67
|
alt="Agent Icon"
|