@promptbook/cli 0.104.0-7 โ 0.104.0-8
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/admin/browser-test/BrowserTestClient.tsx +85 -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 +0 -3
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +4 -2
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +5 -2
- 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/browser-test/screenshot/route.ts +30 -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 +22 -14
- 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/VercelDeploymentCard/VercelDeploymentCard.tsx +2 -0
- package/apps/agents-server/src/components/_utils/generateMetaTxt.ts +12 -10
- 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 +1 -1
- package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +2 -2
- 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 +1 -1
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
// Dynamic sitemap.xml for Agents Server
|
|
2
2
|
|
|
3
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
4
3
|
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
4
|
+
import { $provideServer } from '@/src/tools/$provideServer';
|
|
5
5
|
import { spaceTrim } from '@promptbook-local/utils';
|
|
6
6
|
import { NextResponse } from 'next/server';
|
|
7
7
|
|
|
8
8
|
export const dynamic = 'force-dynamic';
|
|
9
9
|
|
|
10
10
|
export async function GET() {
|
|
11
|
+
const { publicUrl } = await $provideServer();
|
|
12
|
+
|
|
11
13
|
const collection = await $provideAgentCollectionForServer();
|
|
12
14
|
|
|
13
15
|
// Assume collection.listAgents() returns an array of agent names
|
|
14
16
|
const agents = await collection.listAgents();
|
|
15
17
|
|
|
16
|
-
// Get base URL from environment or config
|
|
17
|
-
const baseUrl = NEXT_PUBLIC_SITE_URL?.href || process.env.PUBLIC_URL || 'https://ptbk.io';
|
|
18
|
-
|
|
19
18
|
const urls = agents
|
|
20
19
|
.map(
|
|
21
20
|
({ permanentId, agentName }) =>
|
|
22
|
-
`<url><loc>${
|
|
21
|
+
`<url><loc>${publicUrl.href}agents/${encodeURIComponent(permanentId || agentName)}</loc></url>`,
|
|
23
22
|
)
|
|
24
23
|
.join('\n');
|
|
25
24
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { colorToDataUrl } from '@promptbook-local/color';
|
|
3
4
|
import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
|
|
4
5
|
import { AgentBasicInformation, string_agent_permanent_id } from '@promptbook-local/types';
|
|
5
6
|
import { RepeatIcon } from 'lucide-react';
|
|
@@ -7,7 +8,6 @@ import { useState } from 'react';
|
|
|
7
8
|
import { AgentQrCode } from './AgentQrCode';
|
|
8
9
|
import { QrCodeModal } from './QrCodeModal';
|
|
9
10
|
import { useAgentBackground } from './useAgentBackground';
|
|
10
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
11
11
|
|
|
12
12
|
type AgentProfileProps = {
|
|
13
13
|
/**
|
|
@@ -27,6 +27,11 @@ type AgentProfileProps = {
|
|
|
27
27
|
*/
|
|
28
28
|
readonly agentUrl?: string;
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Base URL of the agents server
|
|
32
|
+
*/
|
|
33
|
+
readonly publicUrl: URL;
|
|
34
|
+
|
|
30
35
|
/**
|
|
31
36
|
* Email of the agent
|
|
32
37
|
*/
|
|
@@ -65,6 +70,7 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
65
70
|
agent,
|
|
66
71
|
agentUrl = '',
|
|
67
72
|
agentEmail = '',
|
|
73
|
+
publicUrl,
|
|
68
74
|
permanentId,
|
|
69
75
|
renderMenu,
|
|
70
76
|
children,
|
|
@@ -72,11 +78,11 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
72
78
|
isHeadless = false,
|
|
73
79
|
className,
|
|
74
80
|
} = props;
|
|
75
|
-
|
|
81
|
+
|
|
76
82
|
const { meta, agentName } = agent;
|
|
77
83
|
const fullname = (meta.fullname as string) || agentName || 'Agent';
|
|
78
84
|
const personaDescription = agent.personaDescription || '';
|
|
79
|
-
const imageUrl = meta.image || generatePlaceholderAgentProfileImageUrl(permanentId,
|
|
85
|
+
const imageUrl = meta.image || generatePlaceholderAgentProfileImageUrl(permanentId, publicUrl);
|
|
80
86
|
|
|
81
87
|
const [isQrModalOpen, setIsQrModalOpen] = useState(false);
|
|
82
88
|
const [isFlipped, setIsFlipped] = useState(false);
|
|
@@ -154,17 +160,19 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
154
160
|
// ['cornerShape' as really_any /* <- Note: `cornerShape` is non standard CSS property */]: 'squircle ',
|
|
155
161
|
}}
|
|
156
162
|
>
|
|
157
|
-
{
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
164
|
+
<img
|
|
165
|
+
src={imageUrl}
|
|
166
|
+
alt={fullname}
|
|
167
|
+
className="w-full h-full object-cover"
|
|
168
|
+
// width={1024}
|
|
169
|
+
// height={1792}
|
|
170
|
+
// <- TODO: [๐ค] DRY
|
|
171
|
+
style={{
|
|
172
|
+
objectFit: 'cover',
|
|
173
|
+
backgroundImage: `url(${colorToDataUrl(brandColorLightHex)})`,
|
|
174
|
+
}}
|
|
175
|
+
/>
|
|
168
176
|
|
|
169
177
|
{/* Flip hint icon */}
|
|
170
178
|
<div className="absolute bottom-2 md:bottom-4 right-2 md:right-4 bg-black/30 p-1 md:p-2 rounded-full text-white/80 backdrop-blur-md opacity-0 group-hover:opacity-100 transition-opacity">
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
4
3
|
import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
|
|
5
4
|
import { really_any } from '@promptbook-local/types';
|
|
6
5
|
import { EyeIcon, EyeOffIcon, RotateCcwIcon } from 'lucide-react';
|
|
@@ -9,14 +8,50 @@ import { AgentBasicInformation } from '../../../../../src/book-2.0/agent-source/
|
|
|
9
8
|
import { useAgentBackground } from '../AgentProfile/useAgentBackground';
|
|
10
9
|
|
|
11
10
|
type AgentCardProps = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
/**
|
|
12
|
+
* @@@
|
|
13
|
+
*/
|
|
14
|
+
readonly agent: AgentBasicInformation;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @@@
|
|
18
|
+
*/
|
|
19
|
+
readonly href: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Base URL of the agents server
|
|
23
|
+
*/
|
|
24
|
+
readonly publicUrl: URL;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @@@
|
|
28
|
+
*/
|
|
29
|
+
readonly isAdmin?: boolean;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @@@
|
|
33
|
+
*/
|
|
34
|
+
readonly onDelete?: (agentIdentifier: string) => void;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @@@
|
|
38
|
+
*/
|
|
39
|
+
readonly onClone?: (agentIdentifier: string) => void;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @@@
|
|
43
|
+
*/
|
|
44
|
+
readonly onToggleVisibility?: (agentIdentifier: string) => void;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @@@
|
|
48
|
+
*/
|
|
49
|
+
readonly onRestore?: (agentIdentifier: string) => void;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @@@
|
|
53
|
+
*/
|
|
54
|
+
readonly visibility?: 'PUBLIC' | 'PRIVATE';
|
|
20
55
|
};
|
|
21
56
|
|
|
22
57
|
const ACTION_BUTTON_CLASSES =
|
|
@@ -26,6 +61,7 @@ export function AgentCard({
|
|
|
26
61
|
agent,
|
|
27
62
|
href,
|
|
28
63
|
isAdmin,
|
|
64
|
+
publicUrl,
|
|
29
65
|
onDelete,
|
|
30
66
|
onClone,
|
|
31
67
|
onToggleVisibility,
|
|
@@ -34,7 +70,7 @@ export function AgentCard({
|
|
|
34
70
|
}: AgentCardProps) {
|
|
35
71
|
const { meta, agentName } = agent;
|
|
36
72
|
const fullname = (meta.fullname as string) || agentName || 'Agent';
|
|
37
|
-
const imageUrl = meta.image || generatePlaceholderAgentProfileImageUrl(agentName,
|
|
73
|
+
const imageUrl = meta.image || generatePlaceholderAgentProfileImageUrl(agentName, publicUrl);
|
|
38
74
|
const personaDescription = agent.personaDescription || '';
|
|
39
75
|
|
|
40
76
|
const { brandColorLightHex, brandColorDarkHex, backgroundImage } = useAgentBackground(meta.color);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Client Component for rendering and deleting agents
|
|
2
2
|
'use client';
|
|
3
3
|
|
|
4
|
-
import React, { useState } from 'react';
|
|
5
|
-
import { useRouter } from 'next/navigation';
|
|
6
4
|
import { TrashIcon } from 'lucide-react';
|
|
7
5
|
import Link from 'next/link';
|
|
6
|
+
import { useRouter } from 'next/navigation';
|
|
7
|
+
import { useState } from 'react';
|
|
8
8
|
import { AddAgentButton } from '../../app/AddAgentButton';
|
|
9
9
|
import { AgentCard } from './AgentCard';
|
|
10
10
|
import { Section } from './Section';
|
|
@@ -16,16 +16,29 @@ type AgentWithVisibility = AgentBasicInformation & {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
type AgentsListProps = {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* @@@
|
|
21
|
+
*/
|
|
22
|
+
readonly agents: AgentWithVisibility[];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @@@
|
|
26
|
+
*/
|
|
27
|
+
readonly isAdmin: boolean;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Base URL of the agents server
|
|
31
|
+
*/
|
|
32
|
+
readonly publicUrl: URL;
|
|
21
33
|
};
|
|
22
34
|
|
|
23
|
-
export function AgentsList(
|
|
35
|
+
export function AgentsList(props: AgentsListProps) {
|
|
36
|
+
const { agents: initialAgents, isAdmin, publicUrl } = props;
|
|
24
37
|
const router = useRouter();
|
|
25
38
|
const [agents, setAgents] = useState(Array.from(initialAgents));
|
|
26
39
|
|
|
27
40
|
const handleDelete = async (agentIdentifier: string) => {
|
|
28
|
-
const agent = agents.find(a => a.permanentId === agentIdentifier || a.agentName === agentIdentifier);
|
|
41
|
+
const agent = agents.find((a) => a.permanentId === agentIdentifier || a.agentName === agentIdentifier);
|
|
29
42
|
if (!agent) return;
|
|
30
43
|
if (!window.confirm(`Delete agent "${agent.agentName}"? It will be moved to Recycle Bin.`)) return;
|
|
31
44
|
|
|
@@ -45,12 +58,14 @@ export function AgentsList({ agents: initialAgents, isAdmin }: AgentsListProps)
|
|
|
45
58
|
};
|
|
46
59
|
|
|
47
60
|
const handleClone = async (agentIdentifier: string) => {
|
|
48
|
-
const agent = agents.find(a => a.permanentId === agentIdentifier || a.agentName === agentIdentifier);
|
|
61
|
+
const agent = agents.find((a) => a.permanentId === agentIdentifier || a.agentName === agentIdentifier);
|
|
49
62
|
if (!agent) return;
|
|
50
63
|
if (!window.confirm(`Clone agent "${agent.agentName}"?`)) return;
|
|
51
64
|
|
|
52
65
|
try {
|
|
53
|
-
const response = await fetch(`/api/agents/${encodeURIComponent(agentIdentifier)}/clone`, {
|
|
66
|
+
const response = await fetch(`/api/agents/${encodeURIComponent(agentIdentifier)}/clone`, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
});
|
|
54
69
|
if (response.ok) {
|
|
55
70
|
const newAgent = await response.json();
|
|
56
71
|
setAgents([...agents, newAgent]);
|
|
@@ -64,7 +79,7 @@ export function AgentsList({ agents: initialAgents, isAdmin }: AgentsListProps)
|
|
|
64
79
|
};
|
|
65
80
|
|
|
66
81
|
const handleToggleVisibility = async (agentIdentifier: string) => {
|
|
67
|
-
const agent = agents.find(a => a.permanentId === agentIdentifier || a.agentName === agentIdentifier);
|
|
82
|
+
const agent = agents.find((a) => a.permanentId === agentIdentifier || a.agentName === agentIdentifier);
|
|
68
83
|
if (!agent) return;
|
|
69
84
|
|
|
70
85
|
const newVisibility = agent.visibility === 'PUBLIC' ? 'PRIVATE' : 'PUBLIC';
|
|
@@ -78,11 +93,13 @@ export function AgentsList({ agents: initialAgents, isAdmin }: AgentsListProps)
|
|
|
78
93
|
|
|
79
94
|
if (response.ok) {
|
|
80
95
|
// Update the local state
|
|
81
|
-
setAgents(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
setAgents(
|
|
97
|
+
agents.map((a) =>
|
|
98
|
+
a.permanentId === agent.permanentId || a.agentName === agent.agentName
|
|
99
|
+
? { ...a, visibility: newVisibility }
|
|
100
|
+
: a,
|
|
101
|
+
),
|
|
102
|
+
);
|
|
86
103
|
router.refresh(); // Refresh server data to ensure consistency
|
|
87
104
|
} else {
|
|
88
105
|
alert('Failed to update agent visibility');
|
|
@@ -95,6 +112,7 @@ export function AgentsList({ agents: initialAgents, isAdmin }: AgentsListProps)
|
|
|
95
112
|
<AgentCard
|
|
96
113
|
key={agent.permanentId || agent.agentName}
|
|
97
114
|
agent={agent}
|
|
115
|
+
publicUrl={publicUrl}
|
|
98
116
|
href={`/agents/${encodeURIComponent(agent.permanentId || agent.agentName)}`}
|
|
99
117
|
isAdmin={isAdmin}
|
|
100
118
|
onDelete={handleDelete}
|
|
@@ -1,26 +1,41 @@
|
|
|
1
1
|
// Client Component for rendering deleted agents
|
|
2
2
|
'use client';
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import { useState } from 'react';
|
|
5
5
|
import { AgentCard } from './AgentCard';
|
|
6
6
|
|
|
7
7
|
import { AgentBasicInformation } from '../../../../../src/book-2.0/agent-source/AgentBasicInformation';
|
|
8
8
|
|
|
9
9
|
type DeletedAgentsListProps = {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* @@@
|
|
12
|
+
*/
|
|
13
|
+
readonly agents: readonly AgentBasicInformation[];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @@@
|
|
17
|
+
*/
|
|
18
|
+
readonly isAdmin: boolean;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Base URL of the agents server
|
|
22
|
+
*/
|
|
23
|
+
readonly publicUrl: URL;
|
|
12
24
|
};
|
|
13
25
|
|
|
14
|
-
export function DeletedAgentsList(
|
|
26
|
+
export function DeletedAgentsList(props: DeletedAgentsListProps) {
|
|
27
|
+
const { agents: initialAgents, isAdmin, publicUrl } = props;
|
|
15
28
|
const [agents, setAgents] = useState(Array.from(initialAgents));
|
|
16
29
|
|
|
17
30
|
const handleRestore = async (agentIdentifier: string) => {
|
|
18
|
-
const agent = agents.find(a => a.permanentId === agentIdentifier || a.agentName === agentIdentifier);
|
|
31
|
+
const agent = agents.find((a) => a.permanentId === agentIdentifier || a.agentName === agentIdentifier);
|
|
19
32
|
if (!agent) return;
|
|
20
33
|
if (!window.confirm(`Restore agent "${agent.agentName}"?`)) return;
|
|
21
34
|
|
|
22
35
|
try {
|
|
23
|
-
const response = await fetch(`/api/agents/${encodeURIComponent(agentIdentifier)}/restore`, {
|
|
36
|
+
const response = await fetch(`/api/agents/${encodeURIComponent(agentIdentifier)}/restore`, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
});
|
|
24
39
|
if (response.ok) {
|
|
25
40
|
// Update local state immediately
|
|
26
41
|
setAgents(agents.filter((a) => a.permanentId !== agent.permanentId && a.agentName !== agent.agentName));
|
|
@@ -40,6 +55,7 @@ export function DeletedAgentsList({ agents: initialAgents, isAdmin }: DeletedAge
|
|
|
40
55
|
<AgentCard
|
|
41
56
|
key={agent.permanentId || agent.agentName}
|
|
42
57
|
agent={agent}
|
|
58
|
+
publicUrl={publicUrl}
|
|
43
59
|
href={`/agents/${encodeURIComponent(agent.permanentId || agent.agentName)}`}
|
|
44
60
|
isAdmin={isAdmin}
|
|
45
61
|
onRestore={handleRestore}
|
|
@@ -3,16 +3,25 @@ import { AgentCard } from './AgentCard';
|
|
|
3
3
|
import { Section } from './Section';
|
|
4
4
|
|
|
5
5
|
type ExternalAgentsSectionProps = {
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @@@
|
|
8
|
+
*/
|
|
9
|
+
readonly agentsByServer: AgentsByServer[];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Base URL of the agents server
|
|
13
|
+
*/
|
|
14
|
+
readonly publicUrl: URL;
|
|
7
15
|
};
|
|
8
16
|
|
|
9
|
-
export function ExternalAgentsSection(
|
|
17
|
+
export function ExternalAgentsSection(props: ExternalAgentsSectionProps) {
|
|
18
|
+
const { agentsByServer, publicUrl } = props;
|
|
10
19
|
return (
|
|
11
20
|
<>
|
|
12
21
|
{agentsByServer.map(({ serverUrl, agents }) => (
|
|
13
22
|
<Section key={serverUrl} title={`Agents from ${new URL(serverUrl).hostname} (${agents.length})`}>
|
|
14
23
|
{agents.map((agent) => (
|
|
15
|
-
<AgentCard key={agent.url} agent={agent} href={agent.url} />
|
|
24
|
+
<AgentCard key={agent.url} agent={agent} href={agent.url} publicUrl={publicUrl} />
|
|
16
25
|
))}
|
|
17
26
|
</Section>
|
|
18
27
|
))}
|
|
@@ -15,7 +15,15 @@ type ServerState = {
|
|
|
15
15
|
error?: string;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
type ExternalAgentsSectionClientProps = {
|
|
19
|
+
/**
|
|
20
|
+
* Base URL of the agents server
|
|
21
|
+
*/
|
|
22
|
+
readonly publicUrl: URL;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function ExternalAgentsSectionClient(props: ExternalAgentsSectionClientProps) {
|
|
26
|
+
const { publicUrl } = props;
|
|
19
27
|
const [servers, setServers] = useState<Record<string, ServerState>>({});
|
|
20
28
|
const [initialLoading, setInitialLoading] = useState(true);
|
|
21
29
|
|
|
@@ -26,24 +34,23 @@ export function ExternalAgentsSectionClient() {
|
|
|
26
34
|
try {
|
|
27
35
|
const response = await fetch('/api/federated-agents');
|
|
28
36
|
if (!response.ok) throw new Error('Failed to fetch federated servers');
|
|
29
|
-
|
|
37
|
+
|
|
30
38
|
const data: FederatedServersResponse = await response.json();
|
|
31
|
-
|
|
39
|
+
|
|
32
40
|
if (isCancelled) return;
|
|
33
41
|
|
|
34
42
|
const initialServerState: Record<string, ServerState> = {};
|
|
35
|
-
data.federatedServers.forEach(serverUrl => {
|
|
43
|
+
data.federatedServers.forEach((serverUrl) => {
|
|
36
44
|
initialServerState[serverUrl] = { status: 'loading', agents: [] };
|
|
37
45
|
});
|
|
38
|
-
|
|
46
|
+
|
|
39
47
|
setServers(initialServerState);
|
|
40
48
|
setInitialLoading(false);
|
|
41
49
|
|
|
42
50
|
// Fetch agents for each server independently
|
|
43
|
-
data.federatedServers.forEach(serverUrl => {
|
|
51
|
+
data.federatedServers.forEach((serverUrl) => {
|
|
44
52
|
fetchAgentsForServer(serverUrl);
|
|
45
53
|
});
|
|
46
|
-
|
|
47
54
|
} catch (error) {
|
|
48
55
|
console.error('Failed to load federated servers list', error);
|
|
49
56
|
if (!isCancelled) setInitialLoading(false);
|
|
@@ -80,7 +87,9 @@ export function ExternalAgentsSectionClient() {
|
|
|
80
87
|
const response = await fetch(proxyUrl);
|
|
81
88
|
|
|
82
89
|
if (!response.ok) {
|
|
83
|
-
throw new Error(
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Failed to fetch agents from ${serverUrl} via proxy (Status: ${response.status})`,
|
|
92
|
+
);
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
const data = await response.json();
|
|
@@ -134,7 +143,7 @@ export function ExternalAgentsSectionClient() {
|
|
|
134
143
|
|
|
135
144
|
return (
|
|
136
145
|
<>
|
|
137
|
-
{serverUrls.map(serverUrl => {
|
|
146
|
+
{serverUrls.map((serverUrl) => {
|
|
138
147
|
const state = servers[serverUrl];
|
|
139
148
|
const hostname = (() => {
|
|
140
149
|
try {
|
|
@@ -169,7 +178,7 @@ export function ExternalAgentsSectionClient() {
|
|
|
169
178
|
return (
|
|
170
179
|
<Section key={serverUrl} title={`Agents from ${hostname} (${state.agents.length})`}>
|
|
171
180
|
{state.agents.map((agent) => (
|
|
172
|
-
<AgentCard key={agent.url} agent={agent} href={agent.url} />
|
|
181
|
+
<AgentCard key={agent.url} agent={agent} href={agent.url} publicUrl={publicUrl} />
|
|
173
182
|
))}
|
|
174
183
|
</Section>
|
|
175
184
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
NEXT_PUBLIC_SITE_URL,
|
|
2
3
|
NEXT_PUBLIC_VERCEL_BRANCH_URL,
|
|
3
4
|
NEXT_PUBLIC_VERCEL_ENV,
|
|
4
5
|
NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_LOGIN,
|
|
@@ -24,6 +25,7 @@ import { TechInfoCard } from '../Homepage/TechInfoCard';
|
|
|
24
25
|
export default function VercelDeploymentCard() {
|
|
25
26
|
return (
|
|
26
27
|
<TechInfoCard title="Vercel Deployment">
|
|
28
|
+
<p className="text-gray-600">NEXT_PUBLIC_SITE_URL: {NEXT_PUBLIC_SITE_URL?.href || 'undefined'}</p>
|
|
27
29
|
<p className="text-gray-600">NEXT_PUBLIC_VERCEL_ENV: {NEXT_PUBLIC_VERCEL_ENV}</p>
|
|
28
30
|
<p className="text-gray-600">NEXT_PUBLIC_VERCEL_TARGET_ENV: {NEXT_PUBLIC_VERCEL_TARGET_ENV}</p>
|
|
29
31
|
<p className="text-gray-600">NEXT_PUBLIC_VERCEL_URL: {NEXT_PUBLIC_VERCEL_URL}</p>
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
// Utility to generate content for robots.txt, security.txt, and humans.txt [DRY]
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { $provideServer } from '@/src/tools/$provideServer';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
export function generateRobotsTxt(): string {
|
|
9
|
-
return ['User-agent: *', `Sitemap: ${baseUrl}sitemap.xml`, ''].join('\n');
|
|
5
|
+
export async function generateRobotsTxt(): Promise<string> {
|
|
6
|
+
const { publicUrl } = await $provideServer();
|
|
7
|
+
return ['User-agent: *', `Sitemap: ${publicUrl.href}sitemap.xml`, ''].join('\n');
|
|
10
8
|
}
|
|
11
9
|
|
|
12
|
-
export function generateSecurityTxt(): string {
|
|
10
|
+
export async function generateSecurityTxt(): Promise<string> {
|
|
11
|
+
const { publicUrl } = await $provideServer();
|
|
13
12
|
// See https://securitytxt.org/ for more fields
|
|
14
13
|
return [
|
|
15
14
|
`Contact: mailto:security@ptbk.io`,
|
|
16
15
|
`Expires: ${new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]}`,
|
|
17
|
-
`Canonical: ${
|
|
16
|
+
`Canonical: ${publicUrl.href}security.txt`,
|
|
18
17
|
'',
|
|
19
18
|
].join('\n');
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
export function generateHumansTxt(): string {
|
|
23
|
-
|
|
21
|
+
export async function generateHumansTxt(): Promise<string> {
|
|
22
|
+
const { publicUrl } = await $provideServer();
|
|
23
|
+
return ['/* TEAM */', 'Developer: Promptbook Team', `Site: https://ptbk.io`, `Instance: ${publicUrl.href}`].join(
|
|
24
|
+
'\n',
|
|
25
|
+
);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { locateChrome } from 'locate-app';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { BrowserContext, chromium } from 'playwright';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Cache of browser instance
|
|
7
|
+
*
|
|
8
|
+
* @private internal cache for `$provideBrowserForServer`
|
|
9
|
+
*/
|
|
10
|
+
let browserInstance: BrowserContext | null = null;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @@@
|
|
14
|
+
*/
|
|
15
|
+
export async function $provideBrowserForServer(): Promise<BrowserContext> {
|
|
16
|
+
if (browserInstance === null /* || !browserInstance.isConnected() */) {
|
|
17
|
+
console.log('Launching new browser instance...');
|
|
18
|
+
browserInstance = await chromium.launchPersistentContext(
|
|
19
|
+
join(process.cwd(), '.promptbook', 'puppeteer', 'user-data'),
|
|
20
|
+
{
|
|
21
|
+
executablePath: await locateChrome(),
|
|
22
|
+
headless: false,
|
|
23
|
+
// defaultViewport: null,
|
|
24
|
+
// downloadsPath
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return browserInstance;
|
|
29
|
+
}
|
package/esm/index.es.js
CHANGED
|
@@ -47,7 +47,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
47
47
|
* @generated
|
|
48
48
|
* @see https://github.com/webgptorg/promptbook
|
|
49
49
|
*/
|
|
50
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.104.0-
|
|
50
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.104.0-8';
|
|
51
51
|
/**
|
|
52
52
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
53
53
|
* Note: [๐] Ignore a discrepancy between file name and entity name
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { string_agent_name, string_agent_permanent_id, string_url_image } from '../../types/typeAliases';
|
|
1
|
+
import type { string_agent_name, string_agent_permanent_id, string_url, string_url_image } from '../../types/typeAliases';
|
|
2
2
|
/**
|
|
3
3
|
* Generates an image for the agent to use as profile image
|
|
4
4
|
*
|
|
@@ -7,7 +7,7 @@ import type { string_agent_name, string_agent_permanent_id, string_url_image } f
|
|
|
7
7
|
*
|
|
8
8
|
* @public exported from `@promptbook/core`
|
|
9
9
|
*/
|
|
10
|
-
export declare function generatePlaceholderAgentProfileImageUrl(agentIdOrName: string_agent_permanent_id | string_agent_name, agentsServerUrl?: URL): string_url_image;
|
|
10
|
+
export declare function generatePlaceholderAgentProfileImageUrl(agentIdOrName: string_agent_permanent_id | string_agent_name, agentsServerUrl?: URL | string_url): string_url_image;
|
|
11
11
|
/**
|
|
12
12
|
* TODO: [๐คน] Figure out best placeholder image generator https://i.pravatar.cc/1000?u=568
|
|
13
13
|
*/
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { string_color, string_data_url, string_url_image } from '../../../types/typeAliases';
|
|
1
2
|
import { Color } from '../Color';
|
|
2
3
|
/**
|
|
3
4
|
* Makes data url from color
|
|
4
5
|
*
|
|
5
6
|
* @public exported from `@promptbook/color`
|
|
6
7
|
*/
|
|
7
|
-
export declare function colorToDataUrl(color: Color):
|
|
8
|
+
export declare function colorToDataUrl(color: Color | string_color): string_data_url & string_url_image;
|
|
8
9
|
/**
|
|
9
10
|
* TODO: Make as functions NOT const
|
|
10
11
|
*/
|
|
@@ -15,7 +15,7 @@ export declare const BOOK_LANGUAGE_VERSION: string_semantic_version;
|
|
|
15
15
|
export declare const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version;
|
|
16
16
|
/**
|
|
17
17
|
* Represents the version string of the Promptbook engine.
|
|
18
|
-
* It follows semantic versioning (e.g., `0.104.0-
|
|
18
|
+
* It follows semantic versioning (e.g., `0.104.0-7`).
|
|
19
19
|
*
|
|
20
20
|
* @generated
|
|
21
21
|
*/
|
package/package.json
CHANGED
package/umd/index.umd.js
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
* @generated
|
|
57
57
|
* @see https://github.com/webgptorg/promptbook
|
|
58
58
|
*/
|
|
59
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.104.0-
|
|
59
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.104.0-8';
|
|
60
60
|
/**
|
|
61
61
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
62
62
|
* Note: [๐] Ignore a discrepancy between file name and entity name
|