@promptbook/cli 0.103.0-55 → 0.103.0-66
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/TODO.txt +5 -1
- package/apps/agents-server/package-lock.json +2336 -0
- package/apps/agents-server/package.json +9 -0
- package/apps/agents-server/src/app/actions.ts +3 -1
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +3 -1
- package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +282 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +91 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +44 -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]/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/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/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]/generateAgentMetadata.ts +7 -3
- 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]/layout.tsx +41 -0
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +61 -97
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +47 -157
- package/apps/agents-server/src/app/agents/[agentName]/website-integration/page.tsx +70 -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/embed/page.tsx +2 -2
- package/apps/agents-server/src/app/globals.css +129 -0
- package/apps/agents-server/src/app/layout.tsx +16 -26
- package/apps/agents-server/src/app/manifest.ts +9 -4
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +334 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfileFromSource.tsx +23 -0
- package/apps/agents-server/src/{app/agents/[agentName] → components/AgentProfile}/AgentQrCode.tsx +8 -1
- package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +90 -0
- package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +87 -0
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +7 -6
- 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/metadataDefaults.ts +6 -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/utils/handleChatCompletion.ts +186 -14
- package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +13 -6
- package/apps/agents-server/src/utils/validateApiKey.ts +128 -0
- package/apps/agents-server/tailwind.config.ts +1 -1
- package/esm/index.es.js +953 -474
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/components.index.d.ts +2 -2
- package/esm/typings/src/_packages/core.index.d.ts +6 -8
- package/esm/typings/src/_packages/types.index.d.ts +7 -1
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -1
- package/esm/typings/src/book-2.0/agent-source/createCommitmentRegex.d.ts +1 -1
- package/esm/typings/src/book-components/Chat/AgentChat/AgentChat.d.ts +3 -0
- package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +6 -0
- package/esm/typings/src/book-components/Chat/LlmChat/LlmChatProps.d.ts +5 -0
- package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgentIntegration.d.ts +52 -0
- package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgentSeamlessIntegration.d.ts +14 -0
- package/esm/typings/src/book-components/icons/SendIcon.d.ts +3 -0
- package/esm/typings/src/commitments/CLOSED/CLOSED.d.ts +4 -0
- package/esm/typings/src/commitments/CLOSED/CLOSED.test.d.ts +4 -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/USE/USE.d.ts +53 -0
- package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.d.ts +42 -0
- package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.test.d.ts +1 -0
- package/esm/typings/src/commitments/{IMPORTANT/IMPORTANT.d.ts → USE_MCP/USE_MCP.d.ts} +16 -5
- package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.d.ts +38 -0
- package/esm/typings/src/commitments/_base/BaseCommitmentDefinition.d.ts +6 -0
- package/esm/typings/src/commitments/index.d.ts +93 -1
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +3 -1
- package/esm/typings/src/other/templates/getTemplatesPipelineCollection.d.ts +1 -1
- package/esm/typings/src/playground/playground.d.ts +3 -0
- package/esm/typings/src/types/typeAliases.d.ts +6 -0
- package/esm/typings/src/utils/color/Color.d.ts +9 -1
- package/esm/typings/src/utils/color/css-colors.d.ts +1 -0
- package/esm/typings/src/utils/random/$generateBookBoilerplate.d.ts +6 -0
- package/esm/typings/src/utils/random/CzechNamePool.d.ts +7 -0
- package/esm/typings/src/utils/random/EnglishNamePool.d.ts +7 -0
- package/esm/typings/src/utils/random/NamePool.d.ts +17 -0
- package/esm/typings/src/utils/random/getNamePool.d.ts +10 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/umd/index.umd.js +902 -423
- package/umd/index.umd.js.map +1 -1
- package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgent.d.ts +0 -29
- package/esm/typings/src/commitments/registry.d.ts +0 -68
- package/esm/typings/src/playground/playground1.d.ts +0 -2
|
@@ -8,5 +8,14 @@
|
|
|
8
8
|
"start": "next start -p 4440",
|
|
9
9
|
"lint": "next lint",
|
|
10
10
|
"postinstall": "cd ../../ && npm ci"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
14
|
+
"autoprefixer": "^10.4.21",
|
|
15
|
+
"postcss": "^8.5.6",
|
|
16
|
+
"tailwindcss": "^3.4.18"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"remark-gfm": "^4.0.1"
|
|
11
20
|
}
|
|
12
21
|
}
|
|
@@ -4,6 +4,7 @@ import { $generateBookBoilerplate } from '@promptbook-local/core';
|
|
|
4
4
|
import { string_agent_name } from '@promptbook-local/types';
|
|
5
5
|
import { revalidatePath } from 'next/cache';
|
|
6
6
|
import { cookies } from 'next/headers';
|
|
7
|
+
import { getMetadata } from '../database/getMetadata';
|
|
7
8
|
import { $provideAgentCollectionForServer } from '../tools/$provideAgentCollectionForServer';
|
|
8
9
|
import { authenticateUser } from '../utils/authenticateUser';
|
|
9
10
|
import { isUserAdmin } from '../utils/isUserAdmin';
|
|
@@ -16,7 +17,8 @@ export async function $createAgentAction(): Promise<string_agent_name> {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const collection = await $provideAgentCollectionForServer();
|
|
19
|
-
const
|
|
20
|
+
const namePool = (await getMetadata('NAME_POOL')) || 'ENGLISH';
|
|
21
|
+
const agentSource = $generateBookBoilerplate({ namePool });
|
|
20
22
|
|
|
21
23
|
const { agentName } = await collection.createAgent(agentSource);
|
|
22
24
|
|
|
@@ -9,12 +9,13 @@ import { string_agent_url } from '../../../../../../src/types/typeAliases';
|
|
|
9
9
|
type AgentChatWrapperProps = {
|
|
10
10
|
agentUrl: string_agent_url;
|
|
11
11
|
defaultMessage?: string;
|
|
12
|
+
autoExecuteMessage?: string;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
// TODO: [🐱🚀] Rename to AgentChatSomethingWrapper
|
|
15
16
|
|
|
16
17
|
export function AgentChatWrapper(props: AgentChatWrapperProps) {
|
|
17
|
-
const { agentUrl, defaultMessage } = props;
|
|
18
|
+
const { agentUrl, defaultMessage, autoExecuteMessage } = props;
|
|
18
19
|
|
|
19
20
|
const agentPromise = useMemo(
|
|
20
21
|
() =>
|
|
@@ -67,6 +68,7 @@ export function AgentChatWrapper(props: AgentChatWrapperProps) {
|
|
|
67
68
|
agent={agent}
|
|
68
69
|
onFeedback={handleFeedback}
|
|
69
70
|
defaultMessage={defaultMessage}
|
|
71
|
+
autoExecuteMessage={autoExecuteMessage}
|
|
70
72
|
/>
|
|
71
73
|
);
|
|
72
74
|
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { TODO_any } from '@promptbook-local/types';
|
|
4
|
+
import {
|
|
5
|
+
CopyIcon,
|
|
6
|
+
CopyPlusIcon,
|
|
7
|
+
DownloadIcon,
|
|
8
|
+
MailIcon,
|
|
9
|
+
MessageCircleQuestionIcon,
|
|
10
|
+
MessageSquareIcon,
|
|
11
|
+
MessageSquareShareIcon,
|
|
12
|
+
MoreHorizontalIcon,
|
|
13
|
+
QrCodeIcon,
|
|
14
|
+
SmartphoneIcon,
|
|
15
|
+
SquareSplitHorizontalIcon,
|
|
16
|
+
} from 'lucide-react';
|
|
17
|
+
import { Barlow_Condensed } from 'next/font/google';
|
|
18
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
19
|
+
import { string_data_url, string_url_image } from '../../../../../../src/types/typeAliases';
|
|
20
|
+
import { getAgentLinks } from './agentLinks';
|
|
21
|
+
|
|
22
|
+
type BeforeInstallPromptEvent = Event & {
|
|
23
|
+
prompt: () => Promise<void>;
|
|
24
|
+
userChoice: Promise<{ outcome: 'accepted' | 'dismissed'; platform: string }>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const barlowCondensed = Barlow_Condensed({
|
|
28
|
+
subsets: ['latin'],
|
|
29
|
+
weight: ['300', '400', '500', '600', '700'],
|
|
30
|
+
variable: '--font-barlow-condensed',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
type AgentOptionsMenuProps = {
|
|
34
|
+
agentName: string;
|
|
35
|
+
agentUrl: string;
|
|
36
|
+
agentEmail: string;
|
|
37
|
+
brandColorHex: string;
|
|
38
|
+
isAdmin?: boolean;
|
|
39
|
+
backgroundImage: string_url_image & string_data_url;
|
|
40
|
+
onShowQrCode?: () => void;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export function AgentOptionsMenu({
|
|
44
|
+
agentName,
|
|
45
|
+
agentUrl,
|
|
46
|
+
agentEmail,
|
|
47
|
+
brandColorHex,
|
|
48
|
+
isAdmin = false,
|
|
49
|
+
backgroundImage,
|
|
50
|
+
onShowQrCode,
|
|
51
|
+
}: AgentOptionsMenuProps) {
|
|
52
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
53
|
+
const [copyFeedback, setCopyFeedback] = useState<string | null>(null);
|
|
54
|
+
const menuRef = useRef<HTMLDivElement>(null);
|
|
55
|
+
|
|
56
|
+
// PWA Install state
|
|
57
|
+
const [installPromptEvent, setInstallPromptEvent] = useState<BeforeInstallPromptEvent | null>(null);
|
|
58
|
+
const [isInstalled, setIsInstalled] = useState(false);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
function handleBeforeInstallPrompt(e: Event) {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
setInstallPromptEvent(e as BeforeInstallPromptEvent);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function updateInstalledStatus() {
|
|
67
|
+
const mediaMatch = window.matchMedia('(display-mode: standalone)');
|
|
68
|
+
const standalone = mediaMatch.matches || (window.navigator as TODO_any).standalone === true;
|
|
69
|
+
setIsInstalled(standalone);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
|
|
73
|
+
updateInstalledStatus();
|
|
74
|
+
window.matchMedia('(display-mode: standalone)').addEventListener('change', updateInstalledStatus);
|
|
75
|
+
|
|
76
|
+
return () => {
|
|
77
|
+
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
|
|
78
|
+
window.matchMedia('(display-mode: standalone)').removeEventListener('change', updateInstalledStatus);
|
|
79
|
+
};
|
|
80
|
+
}, []);
|
|
81
|
+
|
|
82
|
+
const handleInstallApp = useCallback(async () => {
|
|
83
|
+
if (!installPromptEvent) return;
|
|
84
|
+
try {
|
|
85
|
+
installPromptEvent.prompt();
|
|
86
|
+
const choice = await installPromptEvent.userChoice.catch(() => null);
|
|
87
|
+
if (choice?.outcome === 'accepted') {
|
|
88
|
+
setIsInstalled(true);
|
|
89
|
+
}
|
|
90
|
+
} finally {
|
|
91
|
+
setInstallPromptEvent(null);
|
|
92
|
+
}
|
|
93
|
+
}, [installPromptEvent]);
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
function handleClickOutside(event: MouseEvent) {
|
|
97
|
+
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
|
98
|
+
setIsOpen(false);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
103
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
const handleCopy = async (value: string, label: string) => {
|
|
107
|
+
try {
|
|
108
|
+
await navigator.clipboard.writeText(value);
|
|
109
|
+
setCopyFeedback(label);
|
|
110
|
+
setTimeout(() => setCopyFeedback(null), 2000);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error('Failed to copy:', error);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const links = getAgentLinks(agentName);
|
|
117
|
+
const editBookLink = links.find((l) => l.title === 'Edit Book')!;
|
|
118
|
+
const integrationLink = links.find((l) => l.title === 'Integration')!;
|
|
119
|
+
const historyLink = links.find((l) => l.title === 'History & Feedback')!;
|
|
120
|
+
const allLinksLink = links.find((l) => l.title === 'All Links')!;
|
|
121
|
+
|
|
122
|
+
const menuItems = [
|
|
123
|
+
{
|
|
124
|
+
type: 'link' as const,
|
|
125
|
+
href: `/agents/${encodeURIComponent(agentName)}/chat`,
|
|
126
|
+
icon: MessageSquareShareIcon,
|
|
127
|
+
label: 'Standalone Chat',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
type: 'link' as const,
|
|
131
|
+
href: `/agents/${encodeURIComponent(agentName)}/book+chat`,
|
|
132
|
+
icon: SquareSplitHorizontalIcon,
|
|
133
|
+
label: 'Edit Book & Chat',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
type: 'link' as const,
|
|
137
|
+
href: editBookLink.href,
|
|
138
|
+
icon: editBookLink.icon,
|
|
139
|
+
label: editBookLink.title,
|
|
140
|
+
},
|
|
141
|
+
{ type: 'divider' as const },
|
|
142
|
+
{
|
|
143
|
+
type: 'link' as const,
|
|
144
|
+
href: integrationLink.href,
|
|
145
|
+
icon: integrationLink.icon,
|
|
146
|
+
label: integrationLink.title,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
type: 'link' as const,
|
|
150
|
+
href: historyLink.href,
|
|
151
|
+
icon: historyLink.icon,
|
|
152
|
+
label: historyLink.title, // 'History & Feedback'
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
type: 'link' as const,
|
|
156
|
+
href: allLinksLink.href,
|
|
157
|
+
icon: allLinksLink.icon,
|
|
158
|
+
label: allLinksLink.title,
|
|
159
|
+
},
|
|
160
|
+
{ type: 'divider' as const },
|
|
161
|
+
{
|
|
162
|
+
type: 'action' as const,
|
|
163
|
+
icon: CopyIcon,
|
|
164
|
+
label: copyFeedback === 'URL' ? 'Copied!' : 'Copy Agent URL',
|
|
165
|
+
onClick: () => handleCopy(agentUrl, 'URL'),
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
type: 'action' as const,
|
|
169
|
+
icon: MailIcon,
|
|
170
|
+
label: copyFeedback === 'Email' ? 'Copied!' : 'Copy Agent Email',
|
|
171
|
+
onClick: () => handleCopy(agentEmail, 'Email'),
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
type: 'action' as const,
|
|
175
|
+
icon: QrCodeIcon,
|
|
176
|
+
label: 'Show QR Code',
|
|
177
|
+
onClick: onShowQrCode,
|
|
178
|
+
},
|
|
179
|
+
// Install App - only show if PWA is installable and not already installed
|
|
180
|
+
...(!isInstalled && installPromptEvent
|
|
181
|
+
? [
|
|
182
|
+
{
|
|
183
|
+
type: 'action' as const,
|
|
184
|
+
icon: SmartphoneIcon,
|
|
185
|
+
label: 'Install App',
|
|
186
|
+
onClick: handleInstallApp,
|
|
187
|
+
},
|
|
188
|
+
]
|
|
189
|
+
: []),
|
|
190
|
+
// Admin-only items
|
|
191
|
+
...(isAdmin
|
|
192
|
+
? [
|
|
193
|
+
{ type: 'divider' as const },
|
|
194
|
+
{
|
|
195
|
+
type: 'link' as const,
|
|
196
|
+
href: `/admin/chat-history?agentName=${encodeURIComponent(agentName)}`,
|
|
197
|
+
icon: MessageSquareIcon,
|
|
198
|
+
label: 'Chat History',
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
type: 'link' as const,
|
|
202
|
+
href: `/admin/chat-feedback?agentName=${encodeURIComponent(agentName)}`,
|
|
203
|
+
icon: MessageCircleQuestionIcon,
|
|
204
|
+
label: 'Chat Feedback',
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
type: 'link' as const,
|
|
208
|
+
href: `/agents/${encodeURIComponent(agentName)}/clone`,
|
|
209
|
+
icon: CopyPlusIcon,
|
|
210
|
+
label: 'Clone Agent',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
type: 'link' as const,
|
|
214
|
+
href: `/agents/${encodeURIComponent(agentName)}/export`,
|
|
215
|
+
icon: DownloadIcon,
|
|
216
|
+
label: 'Export Agent',
|
|
217
|
+
},
|
|
218
|
+
// {
|
|
219
|
+
// type: 'link' as const,
|
|
220
|
+
// href: backgroundImage,
|
|
221
|
+
// icon: DownloadIcon,
|
|
222
|
+
// label: 'Download Background Image',
|
|
223
|
+
// },
|
|
224
|
+
]
|
|
225
|
+
: []),
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<div ref={menuRef} className="relative z-[9999]">
|
|
230
|
+
<button
|
|
231
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
232
|
+
className="p-3 rounded-full hover:bg-white/30 transition-all duration-200"
|
|
233
|
+
// style={{ backgroundColor: brandColorHex }}
|
|
234
|
+
aria-label="More options"
|
|
235
|
+
>
|
|
236
|
+
<MoreHorizontalIcon className="w-5 h-5 text-black" />
|
|
237
|
+
</button>
|
|
238
|
+
|
|
239
|
+
{isOpen && (
|
|
240
|
+
<div
|
|
241
|
+
className={`absolute right-0 top-full mt-2 w-56 bg-white rounded-xl shadow-2xl border border-gray-100 py-2 z-[9999] animate-in fade-in slide-in-from-top-2 duration-200 ${barlowCondensed.className}`}
|
|
242
|
+
>
|
|
243
|
+
{menuItems.map((item, index) => {
|
|
244
|
+
if (item.type === 'divider') {
|
|
245
|
+
return <div key={index} className="h-px bg-gray-100 my-2" />;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (item.type === 'link') {
|
|
249
|
+
return (
|
|
250
|
+
<a
|
|
251
|
+
key={index}
|
|
252
|
+
href={item.href}
|
|
253
|
+
className="flex items-center gap-3 px-4 py-2.5 text-gray-700 hover:bg-gray-50 transition-colors"
|
|
254
|
+
onClick={() => setIsOpen(false)}
|
|
255
|
+
>
|
|
256
|
+
<item.icon className="w-4 h-4 text-gray-500" />
|
|
257
|
+
<span className="text-sm font-medium">{item.label}</span>
|
|
258
|
+
</a>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<button
|
|
264
|
+
key={index}
|
|
265
|
+
onClick={() => {
|
|
266
|
+
item.onClick?.();
|
|
267
|
+
if (item.label !== 'Show QR Code') {
|
|
268
|
+
// Keep menu open for copy feedback
|
|
269
|
+
}
|
|
270
|
+
}}
|
|
271
|
+
className="flex items-center gap-3 px-4 py-2.5 text-gray-700 hover:bg-gray-50 transition-colors w-full text-left"
|
|
272
|
+
>
|
|
273
|
+
<item.icon className="w-4 h-4 text-gray-500" />
|
|
274
|
+
<span className="text-sm font-medium">{item.label}</span>
|
|
275
|
+
</button>
|
|
276
|
+
);
|
|
277
|
+
})}
|
|
278
|
+
</div>
|
|
279
|
+
)}
|
|
280
|
+
</div>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { usePromise } from '@common/hooks/usePromise';
|
|
4
|
+
import { Chat } from '@promptbook-local/components';
|
|
5
|
+
import { RemoteAgent } from '@promptbook-local/core';
|
|
6
|
+
import { useRouter } from 'next/navigation';
|
|
7
|
+
import { useCallback, useMemo } from 'react';
|
|
8
|
+
import spaceTrim from 'spacetrim';
|
|
9
|
+
import { string_agent_url, string_color } from '../../../../../../src/types/typeAliases';
|
|
10
|
+
|
|
11
|
+
type AgentProfileChatProps = {
|
|
12
|
+
agentUrl: string_agent_url;
|
|
13
|
+
agentName: string;
|
|
14
|
+
fullname: string;
|
|
15
|
+
brandColorHex: string_color;
|
|
16
|
+
avatarSrc: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function AgentProfileChat({ agentUrl, agentName, fullname, brandColorHex, avatarSrc }: AgentProfileChatProps) {
|
|
20
|
+
const router = useRouter();
|
|
21
|
+
|
|
22
|
+
const agentPromise = useMemo(
|
|
23
|
+
() =>
|
|
24
|
+
RemoteAgent.connect({
|
|
25
|
+
agentUrl,
|
|
26
|
+
isVerbose: true,
|
|
27
|
+
}),
|
|
28
|
+
[agentUrl],
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const { value: agent } = usePromise(agentPromise, [agentPromise]);
|
|
32
|
+
|
|
33
|
+
const handleMessage = useCallback(
|
|
34
|
+
async (message: string) => {
|
|
35
|
+
// Redirect to chat page with the message
|
|
36
|
+
router.push(`/agents/${encodeURIComponent(agentName)}/chat?message=${encodeURIComponent(message)}`);
|
|
37
|
+
},
|
|
38
|
+
[agentName, router],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const initialMessage = useMemo(() => {
|
|
42
|
+
if (!agent) {
|
|
43
|
+
return 'Loading...';
|
|
44
|
+
}
|
|
45
|
+
return (
|
|
46
|
+
agent.initialMessage ||
|
|
47
|
+
spaceTrim(`
|
|
48
|
+
Hello! I am ${fullname || agentName || 'an AI Agent'}.
|
|
49
|
+
|
|
50
|
+
[Hello](?message=Hello, can you tell me about yourself?)
|
|
51
|
+
`)
|
|
52
|
+
);
|
|
53
|
+
}, [agent, fullname, agentName]);
|
|
54
|
+
|
|
55
|
+
// If agent is not loaded yet, we can show a skeleton or just the default Chat structure
|
|
56
|
+
// But to match "same initial message", we need the agent loaded or at least the default fallback.
|
|
57
|
+
// The fallback above matches AgentChat.tsx default.
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="w-full h-[400px] md:h-[500px]">
|
|
61
|
+
<Chat
|
|
62
|
+
title={`Chat with ${fullname}`}
|
|
63
|
+
participants={[
|
|
64
|
+
{
|
|
65
|
+
name: 'AGENT',
|
|
66
|
+
fullname,
|
|
67
|
+
isMe: false,
|
|
68
|
+
color: brandColorHex,
|
|
69
|
+
avatarSrc,
|
|
70
|
+
// <- TODO: [🧠] Maybe this shouldnt be there
|
|
71
|
+
},
|
|
72
|
+
]}
|
|
73
|
+
messages={[
|
|
74
|
+
{
|
|
75
|
+
from: 'AGENT',
|
|
76
|
+
content: initialMessage,
|
|
77
|
+
date: new Date(),
|
|
78
|
+
id: 'initial-message',
|
|
79
|
+
isComplete: true,
|
|
80
|
+
},
|
|
81
|
+
]}
|
|
82
|
+
onMessage={handleMessage}
|
|
83
|
+
isSaveButtonEnabled={false}
|
|
84
|
+
isCopyButtonEnabled={false}
|
|
85
|
+
className="bg-transparent"
|
|
86
|
+
buttonColor={brandColorHex}
|
|
87
|
+
style={{ background: 'transparent' }}
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { AgentBasicInformation } from '@promptbook-local/types';
|
|
4
|
+
import { AgentProfile } from '../../../components/AgentProfile/AgentProfile';
|
|
5
|
+
import { AgentOptionsMenu } from './AgentOptionsMenu';
|
|
6
|
+
|
|
7
|
+
type AgentProfileWrapperProps = {
|
|
8
|
+
agent: AgentBasicInformation;
|
|
9
|
+
agentUrl: string;
|
|
10
|
+
agentEmail: string;
|
|
11
|
+
agentName: string;
|
|
12
|
+
brandColorHex: string;
|
|
13
|
+
isAdmin: boolean;
|
|
14
|
+
isHeadless: boolean;
|
|
15
|
+
actions: React.ReactNode;
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function AgentProfileWrapper(props: AgentProfileWrapperProps) {
|
|
20
|
+
const { agent, agentUrl, agentEmail, agentName, brandColorHex, isAdmin, isHeadless, actions, children } = props;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<AgentProfile
|
|
24
|
+
agent={agent}
|
|
25
|
+
agentUrl={agentUrl}
|
|
26
|
+
agentEmail={agentEmail}
|
|
27
|
+
isHeadless={isHeadless}
|
|
28
|
+
renderMenu={({ onShowQrCode }) => (
|
|
29
|
+
<AgentOptionsMenu
|
|
30
|
+
agentName={agentName}
|
|
31
|
+
agentUrl={agentUrl}
|
|
32
|
+
agentEmail={agentEmail}
|
|
33
|
+
brandColorHex={brandColorHex}
|
|
34
|
+
isAdmin={isAdmin}
|
|
35
|
+
onShowQrCode={onShowQrCode}
|
|
36
|
+
backgroundImage="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAA1JREFUGFdjYJh39z8ABJgCe/ZvAS4AAAAASUVORK5CYII="
|
|
37
|
+
/>
|
|
38
|
+
)}
|
|
39
|
+
actions={actions}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
</AgentProfile>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -12,10 +12,10 @@ export function CloneAgentButton({ agentName }: CloneAgentButtonProps) {
|
|
|
12
12
|
|
|
13
13
|
const handleClone = async () => {
|
|
14
14
|
if (!window.confirm(`Clone agent "${agentName}"?`)) return;
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
try {
|
|
17
17
|
const response = await fetch(`/api/agents/${encodeURIComponent(agentName)}/clone`, { method: 'POST' });
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
if (!response.ok) {
|
|
20
20
|
throw new Error('Failed to clone agent');
|
|
21
21
|
}
|
|
@@ -32,9 +32,9 @@ export function CloneAgentButton({ agentName }: CloneAgentButtonProps) {
|
|
|
32
32
|
return (
|
|
33
33
|
<button
|
|
34
34
|
onClick={handleClone}
|
|
35
|
-
className="
|
|
35
|
+
className="inline-flex items-center justify-center whitespace-nowrap rounded-md border border-gray-300 bg-white px-3 py-1.5 text-xs font-semibold text-gray-700 shadow-sm hover:bg-gray-50"
|
|
36
36
|
>
|
|
37
|
-
<CopyIcon className="
|
|
37
|
+
<CopyIcon className="mr-2 w-3 h-3" />
|
|
38
38
|
Clone
|
|
39
39
|
</button>
|
|
40
40
|
);
|
|
@@ -58,7 +58,7 @@ export function InstallPwaButton() {
|
|
|
58
58
|
<button
|
|
59
59
|
type="button"
|
|
60
60
|
onClick={onInstall}
|
|
61
|
-
className="
|
|
61
|
+
className="inline-flex items-center justify-center whitespace-nowrap rounded-md border border-gray-300 bg-white px-3 py-1.5 text-xs font-semibold text-gray-700 shadow-sm hover:bg-gray-50"
|
|
62
62
|
style={{
|
|
63
63
|
opacity: installPromptEvent ? 1 : 0.5,
|
|
64
64
|
cursor: installPromptEvent ? 'pointer' : 'wait',
|
|
@@ -67,7 +67,7 @@ export function InstallPwaButton() {
|
|
|
67
67
|
disabled={!installPromptEvent}
|
|
68
68
|
>
|
|
69
69
|
{/* Simple icon substitute: download arrow */}
|
|
70
|
-
<ShoppingBagIcon className="
|
|
70
|
+
<ShoppingBagIcon className="mr-2 w-3 h-3" />
|
|
71
71
|
Install
|
|
72
72
|
</button>
|
|
73
73
|
);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BookOpenIcon,
|
|
3
|
+
CodeIcon,
|
|
4
|
+
GlobeIcon,
|
|
5
|
+
HistoryIcon,
|
|
6
|
+
LinkIcon,
|
|
7
|
+
MessageSquareIcon,
|
|
8
|
+
NotebookPenIcon,
|
|
9
|
+
} from 'lucide-react';
|
|
10
|
+
import type { ComponentType } from 'react';
|
|
11
|
+
|
|
12
|
+
type AgentLink = {
|
|
13
|
+
title: string;
|
|
14
|
+
href: string;
|
|
15
|
+
icon: ComponentType<{ className?: string }>;
|
|
16
|
+
description?: string;
|
|
17
|
+
target?: '_blank' | '_self';
|
|
18
|
+
rel?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const getAgentLinks = (agentName: string): AgentLink[] => {
|
|
22
|
+
const encodedName = encodeURIComponent(agentName);
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
title: 'Chat with Agent',
|
|
26
|
+
href: `/agents/${encodedName}`,
|
|
27
|
+
icon: MessageSquareIcon,
|
|
28
|
+
description: 'Direct interface to converse with the agent.',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: 'Edit Book',
|
|
32
|
+
href: `/agents/${encodedName}/book`,
|
|
33
|
+
icon: NotebookPenIcon,
|
|
34
|
+
description: "Edit the agent's knowledge book.",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
title: 'Integration',
|
|
38
|
+
href: `/agents/${encodedName}/integration`,
|
|
39
|
+
icon: CodeIcon,
|
|
40
|
+
description: 'Learn how to integrate this agent into your applications.',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
title: 'History & Feedback',
|
|
44
|
+
href: `/agents/${encodedName}/history`,
|
|
45
|
+
icon: HistoryIcon,
|
|
46
|
+
description: 'View past conversations and provide feedback.',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
title: 'All Links',
|
|
50
|
+
href: `/agents/${encodedName}/links`,
|
|
51
|
+
icon: LinkIcon,
|
|
52
|
+
description: 'Signpost & Links',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
title: 'Website Integration',
|
|
56
|
+
href: `/agents/${encodedName}/website-integration`,
|
|
57
|
+
icon: GlobeIcon,
|
|
58
|
+
description: 'Embed the agent chat widget directly into your React application.',
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const getAgentExternalLinks = (): AgentLink[] => [
|
|
64
|
+
{
|
|
65
|
+
title: 'Promptbook Studio',
|
|
66
|
+
href: 'https://promptbook.studio',
|
|
67
|
+
icon: BookOpenIcon,
|
|
68
|
+
description: 'Create and manage your own agents',
|
|
69
|
+
target: '_blank',
|
|
70
|
+
rel: 'noopener noreferrer',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
title: 'GitHub Repository',
|
|
74
|
+
href: 'https://github.com/webgptorg/promptbook',
|
|
75
|
+
icon: CodeIcon,
|
|
76
|
+
description: 'Star us and contribute to the project',
|
|
77
|
+
target: '_blank',
|
|
78
|
+
rel: 'noopener noreferrer',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
2
|
+
import { resolveInheritedAgentSource } from '@/src/utils/resolveInheritedAgentSource';
|
|
2
3
|
import { padBook, validateBook } from '@promptbook-local/core';
|
|
3
4
|
import { serializeError } from '@promptbook-local/utils';
|
|
4
5
|
import spaceTrim from 'spacetrim';
|
|
@@ -13,8 +14,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
13
14
|
try {
|
|
14
15
|
const collection = await $provideAgentCollectionForServer();
|
|
15
16
|
const agentSource = await collection.getAgentSource(agentName);
|
|
17
|
+
const effectiveAgentSource = await resolveInheritedAgentSource(agentSource, collection);
|
|
16
18
|
|
|
17
|
-
return new Response(
|
|
19
|
+
return new Response(effectiveAgentSource, {
|
|
18
20
|
status: 200,
|
|
19
21
|
headers: { 'Content-Type': 'text/plain' /* <- TODO: [🎳] Mime type of book */ },
|
|
20
22
|
});
|
|
@@ -77,11 +77,15 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
77
77
|
userAgent,
|
|
78
78
|
language,
|
|
79
79
|
platform,
|
|
80
|
+
source: 'AGENT_PAGE_CHAT',
|
|
81
|
+
apiKey: null,
|
|
80
82
|
});
|
|
81
83
|
|
|
82
84
|
const encoder = new TextEncoder();
|
|
83
85
|
const readableStream = new ReadableStream({
|
|
84
86
|
start(controller) {
|
|
87
|
+
let previousContent = '';
|
|
88
|
+
|
|
85
89
|
agent.callChatModelStream!(
|
|
86
90
|
{
|
|
87
91
|
title: `Chat with agent ${
|
|
@@ -95,7 +99,11 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
95
99
|
thread,
|
|
96
100
|
},
|
|
97
101
|
(chunk) => {
|
|
98
|
-
|
|
102
|
+
const fullContent = chunk.content;
|
|
103
|
+
const deltaContent = fullContent.substring(previousContent.length);
|
|
104
|
+
previousContent = fullContent;
|
|
105
|
+
|
|
106
|
+
controller.enqueue(encoder.encode(deltaContent));
|
|
99
107
|
},
|
|
100
108
|
)
|
|
101
109
|
.then(async (response) => {
|
|
@@ -119,6 +127,8 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
119
127
|
userAgent,
|
|
120
128
|
language,
|
|
121
129
|
platform,
|
|
130
|
+
source: 'AGENT_PAGE_CHAT',
|
|
131
|
+
apiKey: null,
|
|
122
132
|
});
|
|
123
133
|
|
|
124
134
|
// Note: [🐱🚀] Save the learned data
|