@promptbook/cli 0.104.0-1 → 0.104.0-11
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/next.config.ts +2 -2
- package/apps/agents-server/package.json +7 -3
- package/apps/agents-server/public/fonts/OpenMoji-color-cbdt.woff2 +0 -0
- package/apps/agents-server/public/swagger.json +115 -0
- package/apps/agents-server/scripts/generate-reserved-paths/generate-reserved-paths.ts +54 -0
- package/apps/agents-server/scripts/generate-reserved-paths/tsconfig.json +19 -0
- package/apps/agents-server/src/app/AddAgentButton.tsx +47 -21
- package/apps/agents-server/src/app/actions.ts +22 -5
- package/apps/agents-server/src/app/admin/browser-test/BrowserTestClient.tsx +211 -0
- package/apps/agents-server/src/app/admin/browser-test/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +221 -274
- package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +94 -137
- package/apps/agents-server/src/app/admin/files/FilesGalleryClient.tsx +263 -0
- package/apps/agents-server/src/app/admin/files/actions.ts +61 -0
- package/apps/agents-server/src/app/admin/files/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/image-generator-test/ImageGeneratorTestClient.tsx +169 -0
- package/apps/agents-server/src/app/admin/image-generator-test/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/images/ImagesGalleryClient.tsx +256 -0
- package/apps/agents-server/src/app/admin/images/actions.ts +60 -0
- package/apps/agents-server/src/app/admin/images/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/messages/MessagesClient.tsx +294 -0
- package/apps/agents-server/src/app/admin/messages/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/messages/send-email/SendEmailClient.tsx +104 -0
- package/apps/agents-server/src/app/admin/messages/send-email/actions.ts +35 -0
- package/apps/agents-server/src/app/admin/messages/send-email/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +23 -19
- package/apps/agents-server/src/app/admin/search-engine-test/SearchEngineTestClient.tsx +109 -0
- package/apps/agents-server/src/app/admin/search-engine-test/actions.ts +17 -0
- package/apps/agents-server/src/app/admin/search-engine-test/page.tsx +13 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +15 -1
- package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +51 -9
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +47 -4
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +53 -11
- package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +23 -3
- package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +8 -8
- package/apps/agents-server/src/app/agents/[agentName]/api/agents/route.ts +17 -26
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +4 -2
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +20 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +6 -11
- package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +5 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +5 -2
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +20 -16
- package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +15 -2
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +15 -2
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +12 -0
- package/apps/agents-server/src/app/agents/[agentName]/code/api/route.ts +68 -0
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +223 -0
- package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +5 -0
- package/apps/agents-server/src/app/agents/[agentName]/history/actions.ts +2 -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/getAgentDefaultAvatarPrompt.ts +31 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +194 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +14 -2
- package/apps/agents-server/src/app/agents/[agentName]/images/page.tsx +200 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +10 -3
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +11 -4
- package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +11 -2
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +18 -10
- package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +100 -0
- package/apps/agents-server/src/app/api/admin-email/route.ts +12 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +13 -14
- package/apps/agents-server/src/app/api/agents/[agentName]/restore/route.ts +20 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +43 -1
- package/apps/agents-server/src/app/api/agents/route.ts +28 -3
- package/apps/agents-server/src/app/api/api-tokens/route.ts +6 -7
- package/apps/agents-server/src/app/api/browser-test/act/route.ts +141 -0
- 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/api/docs/book.md/route.ts +61 -0
- package/apps/agents-server/src/app/api/emails/incoming/sendgrid/route.ts +48 -0
- package/apps/agents-server/src/app/api/federated-agents/route.ts +12 -0
- package/apps/agents-server/src/app/api/images/[filename]/route.ts +128 -0
- package/apps/agents-server/src/app/api/messages/route.ts +102 -0
- package/apps/agents-server/src/app/api/metadata/route.ts +5 -6
- package/apps/agents-server/src/app/api/upload/route.ts +128 -45
- package/apps/agents-server/src/app/docs/[docId]/page.tsx +2 -3
- package/apps/agents-server/src/app/docs/page.tsx +12 -12
- package/apps/agents-server/src/app/globals.css +140 -33
- package/apps/agents-server/src/app/humans.txt/route.ts +1 -1
- package/apps/agents-server/src/app/layout.tsx +27 -22
- package/apps/agents-server/src/app/page.tsx +54 -6
- package/apps/agents-server/src/app/recycle-bin/actions.ts +20 -14
- package/apps/agents-server/src/app/recycle-bin/page.tsx +27 -41
- 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 +9 -7
- package/apps/agents-server/src/app/swagger/page.tsx +14 -0
- package/apps/agents-server/src/components/AgentProfile/AgentCapabilityChips.tsx +38 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +44 -116
- package/apps/agents-server/src/components/AgentProfile/AgentProfileImage.tsx +92 -0
- package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +0 -1
- package/apps/agents-server/src/components/AgentProfile/useAgentBackground.ts +97 -0
- package/apps/agents-server/src/components/Auth/AuthControls.tsx +5 -4
- package/apps/agents-server/src/components/DeletedAgentBanner.tsx +26 -0
- package/apps/agents-server/src/components/DocsToolbar/DocsToolbar.tsx +38 -0
- package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +11 -9
- package/apps/agents-server/src/components/Footer/Footer.tsx +5 -5
- package/apps/agents-server/src/components/ForgottenPasswordDialog/ForgottenPasswordDialog.tsx +61 -0
- package/apps/agents-server/src/components/Header/Header.tsx +130 -40
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +150 -23
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +93 -15
- package/apps/agents-server/src/components/Homepage/DeletedAgentsList.tsx +66 -0
- 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/LayoutWrapper/LayoutWrapper.tsx +3 -2
- package/apps/agents-server/src/components/LoginForm/LoginForm.tsx +50 -1
- package/apps/agents-server/src/components/NewAgentDialog/NewAgentDialog.tsx +88 -0
- package/apps/agents-server/src/components/NotFoundPage/NotFoundPage.tsx +7 -2
- package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +16 -7
- package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +4 -4
- package/apps/agents-server/src/components/RegisterUserDialog/RegisterUserDialog.tsx +61 -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/components/_utils/headlessParam.tsx +7 -3
- package/apps/agents-server/src/database/$getTableName.ts +1 -0
- package/apps/agents-server/src/database/$provideSupabaseForBrowser.ts +3 -3
- package/apps/agents-server/src/database/$provideSupabaseForServer.ts +1 -1
- package/apps/agents-server/src/database/$provideSupabaseForWorker.ts +3 -3
- package/apps/agents-server/src/database/metadataDefaults.ts +19 -1
- package/apps/agents-server/src/database/migrate.ts +34 -1
- package/apps/agents-server/src/database/migrations/2025-11-0001-initial-schema.sql +1 -3
- package/apps/agents-server/src/database/migrations/2025-11-0002-metadata-table.sql +1 -3
- package/apps/agents-server/src/database/migrations/2025-12-0240-agent-public-id.sql +3 -0
- package/apps/agents-server/src/database/migrations/2025-12-0360-agent-deleted-at.sql +1 -0
- package/apps/agents-server/src/database/migrations/2025-12-0370-image-table.sql +19 -0
- package/apps/agents-server/src/database/migrations/2025-12-0380-agent-visibility.sql +1 -0
- package/apps/agents-server/src/database/migrations/2025-12-0390-upload-tracking.sql +20 -0
- package/apps/agents-server/src/database/migrations/2025-12-0401-file-upload-status.sql +13 -0
- package/apps/agents-server/src/database/migrations/2025-12-0402-message-table.sql +42 -0
- package/apps/agents-server/src/database/migrations/2025-12-0403-generation-lock-table.sql +15 -0
- package/apps/agents-server/src/database/migrations/2025-12-0640-openai-assistant-cache.sql +12 -0
- package/apps/agents-server/src/database/migrations/2025-12-0820-agent-history-permanent-id.sql +29 -0
- package/apps/agents-server/src/database/migrations/2025-12-0830-image-purpose.sql +5 -0
- package/apps/agents-server/src/database/migrations/2025-12-0890-file-agent-id.sql +5 -0
- package/apps/agents-server/src/database/schema.ts +244 -4
- package/apps/agents-server/src/generated/reservedPaths.ts +32 -0
- package/apps/agents-server/src/message-providers/email/_common/Email.ts +73 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/TODO.txt +1 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.test.ts.todo +108 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.ts +62 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.test.ts.todo +117 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.test.ts.todo +119 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.test.ts.todo +74 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.ts +14 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/SendgridMessageProvider.ts +44 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/parseInboundSendgridEmail.ts +49 -0
- package/apps/agents-server/src/message-providers/email/zeptomail/ZeptomailMessageProvider.ts +51 -0
- package/apps/agents-server/src/message-providers/index.ts +13 -0
- package/apps/agents-server/src/message-providers/interfaces/MessageProvider.ts +11 -0
- package/apps/agents-server/src/middleware.ts +19 -23
- package/apps/agents-server/src/tools/$provideBrowserForServer.ts +32 -0
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +7 -2
- package/apps/agents-server/src/utils/auth.ts +117 -17
- package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +57 -0
- package/apps/agents-server/src/utils/cdn/classes/VercelBlobStorage.ts +4 -0
- package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +18 -0
- package/apps/agents-server/src/utils/content/extractBodyContentFromHtml.ts +19 -0
- package/apps/agents-server/src/utils/getUserIdFromRequest.ts +35 -0
- package/apps/agents-server/src/utils/handleChatCompletion.ts +65 -5
- package/apps/agents-server/src/utils/messages/sendMessage.ts +91 -0
- package/apps/agents-server/src/utils/messagesAdmin.ts +72 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.test.ts +36 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.ts +25 -0
- package/apps/agents-server/src/utils/validateApiKey.ts +7 -11
- package/esm/index.es.js +1534 -1330
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +8 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/types.index.d.ts +16 -2
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +29 -1
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
- 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 +3 -3
- package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +5 -1
- package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/esm/typings/src/book-components/Chat/CodeBlock/CodeBlock.d.ts +13 -0
- package/esm/typings/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
- package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +9 -13
- package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +3 -3
- package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +1 -1
- package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
- package/esm/typings/src/book-components/icons/AboutIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/AttachmentIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/CameraIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/DownloadIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/MenuIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/SaveIcon.d.ts +1 -1
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +22 -12
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +27 -15
- package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
- package/esm/typings/src/commitments/index.d.ts +2 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +1 -1
- package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +6 -1
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
- package/esm/typings/src/remote-server/ui/ServerApp.d.ts +1 -1
- package/esm/typings/src/search-engines/SearchEngine.d.ts +9 -0
- package/esm/typings/src/search-engines/SearchResult.d.ts +18 -0
- package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +15 -0
- package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +15 -0
- package/esm/typings/src/types/Message.d.ts +49 -0
- package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
- package/esm/typings/src/types/typeAliases.d.ts +23 -1
- package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
- package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
- package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
- package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
- package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
- package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +3 -2
- package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +1542 -1338
- package/umd/index.umd.js.map +1 -1
- package/apps/agents-server/package-lock.json +0 -27
- package/apps/agents-server/public/fonts/download-font.js +0 -22
- package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +0 -18
- package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
import { $provideServer } from '@/src/tools/$provideServer';
|
|
4
4
|
import { isUserAdmin } from '@/src/utils/isUserAdmin';
|
|
5
5
|
import { saturate } from '@promptbook-local/color';
|
|
6
|
-
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
6
|
+
import { generatePlaceholderAgentProfileImageUrl, NotFoundError, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
7
7
|
import { notFound } from 'next/navigation';
|
|
8
8
|
import { Color } from '../../../../../../src/utils/color/Color';
|
|
9
|
-
import {
|
|
9
|
+
import { DeletedAgentBanner } from '../../../components/DeletedAgentBanner';
|
|
10
|
+
import { getAgentName, getAgentProfile, isAgentDeleted } from './_utils';
|
|
10
11
|
import { getAgentLinks } from './agentLinks';
|
|
11
12
|
import { AgentProfileChat } from './AgentProfileChat';
|
|
12
13
|
import { AgentProfileWrapper } from './AgentProfileWrapper';
|
|
@@ -26,24 +27,24 @@ export default async function AgentPage({
|
|
|
26
27
|
const isAdmin = await isUserAdmin();
|
|
27
28
|
const { headless: headlessParam } = await searchParams;
|
|
28
29
|
const isHeadless = headlessParam !== undefined;
|
|
30
|
+
const { publicUrl } = await $provideServer();
|
|
29
31
|
|
|
30
32
|
let agentProfile;
|
|
31
33
|
try {
|
|
32
34
|
agentProfile = await getAgentProfile(agentName);
|
|
33
35
|
} catch (error) {
|
|
34
36
|
if (
|
|
35
|
-
error instanceof
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
error.message.includes('
|
|
37
|
+
error instanceof NotFoundError ||
|
|
38
|
+
(error instanceof Error &&
|
|
39
|
+
// Note: This is a bit hacky, but valid way to check for specific error message
|
|
40
|
+
(error.message.includes('Cannot coerce the result to a single JSON object') ||
|
|
41
|
+
error.message.includes('JSON object requested, multiple (or no) results returned')))
|
|
39
42
|
) {
|
|
40
43
|
notFound();
|
|
41
44
|
}
|
|
42
45
|
throw error;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
const { publicUrl } = await $provideServer();
|
|
46
|
-
|
|
47
48
|
// Build agent page URL for QR and copy
|
|
48
49
|
const agentUrl = `${publicUrl.href}${encodeURIComponent(agentName)}`;
|
|
49
50
|
// <- TODO: [🐱🚀] Better
|
|
@@ -54,6 +55,7 @@ export default async function AgentPage({
|
|
|
54
55
|
const brandColorHex = brandColor.then(saturate(-0.5)).toHex();
|
|
55
56
|
|
|
56
57
|
const fullname = (agentProfile.meta.fullname || agentProfile.agentName || 'Agent') as string;
|
|
58
|
+
const isDeleted = await isAgentDeleted(agentName);
|
|
57
59
|
|
|
58
60
|
return (
|
|
59
61
|
<>
|
|
@@ -61,6 +63,7 @@ export default async function AgentPage({
|
|
|
61
63
|
<AgentProfileWrapper
|
|
62
64
|
agent={agentProfile}
|
|
63
65
|
agentUrl={agentUrl}
|
|
66
|
+
publicUrl={publicUrl}
|
|
64
67
|
agentEmail={agentEmail}
|
|
65
68
|
agentName={agentName}
|
|
66
69
|
brandColorHex={brandColorHex}
|
|
@@ -68,7 +71,7 @@ export default async function AgentPage({
|
|
|
68
71
|
isHeadless={isHeadless}
|
|
69
72
|
actions={
|
|
70
73
|
<>
|
|
71
|
-
{getAgentLinks(agentName)
|
|
74
|
+
{getAgentLinks(agentProfile.permanentId || agentName)
|
|
72
75
|
.filter((link) => ['Edit Book', 'Integration', 'All Links'].includes(link.title))
|
|
73
76
|
.map((link) => (
|
|
74
77
|
<a
|
|
@@ -86,12 +89,17 @@ export default async function AgentPage({
|
|
|
86
89
|
</>
|
|
87
90
|
}
|
|
88
91
|
>
|
|
92
|
+
{isDeleted && <DeletedAgentBanner />}
|
|
89
93
|
<AgentProfileChat
|
|
90
94
|
agentUrl={agentUrl}
|
|
91
95
|
agentName={agentName}
|
|
92
96
|
fullname={fullname}
|
|
93
97
|
brandColorHex={brandColorHex}
|
|
94
|
-
avatarSrc={
|
|
98
|
+
avatarSrc={
|
|
99
|
+
agentProfile.meta.image ||
|
|
100
|
+
generatePlaceholderAgentProfileImageUrl(agentProfile.permanentId || agentName, publicUrl)
|
|
101
|
+
}
|
|
102
|
+
isDeleted={isDeleted}
|
|
95
103
|
/>
|
|
96
104
|
</AgentProfileWrapper>
|
|
97
105
|
</>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
4
|
+
import { $provideServer } from '@/src/tools/$provideServer';
|
|
5
|
+
import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
|
|
6
|
+
import { ArrowLeftIcon, FileTextIcon } from 'lucide-react';
|
|
7
|
+
import { headers } from 'next/headers';
|
|
8
|
+
import Link from 'next/link';
|
|
9
|
+
import { notFound } from 'next/navigation';
|
|
10
|
+
import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
|
|
11
|
+
import { getAgentName, getAgentProfile } from '../_utils';
|
|
12
|
+
import { generateAgentMetadata } from '../generateAgentMetadata';
|
|
13
|
+
|
|
14
|
+
export const generateMetadata = generateAgentMetadata;
|
|
15
|
+
|
|
16
|
+
export default async function AgentSystemMessagePage({ params }: { params: Promise<{ agentName: string }> }) {
|
|
17
|
+
$sideEffect(headers());
|
|
18
|
+
|
|
19
|
+
const { publicUrl } = await $provideServer();
|
|
20
|
+
|
|
21
|
+
const agentName = await getAgentName(params);
|
|
22
|
+
|
|
23
|
+
let agentProfile;
|
|
24
|
+
let agentSource;
|
|
25
|
+
try {
|
|
26
|
+
agentProfile = await getAgentProfile(agentName);
|
|
27
|
+
const collection = await $provideAgentCollectionForServer();
|
|
28
|
+
agentSource = await collection.getAgentSource(agentName);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (
|
|
31
|
+
error instanceof Error &&
|
|
32
|
+
(error.message.includes('Cannot coerce the result to a single JSON object') ||
|
|
33
|
+
error.message.includes('JSON object requested, multiple (or no) results returned'))
|
|
34
|
+
) {
|
|
35
|
+
notFound();
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// For now, we'll display the agent source as the system message
|
|
41
|
+
// TODO: [🧠] This might need to be the actual generated system message from the Agent class
|
|
42
|
+
const systemMessage = agentSource || 'No system message available';
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="min-h-screen p-6 md:p-12 flex flex-col items-center bg-gray-50">
|
|
46
|
+
<div className="w-full max-w-4xl bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
|
|
47
|
+
{/* Header */}
|
|
48
|
+
<div className="p-6 border-b border-gray-200 flex items-center gap-4">
|
|
49
|
+
{agentProfile.meta.image && (
|
|
50
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
51
|
+
<img
|
|
52
|
+
src={
|
|
53
|
+
agentProfile.meta.image ||
|
|
54
|
+
generatePlaceholderAgentProfileImageUrl(
|
|
55
|
+
agentProfile.permanentId || agentName,
|
|
56
|
+
publicUrl,
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
alt={agentProfile.meta.fullname || agentName}
|
|
60
|
+
className="w-16 h-16 rounded-full object-cover border-2 border-gray-200"
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
<div className="flex-1">
|
|
64
|
+
<h1 className="text-2xl font-bold text-gray-900">{agentProfile.meta.fullname || agentName}</h1>
|
|
65
|
+
<p className="text-gray-500 flex items-center gap-2">
|
|
66
|
+
<FileTextIcon className="w-4 h-4" />
|
|
67
|
+
System Message
|
|
68
|
+
</p>
|
|
69
|
+
</div>
|
|
70
|
+
<Link
|
|
71
|
+
href={`/agents/${encodeURIComponent(agentName)}`}
|
|
72
|
+
className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full transition-colors"
|
|
73
|
+
title="Back to Agent"
|
|
74
|
+
>
|
|
75
|
+
<ArrowLeftIcon className="w-6 h-6" />
|
|
76
|
+
</Link>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div className="p-6">
|
|
80
|
+
<div className="bg-gray-50 rounded-lg p-4 border border-gray-200">
|
|
81
|
+
<h2 className="text-lg font-semibold text-gray-900 mb-3">Generated System Message</h2>
|
|
82
|
+
<pre className="text-sm text-gray-700 whitespace-pre-wrap font-mono bg-white p-4 rounded border border-gray-200 overflow-x-auto">
|
|
83
|
+
{systemMessage}
|
|
84
|
+
</pre>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div className="mt-6 bg-blue-50 rounded-lg p-4 border border-blue-200">
|
|
88
|
+
<h3 className="text-md font-semibold text-blue-900 mb-2">Model Requirements</h3>
|
|
89
|
+
<div className="text-sm text-blue-800">
|
|
90
|
+
<p>
|
|
91
|
+
<strong>Model Variant:</strong> CHAT
|
|
92
|
+
</p>
|
|
93
|
+
{/* TODO: [🧠] Add more model requirements if available */}
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getMetadata } from '../../../database/getMetadata';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const adminEmail = await getMetadata('ADMIN_EMAIL');
|
|
7
|
+
return NextResponse.json({ adminEmail });
|
|
8
|
+
} catch (error) {
|
|
9
|
+
console.error('Failed to get admin email:', error);
|
|
10
|
+
return NextResponse.json({ adminEmail: 'support@ptbk.io' }, { status: 500 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
// POST /api/agents/[agentName]/clone
|
|
2
1
|
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
3
|
-
import { AgentBasicInformation } from '../../../../../../../../src/book-2.0/agent-source/AgentBasicInformation';
|
|
4
|
-
import { string_book } from '../../../../../../../../src/book-2.0/agent-source/string_book';
|
|
5
2
|
import { TODO_any } from '@promptbook-local/types';
|
|
6
3
|
import { NextResponse } from 'next/server';
|
|
4
|
+
import { string_book } from '../../../../../../../../src/book-2.0/agent-source/string_book';
|
|
7
5
|
|
|
8
6
|
export async function POST(request: Request, { params }: { params: Promise<{ agentName: string }> }) {
|
|
9
7
|
const { agentName } = await params;
|
|
10
8
|
const collection = await $provideAgentCollectionForServer();
|
|
11
9
|
|
|
12
10
|
try {
|
|
13
|
-
const
|
|
11
|
+
const agentId = await collection.getAgentPermanentId(agentName);
|
|
12
|
+
const source = await collection.getAgentSource(agentId);
|
|
14
13
|
|
|
15
14
|
// Generate new name
|
|
16
15
|
// TODO: [🧠] Better naming strategy, maybe check for collisions
|
|
@@ -20,15 +19,15 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
20
19
|
// eslint-disable-next-line no-constant-condition
|
|
21
20
|
while (true) {
|
|
22
21
|
try {
|
|
23
|
-
await collection.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
await collection.getAgentPermanentId(newAgentName);
|
|
23
|
+
// If success, it means it exists, so we try next one
|
|
24
|
+
counter++;
|
|
25
|
+
newAgentName = `${agentName} (Copy ${counter})`;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// If error, it likely means it does not exist (NotFoundError), so we can use it
|
|
28
|
+
// TODO: [🧠] Check if it is really NotFoundError
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
const lines = source.split('\n');
|
|
@@ -36,7 +35,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
36
35
|
const newSource = lines.join('\n') as string_book;
|
|
37
36
|
|
|
38
37
|
const newAgent = await collection.createAgent(newSource);
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
return NextResponse.json(newAgent);
|
|
41
40
|
} catch (error) {
|
|
42
41
|
return NextResponse.json(
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// POST /api/agents/[agentName]/restore - restore deleted agent
|
|
2
|
+
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
3
|
+
import { TODO_any } from '@promptbook-local/types';
|
|
4
|
+
import { NextResponse } from 'next/server';
|
|
5
|
+
|
|
6
|
+
export async function POST(request: Request, { params }: { params: Promise<{ agentName: string }> }) {
|
|
7
|
+
const { agentName } = await params;
|
|
8
|
+
const collection = await $provideAgentCollectionForServer();
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const agentId = await collection.getAgentPermanentId(agentName);
|
|
12
|
+
await collection.restoreAgent(agentId);
|
|
13
|
+
return NextResponse.json({ success: true });
|
|
14
|
+
} catch (error) {
|
|
15
|
+
return NextResponse.json(
|
|
16
|
+
{ success: false, error: (error as TODO_any)?.message || 'Failed to restore agent' },
|
|
17
|
+
{ status: 500 },
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,14 +1,56 @@
|
|
|
1
1
|
// DELETE /api/agents/[agentName]
|
|
2
|
+
// PATCH /api/agents/[agentName] - update agent visibility
|
|
3
|
+
// POST /api/agents/[agentName]/restore - restore deleted agent
|
|
4
|
+
import { $getTableName } from '@/src/database/$getTableName';
|
|
5
|
+
import { $provideSupabaseForServer } from '@/src/database/$provideSupabaseForServer';
|
|
2
6
|
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
3
7
|
import { TODO_any } from '@promptbook-local/types';
|
|
4
8
|
import { NextResponse } from 'next/server';
|
|
5
9
|
|
|
10
|
+
export async function PATCH(request: Request, { params }: { params: Promise<{ agentName: string }> }) {
|
|
11
|
+
const { agentName } = await params;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const body = await request.json();
|
|
15
|
+
const { visibility }: { visibility: 'PUBLIC' | 'PRIVATE' } = body;
|
|
16
|
+
|
|
17
|
+
if (!visibility || !['PUBLIC', 'PRIVATE'].includes(visibility)) {
|
|
18
|
+
return NextResponse.json(
|
|
19
|
+
{ success: false, error: 'Invalid visibility value. Must be PUBLIC or PRIVATE.' },
|
|
20
|
+
{ status: 400 },
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const supabase = $provideSupabaseForServer();
|
|
25
|
+
// const { tablePrefix } = await $provideServer();
|
|
26
|
+
|
|
27
|
+
const updateResult = await supabase
|
|
28
|
+
.from(await $getTableName(`Agent`))
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
.update({ visibility } as any)
|
|
31
|
+
.or(`agentName.eq.${agentName},permanentId.eq.${agentName}`)
|
|
32
|
+
.is('deletedAt', null);
|
|
33
|
+
|
|
34
|
+
if (updateResult.error) {
|
|
35
|
+
return NextResponse.json({ success: false, error: updateResult.error.message }, { status: 500 });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return NextResponse.json({ success: true });
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return NextResponse.json(
|
|
41
|
+
{ success: false, error: (error as TODO_any)?.message || 'Failed to update agent visibility' },
|
|
42
|
+
{ status: 500 },
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
6
47
|
export async function DELETE(request: Request, { params }: { params: Promise<{ agentName: string }> }) {
|
|
7
48
|
const { agentName } = await params;
|
|
8
49
|
const collection = await $provideAgentCollectionForServer();
|
|
9
50
|
|
|
10
51
|
try {
|
|
11
|
-
await collection.
|
|
52
|
+
const agentId = await collection.getAgentPermanentId(agentName);
|
|
53
|
+
await collection.deleteAgent(agentId);
|
|
12
54
|
return NextResponse.json({ success: true });
|
|
13
55
|
} catch (error) {
|
|
14
56
|
return NextResponse.json(
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { $getTableName } from '@/src/database/$getTableName';
|
|
1
2
|
import { $provideServer } from '@/src/tools/$provideServer';
|
|
2
3
|
import { NextResponse } from 'next/server';
|
|
4
|
+
import { $provideSupabaseForServer } from '../../../database/$provideSupabaseForServer';
|
|
3
5
|
import { $provideAgentCollectionForServer } from '../../../tools/$provideAgentCollectionForServer';
|
|
4
6
|
import { getFederatedServersFromMetadata } from '../../../utils/getFederatedServersFromMetadata';
|
|
5
7
|
|
|
@@ -8,13 +10,36 @@ export const dynamic = 'force-dynamic';
|
|
|
8
10
|
export async function GET() {
|
|
9
11
|
try {
|
|
10
12
|
const collection = await $provideAgentCollectionForServer();
|
|
11
|
-
const
|
|
13
|
+
const allAgents = await collection.listAgents();
|
|
12
14
|
const federatedServers = await getFederatedServersFromMetadata();
|
|
13
15
|
const { publicUrl } = await $provideServer();
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
// Filter to only include PUBLIC agents for federated API
|
|
18
|
+
const supabase = $provideSupabaseForServer();
|
|
19
|
+
const visibilityResult = await supabase
|
|
20
|
+
.from(await $getTableName(`Agent`))
|
|
21
|
+
.select('agentName, visibility')
|
|
22
|
+
.is('deletedAt', null);
|
|
23
|
+
|
|
24
|
+
let publicAgents = allAgents;
|
|
25
|
+
if (!visibilityResult.error) {
|
|
26
|
+
const visibilityMap = new Map(
|
|
27
|
+
visibilityResult.data.map((item: { agentName: string; visibility: 'PUBLIC' | 'PRIVATE' }) => [
|
|
28
|
+
item.agentName,
|
|
29
|
+
item.visibility,
|
|
30
|
+
]),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Only include PUBLIC agents in federated API
|
|
34
|
+
publicAgents = allAgents.filter((agent) => {
|
|
35
|
+
const visibility = visibilityMap.get(agent.agentName);
|
|
36
|
+
return visibility === 'PUBLIC';
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const agentsWithUrl = publicAgents.map((agent) => ({
|
|
16
41
|
...agent,
|
|
17
|
-
url: `${publicUrl.href}agents/${encodeURIComponent(agent.agentName)}`,
|
|
42
|
+
url: `${publicUrl.href}agents/${encodeURIComponent(agent.permanentId || agent.agentName)}`,
|
|
18
43
|
}));
|
|
19
44
|
|
|
20
45
|
const response = NextResponse.json({
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { keepUnused } from '../../../../../../src/utils/organization/keepUnused';
|
|
1
4
|
import { $getTableName } from '../../../database/$getTableName';
|
|
2
5
|
import { $provideSupabase } from '../../../database/$provideSupabase';
|
|
3
6
|
import { isUserAdmin } from '../../../utils/isUserAdmin';
|
|
4
|
-
import { randomUUID } from 'crypto';
|
|
5
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
6
7
|
|
|
7
8
|
export async function GET(request: NextRequest) {
|
|
9
|
+
keepUnused(request);
|
|
10
|
+
|
|
8
11
|
if (!(await isUserAdmin())) {
|
|
9
12
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
10
13
|
}
|
|
@@ -35,11 +38,7 @@ export async function POST(request: NextRequest) {
|
|
|
35
38
|
const supabase = $provideSupabase();
|
|
36
39
|
const table = await $getTableName('ApiTokens');
|
|
37
40
|
|
|
38
|
-
const { data, error } = await supabase
|
|
39
|
-
.from(table)
|
|
40
|
-
.insert({ token, note })
|
|
41
|
-
.select()
|
|
42
|
-
.single();
|
|
41
|
+
const { data, error } = await supabase.from(table).insert({ token, note }).select().single();
|
|
43
42
|
|
|
44
43
|
if (error) {
|
|
45
44
|
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { $provideBrowserForServer } from '@/src/tools/$provideBrowserForServer';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { OpenAI } from 'openai';
|
|
4
|
+
|
|
5
|
+
export const maxDuration = 60; // Allow longer timeout for agent actions
|
|
6
|
+
|
|
7
|
+
export async function POST(request: NextRequest) {
|
|
8
|
+
try {
|
|
9
|
+
const { goal, action, plan } = await request.json();
|
|
10
|
+
|
|
11
|
+
if (!goal) {
|
|
12
|
+
return NextResponse.json({ error: 'Goal is required' }, { status: 400 });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const browserContext = await $provideBrowserForServer();
|
|
16
|
+
const pages = browserContext.pages();
|
|
17
|
+
let page = pages[0];
|
|
18
|
+
|
|
19
|
+
if (!page) {
|
|
20
|
+
page = await browserContext.newPage();
|
|
21
|
+
await page.goto('https://www.facebook.com/');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Ensure we are on Facebook
|
|
25
|
+
if (!page.url().includes('facebook.com')) {
|
|
26
|
+
await page.goto('https://www.facebook.com/');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const openai = new OpenAI({
|
|
30
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Get page context (simplified for now: just text content)
|
|
34
|
+
// In a real scenario, we would use accessibility tree or screenshots
|
|
35
|
+
const pageText = await page.evaluate(() => document.body.innerText.slice(0, 10000)); // Limit text size
|
|
36
|
+
|
|
37
|
+
if (action === 'plan') {
|
|
38
|
+
const systemPrompt = `
|
|
39
|
+
You are an autonomous agent interacting with Facebook.
|
|
40
|
+
Your goal is to help the user achieve: "${goal}".
|
|
41
|
+
Analyze the current page content and propose a step-by-step plan.
|
|
42
|
+
Keep the plan concise and actionable.
|
|
43
|
+
Do not execute any actions yet, just list them.
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
const completion = await openai.chat.completions.create({
|
|
47
|
+
model: 'gpt-4o',
|
|
48
|
+
messages: [
|
|
49
|
+
{ role: 'system', content: systemPrompt },
|
|
50
|
+
{ role: 'user', content: `Current page text (truncated):\n${pageText}` },
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const plan = completion.choices[0].message.content;
|
|
55
|
+
return NextResponse.json({ plan });
|
|
56
|
+
} else if (action === 'execute') {
|
|
57
|
+
// This is a simplified execution. Ideally, this would be a loop.
|
|
58
|
+
// We ask the LLM to give us a JSON of actions to perform immediately.
|
|
59
|
+
|
|
60
|
+
const systemPrompt = `
|
|
61
|
+
You are an autonomous agent interacting with Facebook.
|
|
62
|
+
Your goal is to help the user achieve: "${goal}".
|
|
63
|
+
${plan ? `You have previously agreed to this plan:\n${plan}\n\n` : ''}
|
|
64
|
+
Based on the current page content, generate a list of low-level actions to perform NOW to advance the plan.
|
|
65
|
+
|
|
66
|
+
Supported actions:
|
|
67
|
+
- { "type": "click", "selector": "css selector", "description": "reason" }
|
|
68
|
+
- { "type": "type", "selector": "css selector", "text": "text to type", "description": "reason" }
|
|
69
|
+
- { "type": "scroll", "amount": number, "description": "reason" }
|
|
70
|
+
- { "type": "wait", "ms": number, "description": "reason" }
|
|
71
|
+
- { "type": "navigate", "url": "url", "description": "reason" }
|
|
72
|
+
|
|
73
|
+
Return a JSON object with a key "actions" containing an array of these actions.
|
|
74
|
+
Example: { "actions": [{ "type": "scroll", "amount": 500, "description": "scanning feed" }, { "type": "click", "selector": "...", "description": "liking post" }] }
|
|
75
|
+
|
|
76
|
+
IMPORTANT: Return ONLY valid JSON.
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
const completion = await openai.chat.completions.create({
|
|
80
|
+
model: 'gpt-4o',
|
|
81
|
+
messages: [
|
|
82
|
+
{ role: 'system', content: systemPrompt },
|
|
83
|
+
{ role: 'user', content: `Current page text (truncated):\n${pageText}` },
|
|
84
|
+
],
|
|
85
|
+
response_format: { type: 'json_object' },
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const responseContent = completion.choices[0].message.content;
|
|
89
|
+
if (!responseContent) {
|
|
90
|
+
throw new Error('No response from AI');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
94
|
+
const { actions } = JSON.parse(responseContent) as { actions: any[] };
|
|
95
|
+
const results = [];
|
|
96
|
+
|
|
97
|
+
for (const act of actions) {
|
|
98
|
+
console.log('Executing action:', act);
|
|
99
|
+
try {
|
|
100
|
+
if (act.type === 'click') {
|
|
101
|
+
// Try to find element and click
|
|
102
|
+
// We might need to use evaluate if selector is complex or text-based, but let's stick to CSS for now
|
|
103
|
+
// Or ask LLM to give text-based selector?
|
|
104
|
+
// Playwright's locator is powerful.
|
|
105
|
+
// Let's assume standard CSS selectors for now.
|
|
106
|
+
if (act.selector) {
|
|
107
|
+
// Try to wait for it briefly
|
|
108
|
+
await page.waitForSelector(act.selector, { timeout: 2000 });
|
|
109
|
+
await page.click(act.selector);
|
|
110
|
+
}
|
|
111
|
+
} else if (act.type === 'type') {
|
|
112
|
+
if (act.selector && act.text) {
|
|
113
|
+
await page.waitForSelector(act.selector, { timeout: 2000 });
|
|
114
|
+
await page.type(act.selector, act.text);
|
|
115
|
+
}
|
|
116
|
+
} else if (act.type === 'scroll') {
|
|
117
|
+
await page.evaluate((y) => window.scrollBy(0, y), act.amount || 500);
|
|
118
|
+
} else if (act.type === 'wait') {
|
|
119
|
+
await page.waitForTimeout(act.ms || 1000);
|
|
120
|
+
} else if (act.type === 'navigate') {
|
|
121
|
+
if (act.url) await page.goto(act.url);
|
|
122
|
+
}
|
|
123
|
+
results.push({ action: act, status: 'success' });
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Action failed:', act, error);
|
|
126
|
+
results.push({ action: act, status: 'error', error: String(error) });
|
|
127
|
+
}
|
|
128
|
+
// Small delay between actions
|
|
129
|
+
await page.waitForTimeout(500);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return NextResponse.json({ success: true, results });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return NextResponse.json({ error: 'Invalid action' }, { status: 400 });
|
|
136
|
+
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error('Error in Act on Facebook:', error);
|
|
139
|
+
return NextResponse.json({ error: String(error) }, { status: 500 });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { $provideBrowserForServer } from '@/src/tools/$provideBrowserForServer';
|
|
2
|
+
import { serializeError } from '@promptbook-local/utils';
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import { assertsError } from '../../../../../../../src/errors/assertsError';
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
try {
|
|
8
|
+
const browserContext = await $provideBrowserForServer();
|
|
9
|
+
|
|
10
|
+
const page = await browserContext.newPage();
|
|
11
|
+
|
|
12
|
+
await page.goto('https://ptbk.io');
|
|
13
|
+
const screenshotBuffer = await page.screenshot();
|
|
14
|
+
|
|
15
|
+
// await page.close();
|
|
16
|
+
// Do not close browser
|
|
17
|
+
// <- TODO: !!!! Fix
|
|
18
|
+
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
return new NextResponse(new Blob([screenshotBuffer as any]), {
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'image/png',
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
} catch (error) {
|
|
26
|
+
assertsError(error);
|
|
27
|
+
console.error('Error taking screenshot:', error);
|
|
28
|
+
return NextResponse.json({ error: serializeError(error) }, { status: 500 });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { $provideBrowserForServer } from '@/src/tools/$provideBrowserForServer';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
import { just } from '../../../../../../../src/utils/organization/just';
|
|
4
|
+
|
|
5
|
+
export const dynamic = 'force-dynamic';
|
|
6
|
+
|
|
7
|
+
export async function GET() {
|
|
8
|
+
const encoder = new TextEncoder();
|
|
9
|
+
const stream = new ReadableStream({
|
|
10
|
+
async start(controller) {
|
|
11
|
+
try {
|
|
12
|
+
console.log('Starting Facebook scroll session');
|
|
13
|
+
const browserContext = await $provideBrowserForServer();
|
|
14
|
+
const page = await browserContext.newPage();
|
|
15
|
+
|
|
16
|
+
await page.goto('https://www.facebook.com/');
|
|
17
|
+
console.log('Navigated to Facebook');
|
|
18
|
+
|
|
19
|
+
// Loop for streaming
|
|
20
|
+
while (just(true)) {
|
|
21
|
+
// Check for login (simple check for now)
|
|
22
|
+
// Facebook uses role="banner" for the top navigation bar when logged in
|
|
23
|
+
const isLoggedIn = await page.$('div[role="banner"]');
|
|
24
|
+
|
|
25
|
+
if (isLoggedIn) {
|
|
26
|
+
// Scroll down
|
|
27
|
+
await page.evaluate(() => window.scrollBy(0, 500));
|
|
28
|
+
// console.log('Scrolled');
|
|
29
|
+
} else {
|
|
30
|
+
// console.log('Waiting for login...');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const buffer = await page.screenshot({ type: 'jpeg', quality: 50 });
|
|
34
|
+
|
|
35
|
+
const boundary = '--myboundary';
|
|
36
|
+
const header = `\r\n${boundary}\r\nContent-Type: image/jpeg\r\nContent-Length: ${buffer.length}\r\n\r\n`;
|
|
37
|
+
|
|
38
|
+
controller.enqueue(encoder.encode(header));
|
|
39
|
+
controller.enqueue(buffer);
|
|
40
|
+
|
|
41
|
+
// Short delay
|
|
42
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Stream error:', error);
|
|
46
|
+
try {
|
|
47
|
+
controller.close();
|
|
48
|
+
} catch (e) {
|
|
49
|
+
// Ignore error if controller is already closed
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return new NextResponse(stream, {
|
|
56
|
+
headers: {
|
|
57
|
+
'Content-Type': 'multipart/x-mixed-replace; boundary=myboundary',
|
|
58
|
+
'Cache-Control': 'no-cache',
|
|
59
|
+
Connection: 'keep-alive',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|