@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.
Files changed (229) hide show
  1. package/apps/agents-server/config.ts +1 -3
  2. package/apps/agents-server/next.config.ts +2 -2
  3. package/apps/agents-server/package.json +7 -3
  4. package/apps/agents-server/public/fonts/OpenMoji-color-cbdt.woff2 +0 -0
  5. package/apps/agents-server/public/swagger.json +115 -0
  6. package/apps/agents-server/scripts/generate-reserved-paths/generate-reserved-paths.ts +54 -0
  7. package/apps/agents-server/scripts/generate-reserved-paths/tsconfig.json +19 -0
  8. package/apps/agents-server/src/app/AddAgentButton.tsx +47 -21
  9. package/apps/agents-server/src/app/actions.ts +22 -5
  10. package/apps/agents-server/src/app/admin/browser-test/BrowserTestClient.tsx +211 -0
  11. package/apps/agents-server/src/app/admin/browser-test/page.tsx +13 -0
  12. package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +221 -274
  13. package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +94 -137
  14. package/apps/agents-server/src/app/admin/files/FilesGalleryClient.tsx +263 -0
  15. package/apps/agents-server/src/app/admin/files/actions.ts +61 -0
  16. package/apps/agents-server/src/app/admin/files/page.tsx +13 -0
  17. package/apps/agents-server/src/app/admin/image-generator-test/ImageGeneratorTestClient.tsx +169 -0
  18. package/apps/agents-server/src/app/admin/image-generator-test/page.tsx +13 -0
  19. package/apps/agents-server/src/app/admin/images/ImagesGalleryClient.tsx +256 -0
  20. package/apps/agents-server/src/app/admin/images/actions.ts +60 -0
  21. package/apps/agents-server/src/app/admin/images/page.tsx +13 -0
  22. package/apps/agents-server/src/app/admin/messages/MessagesClient.tsx +294 -0
  23. package/apps/agents-server/src/app/admin/messages/page.tsx +13 -0
  24. package/apps/agents-server/src/app/admin/messages/send-email/SendEmailClient.tsx +104 -0
  25. package/apps/agents-server/src/app/admin/messages/send-email/actions.ts +35 -0
  26. package/apps/agents-server/src/app/admin/messages/send-email/page.tsx +13 -0
  27. package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +23 -19
  28. package/apps/agents-server/src/app/admin/search-engine-test/SearchEngineTestClient.tsx +109 -0
  29. package/apps/agents-server/src/app/admin/search-engine-test/actions.ts +17 -0
  30. package/apps/agents-server/src/app/admin/search-engine-test/page.tsx +13 -0
  31. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +15 -1
  32. package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +51 -9
  33. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +47 -4
  34. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +53 -11
  35. package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +23 -3
  36. package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +8 -8
  37. package/apps/agents-server/src/app/agents/[agentName]/api/agents/route.ts +17 -26
  38. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +4 -2
  39. package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +20 -0
  40. package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +6 -11
  41. package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +5 -1
  42. package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +5 -2
  43. package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +20 -16
  44. package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +15 -2
  45. package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +15 -2
  46. package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +12 -0
  47. package/apps/agents-server/src/app/agents/[agentName]/code/api/route.ts +68 -0
  48. package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +223 -0
  49. package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +5 -0
  50. package/apps/agents-server/src/app/agents/[agentName]/history/actions.ts +2 -2
  51. package/apps/agents-server/src/app/agents/[agentName]/history/page.tsx +10 -3
  52. package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/getAgentDefaultAvatarPrompt.ts +31 -0
  53. package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +194 -0
  54. package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +14 -2
  55. package/apps/agents-server/src/app/agents/[agentName]/images/page.tsx +200 -0
  56. package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +4 -3
  57. package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +4 -3
  58. package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +10 -3
  59. package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +11 -4
  60. package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +11 -2
  61. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +18 -10
  62. package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +100 -0
  63. package/apps/agents-server/src/app/api/admin-email/route.ts +12 -0
  64. package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +13 -14
  65. package/apps/agents-server/src/app/api/agents/[agentName]/restore/route.ts +20 -0
  66. package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +43 -1
  67. package/apps/agents-server/src/app/api/agents/route.ts +28 -3
  68. package/apps/agents-server/src/app/api/api-tokens/route.ts +6 -7
  69. package/apps/agents-server/src/app/api/browser-test/act/route.ts +141 -0
  70. package/apps/agents-server/src/app/api/browser-test/screenshot/route.ts +30 -0
  71. package/apps/agents-server/src/app/api/browser-test/scroll-facebook/route.ts +62 -0
  72. package/apps/agents-server/src/app/api/docs/book.md/route.ts +61 -0
  73. package/apps/agents-server/src/app/api/emails/incoming/sendgrid/route.ts +48 -0
  74. package/apps/agents-server/src/app/api/federated-agents/route.ts +12 -0
  75. package/apps/agents-server/src/app/api/images/[filename]/route.ts +128 -0
  76. package/apps/agents-server/src/app/api/messages/route.ts +102 -0
  77. package/apps/agents-server/src/app/api/metadata/route.ts +5 -6
  78. package/apps/agents-server/src/app/api/upload/route.ts +128 -45
  79. package/apps/agents-server/src/app/docs/[docId]/page.tsx +2 -3
  80. package/apps/agents-server/src/app/docs/page.tsx +12 -12
  81. package/apps/agents-server/src/app/globals.css +140 -33
  82. package/apps/agents-server/src/app/humans.txt/route.ts +1 -1
  83. package/apps/agents-server/src/app/layout.tsx +27 -22
  84. package/apps/agents-server/src/app/page.tsx +54 -6
  85. package/apps/agents-server/src/app/recycle-bin/actions.ts +20 -14
  86. package/apps/agents-server/src/app/recycle-bin/page.tsx +27 -41
  87. package/apps/agents-server/src/app/robots.txt/route.ts +1 -1
  88. package/apps/agents-server/src/app/security.txt/route.ts +1 -1
  89. package/apps/agents-server/src/app/sitemap.xml/route.ts +9 -7
  90. package/apps/agents-server/src/app/swagger/page.tsx +14 -0
  91. package/apps/agents-server/src/components/AgentProfile/AgentCapabilityChips.tsx +38 -0
  92. package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +44 -116
  93. package/apps/agents-server/src/components/AgentProfile/AgentProfileImage.tsx +92 -0
  94. package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +0 -1
  95. package/apps/agents-server/src/components/AgentProfile/useAgentBackground.ts +97 -0
  96. package/apps/agents-server/src/components/Auth/AuthControls.tsx +5 -4
  97. package/apps/agents-server/src/components/DeletedAgentBanner.tsx +26 -0
  98. package/apps/agents-server/src/components/DocsToolbar/DocsToolbar.tsx +38 -0
  99. package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +11 -9
  100. package/apps/agents-server/src/components/Footer/Footer.tsx +5 -5
  101. package/apps/agents-server/src/components/ForgottenPasswordDialog/ForgottenPasswordDialog.tsx +61 -0
  102. package/apps/agents-server/src/components/Header/Header.tsx +130 -40
  103. package/apps/agents-server/src/components/Homepage/AgentCard.tsx +150 -23
  104. package/apps/agents-server/src/components/Homepage/AgentsList.tsx +93 -15
  105. package/apps/agents-server/src/components/Homepage/DeletedAgentsList.tsx +66 -0
  106. package/apps/agents-server/src/components/Homepage/ExternalAgentsSection.tsx +12 -3
  107. package/apps/agents-server/src/components/Homepage/ExternalAgentsSectionClient.tsx +19 -10
  108. package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +3 -2
  109. package/apps/agents-server/src/components/LoginForm/LoginForm.tsx +50 -1
  110. package/apps/agents-server/src/components/NewAgentDialog/NewAgentDialog.tsx +88 -0
  111. package/apps/agents-server/src/components/NotFoundPage/NotFoundPage.tsx +7 -2
  112. package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +16 -7
  113. package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +4 -4
  114. package/apps/agents-server/src/components/RegisterUserDialog/RegisterUserDialog.tsx +61 -0
  115. package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +2 -0
  116. package/apps/agents-server/src/components/_utils/generateMetaTxt.ts +12 -10
  117. package/apps/agents-server/src/components/_utils/headlessParam.tsx +7 -3
  118. package/apps/agents-server/src/database/$getTableName.ts +1 -0
  119. package/apps/agents-server/src/database/$provideSupabaseForBrowser.ts +3 -3
  120. package/apps/agents-server/src/database/$provideSupabaseForServer.ts +1 -1
  121. package/apps/agents-server/src/database/$provideSupabaseForWorker.ts +3 -3
  122. package/apps/agents-server/src/database/metadataDefaults.ts +19 -1
  123. package/apps/agents-server/src/database/migrate.ts +34 -1
  124. package/apps/agents-server/src/database/migrations/2025-11-0001-initial-schema.sql +1 -3
  125. package/apps/agents-server/src/database/migrations/2025-11-0002-metadata-table.sql +1 -3
  126. package/apps/agents-server/src/database/migrations/2025-12-0240-agent-public-id.sql +3 -0
  127. package/apps/agents-server/src/database/migrations/2025-12-0360-agent-deleted-at.sql +1 -0
  128. package/apps/agents-server/src/database/migrations/2025-12-0370-image-table.sql +19 -0
  129. package/apps/agents-server/src/database/migrations/2025-12-0380-agent-visibility.sql +1 -0
  130. package/apps/agents-server/src/database/migrations/2025-12-0390-upload-tracking.sql +20 -0
  131. package/apps/agents-server/src/database/migrations/2025-12-0401-file-upload-status.sql +13 -0
  132. package/apps/agents-server/src/database/migrations/2025-12-0402-message-table.sql +42 -0
  133. package/apps/agents-server/src/database/migrations/2025-12-0403-generation-lock-table.sql +15 -0
  134. package/apps/agents-server/src/database/migrations/2025-12-0640-openai-assistant-cache.sql +12 -0
  135. package/apps/agents-server/src/database/migrations/2025-12-0820-agent-history-permanent-id.sql +29 -0
  136. package/apps/agents-server/src/database/migrations/2025-12-0830-image-purpose.sql +5 -0
  137. package/apps/agents-server/src/database/migrations/2025-12-0890-file-agent-id.sql +5 -0
  138. package/apps/agents-server/src/database/schema.ts +244 -4
  139. package/apps/agents-server/src/generated/reservedPaths.ts +32 -0
  140. package/apps/agents-server/src/message-providers/email/_common/Email.ts +73 -0
  141. package/apps/agents-server/src/message-providers/email/_common/utils/TODO.txt +1 -0
  142. package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.test.ts.todo +108 -0
  143. package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.ts +62 -0
  144. package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.test.ts.todo +117 -0
  145. package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.ts +19 -0
  146. package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.test.ts.todo +119 -0
  147. package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.ts +19 -0
  148. package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.test.ts.todo +74 -0
  149. package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.ts +14 -0
  150. package/apps/agents-server/src/message-providers/email/sendgrid/SendgridMessageProvider.ts +44 -0
  151. package/apps/agents-server/src/message-providers/email/sendgrid/parseInboundSendgridEmail.ts +49 -0
  152. package/apps/agents-server/src/message-providers/email/zeptomail/ZeptomailMessageProvider.ts +51 -0
  153. package/apps/agents-server/src/message-providers/index.ts +13 -0
  154. package/apps/agents-server/src/message-providers/interfaces/MessageProvider.ts +11 -0
  155. package/apps/agents-server/src/middleware.ts +19 -23
  156. package/apps/agents-server/src/tools/$provideBrowserForServer.ts +32 -0
  157. package/apps/agents-server/src/tools/$provideCdnForServer.ts +7 -2
  158. package/apps/agents-server/src/utils/auth.ts +117 -17
  159. package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +57 -0
  160. package/apps/agents-server/src/utils/cdn/classes/VercelBlobStorage.ts +4 -0
  161. package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +18 -0
  162. package/apps/agents-server/src/utils/content/extractBodyContentFromHtml.ts +19 -0
  163. package/apps/agents-server/src/utils/getUserIdFromRequest.ts +35 -0
  164. package/apps/agents-server/src/utils/handleChatCompletion.ts +65 -5
  165. package/apps/agents-server/src/utils/messages/sendMessage.ts +91 -0
  166. package/apps/agents-server/src/utils/messagesAdmin.ts +72 -0
  167. package/apps/agents-server/src/utils/normalization/filenameToPrompt.test.ts +36 -0
  168. package/apps/agents-server/src/utils/normalization/filenameToPrompt.ts +25 -0
  169. package/apps/agents-server/src/utils/validateApiKey.ts +7 -11
  170. package/esm/index.es.js +1534 -1330
  171. package/esm/index.es.js.map +1 -1
  172. package/esm/typings/servers.d.ts +8 -0
  173. package/esm/typings/src/_packages/core.index.d.ts +2 -0
  174. package/esm/typings/src/_packages/types.index.d.ts +16 -2
  175. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +29 -1
  176. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
  177. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.closed.test.d.ts +1 -0
  178. package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +3 -3
  179. package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +5 -1
  180. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  181. package/esm/typings/src/book-components/Chat/CodeBlock/CodeBlock.d.ts +13 -0
  182. package/esm/typings/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
  183. package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +9 -13
  184. package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +3 -3
  185. package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +1 -1
  186. package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
  187. package/esm/typings/src/book-components/icons/AboutIcon.d.ts +1 -1
  188. package/esm/typings/src/book-components/icons/AttachmentIcon.d.ts +1 -1
  189. package/esm/typings/src/book-components/icons/CameraIcon.d.ts +1 -1
  190. package/esm/typings/src/book-components/icons/DownloadIcon.d.ts +1 -1
  191. package/esm/typings/src/book-components/icons/MenuIcon.d.ts +1 -1
  192. package/esm/typings/src/book-components/icons/SaveIcon.d.ts +1 -1
  193. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +22 -12
  194. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +27 -15
  195. package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
  196. package/esm/typings/src/commitments/index.d.ts +2 -1
  197. package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +1 -1
  198. package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
  199. package/esm/typings/src/llm-providers/agent/Agent.d.ts +6 -1
  200. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
  201. package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
  202. package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
  203. package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
  204. package/esm/typings/src/remote-server/ui/ServerApp.d.ts +1 -1
  205. package/esm/typings/src/search-engines/SearchEngine.d.ts +9 -0
  206. package/esm/typings/src/search-engines/SearchResult.d.ts +18 -0
  207. package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +15 -0
  208. package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +15 -0
  209. package/esm/typings/src/types/Message.d.ts +49 -0
  210. package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
  211. package/esm/typings/src/types/typeAliases.d.ts +23 -1
  212. package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
  213. package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
  214. package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
  215. package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
  216. package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
  217. package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
  218. package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
  219. package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
  220. package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +3 -2
  221. package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
  222. package/esm/typings/src/version.d.ts +1 -1
  223. package/package.json +1 -1
  224. package/umd/index.umd.js +1542 -1338
  225. package/umd/index.umd.js.map +1 -1
  226. package/apps/agents-server/package-lock.json +0 -27
  227. package/apps/agents-server/public/fonts/download-font.js +0 -22
  228. package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +0 -18
  229. package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
@@ -27,7 +27,11 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
27
27
  const agentSource = await collection.getAgentSource(agentName);
28
28
  const agentProfile = parseAgentSource(agentSource);
29
29
  const agentHash = computeAgentHash(agentSource);
30
- const isVoiceCallingEnabled = (await getMetadata('IS_VOICE_CALLING_ENABLED')) === 'true';
30
+ const isVoiceCallingEnabled = (await getMetadata('IS_EXPERIMENTAL_VOICE_CALLING_ENABLED')) === 'true';
31
+
32
+ if (!agentProfile.meta.image) {
33
+ agentProfile.meta.image = `/agents/${encodeURIComponent(agentName)}/images/default-avatar.png`;
34
+ }
31
35
 
32
36
  return new Response(
33
37
  JSON.stringify(
@@ -6,10 +6,13 @@ import { $provideOpenAiAssistantExecutionToolsForServer } from '@/src/tools/$pro
6
6
  import { Agent, computeAgentHash, PROMPTBOOK_ENGINE_VERSION } from '@promptbook-local/core';
7
7
  import { computeHash, serializeError } from '@promptbook-local/utils';
8
8
  import { assertsError } from '../../../../../../../../src/errors/assertsError';
9
+ import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
9
10
 
10
11
  export const maxDuration = 300;
11
12
 
12
13
  export async function OPTIONS(request: Request) {
14
+ keepUnused(request);
15
+
13
16
  return new Response(null, {
14
17
  status: 200,
15
18
  headers: {
@@ -22,7 +25,7 @@ export async function OPTIONS(request: Request) {
22
25
 
23
26
  export async function POST(request: Request, { params }: { params: Promise<{ agentName: string }> }) {
24
27
  // Check if voice calling is enabled
25
- const isVoiceCallingEnabled = (await getMetadata('IS_VOICE_CALLING_ENABLED')) === 'true';
28
+ const isVoiceCallingEnabled = (await getMetadata('IS_EXPERIMENTAL_VOICE_CALLING_ENABLED')) === 'true';
26
29
  if (!isVoiceCallingEnabled) {
27
30
  return new Response(JSON.stringify({ error: 'Voice calling is disabled on this server' }), {
28
31
  status: 403,
@@ -38,7 +41,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
38
41
  const audioFile = formData.get('audio') as File | null;
39
42
  const threadString = formData.get('thread') as string | null;
40
43
  const thread = threadString ? JSON.parse(threadString) : undefined;
41
- const messageContext = formData.get('message') as string | null; // Optional text context or previous message?
44
+ // const messageContext = formData.get('message') as string | null; // Optional text context or previous message?
42
45
 
43
46
  if (!audioFile) {
44
47
  return new Response(JSON.stringify({ error: 'No audio file provided' }), {
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { BookEditor } from '@promptbook-local/components';
4
4
  import { string_book } from '@promptbook-local/types';
5
+ import { upload } from '@vercel/blob/client';
5
6
  import { useEffect, useRef, useState } from 'react';
6
7
 
7
8
  type BookEditorWrapperProps = {
@@ -93,35 +94,38 @@ export function BookEditorWrapper({ agentName, initialAgentSource }: BookEditorW
93
94
  value={agentSource}
94
95
  onChange={handleChange}
95
96
  onFileUpload={async (file) => {
96
- const formData = new FormData();
97
- formData.append('file', file);
98
-
99
- const response = await fetch('/api/upload', {
100
- method: 'POST',
101
- body: formData,
97
+ console.info('🔼 Uploading file', file);
98
+
99
+ // Build the full path including prefix and user/files directory
100
+ const pathPrefix = process.env.NEXT_PUBLIC_CDN_PATH_PREFIX || '';
101
+ const uploadPath = pathPrefix ? `${pathPrefix}/user/files/${file.name}` : `user/files/${file.name}`;
102
+
103
+ // Upload directly to Vercel Blob using client upload
104
+ const blob = await upload(uploadPath, file, {
105
+ access: 'public',
106
+ handleUploadUrl: '/api/upload',
107
+ clientPayload: JSON.stringify({
108
+ purpose: 'KNOWLEDGE',
109
+ contentType: file.type,
110
+ }),
102
111
  });
103
112
 
104
- if (!response.ok) {
105
- throw new Error(`Failed to upload file: ${response.statusText}`);
106
- }
107
-
108
- const { fileUrl: longFileUrl } = await response.json();
113
+ const fileUrl = blob.url;
109
114
 
110
115
  const LONG_URL = `${process.env.NEXT_PUBLIC_CDN_PUBLIC_URL!}/${process.env
111
116
  .NEXT_PUBLIC_CDN_PATH_PREFIX!}/user/files/`;
112
117
  const SHORT_URL = `https://ptbk.io/k/`;
113
118
  // <- TODO: [🌍] Unite this logic in one place
114
119
 
115
- const shortFileUrl = longFileUrl.split(LONG_URL).join(SHORT_URL);
120
+ const shortFileUrl = fileUrl.split(LONG_URL).join(SHORT_URL);
116
121
 
117
- console.log(`File uploaded:`, {
122
+ console.log(`🔼 File uploaded:`, {
118
123
  LONG_URL,
119
124
  SHORT_URL,
120
- longFileUrl,
125
+ fileUrl,
121
126
  shortFileUrl,
122
127
  file,
123
- formData,
124
- response,
128
+ blob,
125
129
  });
126
130
 
127
131
  return shortFileUrl;
@@ -5,21 +5,34 @@ import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentColle
5
5
  import { isUserAdmin } from '@/src/utils/isUserAdmin';
6
6
  import { headers } from 'next/headers';
7
7
  import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
8
+ import { isAgentDeleted } from '../_utils';
8
9
  import { generateAgentMetadata } from '../generateAgentMetadata';
9
10
  import { BookEditorWrapper } from './BookEditorWrapper';
11
+ import { DeletedAgentBanner } from '../../../../components/DeletedAgentBanner';
10
12
 
11
13
  export const generateMetadata = generateAgentMetadata;
12
14
 
13
15
  export default async function AgentBookPage({ params }: { params: Promise<{ agentName: string }> }) {
14
16
  $sideEffect(headers());
15
17
 
18
+ let { agentName } = await params;
19
+ agentName = decodeURIComponent(agentName);
20
+
21
+ const isDeleted = await isAgentDeleted(agentName);
22
+
23
+ if (isDeleted) {
24
+ return (
25
+ <div className="w-screen h-[calc(100vh-60px)] flex items-center justify-center p-8">
26
+ <DeletedAgentBanner />
27
+ </div>
28
+ );
29
+ }
30
+
16
31
  if (!(await isUserAdmin())) {
17
32
  /* <- TODO: [👹] Here should be user permissions */
18
33
  return <ForbiddenPage />;
19
34
  }
20
35
 
21
- let { agentName } = await params;
22
- agentName = decodeURIComponent(agentName);
23
36
  const collection = await $provideAgentCollectionForServer();
24
37
  const agentSource = await collection.getAgentSource(decodeURIComponent(agentName));
25
38
 
@@ -5,21 +5,34 @@ import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentColle
5
5
  import { isUserAdmin } from '@/src/utils/isUserAdmin';
6
6
  import { headers } from 'next/headers';
7
7
  import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
8
+ import { isAgentDeleted } from '../_utils';
8
9
  import { generateAgentMetadata } from '../generateAgentMetadata';
9
10
  import { AgentBookAndChat } from './AgentBookAndChat';
11
+ import { DeletedAgentBanner } from '../../../../components/DeletedAgentBanner';
10
12
 
11
13
  export const generateMetadata = generateAgentMetadata;
12
14
 
13
15
  export default async function AgentBookAndChatPage({ params }: { params: Promise<{ agentName: string }> }) {
14
16
  $sideEffect(headers());
15
17
 
18
+ let { agentName } = await params;
19
+ agentName = decodeURIComponent(agentName);
20
+
21
+ const isDeleted = await isAgentDeleted(agentName);
22
+
23
+ if (isDeleted) {
24
+ return (
25
+ <div className="w-screen h-[calc(100vh-60px)] flex items-center justify-center p-8">
26
+ <DeletedAgentBanner />
27
+ </div>
28
+ );
29
+ }
30
+
16
31
  if (!(await isUserAdmin())) {
17
32
  /* <- TODO: [👹] Here should be user permissions */
18
33
  return <ForbiddenPage />;
19
34
  }
20
35
 
21
- let { agentName } = await params;
22
- agentName = decodeURIComponent(agentName);
23
36
  const collection = await $provideAgentCollectionForServer();
24
37
  const agentSource = await collection.getAgentSource(agentName);
25
38
  const agentUrl = `/agents/${agentName}`;
@@ -2,8 +2,10 @@
2
2
 
3
3
  import { headers } from 'next/headers';
4
4
  import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
5
+ import { isAgentDeleted } from '../_utils';
5
6
  import { generateAgentMetadata } from '../generateAgentMetadata';
6
7
  import { AgentChatWrapper } from '../AgentChatWrapper';
8
+ import { DeletedAgentBanner } from '../../../../components/DeletedAgentBanner';
7
9
 
8
10
  export const generateMetadata = generateAgentMetadata;
9
11
 
@@ -19,6 +21,16 @@ export default async function AgentChatPage({
19
21
  agentName = decodeURIComponent(agentName);
20
22
  const { message } = await searchParams;
21
23
 
24
+ const isDeleted = await isAgentDeleted(agentName);
25
+
26
+ if (isDeleted) {
27
+ return (
28
+ <main className="w-screen h-screen flex items-center justify-center p-8">
29
+ <DeletedAgentBanner message="This agent has been deleted. You can restore it from the Recycle Bin." />
30
+ </main>
31
+ );
32
+ }
33
+
22
34
  const agentUrl = `/agents/${agentName}`;
23
35
 
24
36
  return (
@@ -0,0 +1,68 @@
1
+ import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
2
+ import { $provideExecutionToolsForServer } from '@/src/tools/$provideExecutionToolsForServer';
3
+ import { NextRequest, NextResponse } from 'next/server';
4
+ import { $bookTranspilersRegister } from '../../../../../../../../src/transpilers/_common/register/$bookTranspilersRegister';
5
+ import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
6
+
7
+ export async function GET(request: NextRequest, { params }: { params: Promise<{ agentName: string }> }) {
8
+ keepUnused(request);
9
+ keepUnused(params);
10
+ // const agentName = (await params).agentName;
11
+
12
+ try {
13
+ // Get available transpilers
14
+ const transpilers = $bookTranspilersRegister.list().map((transpiler) => ({
15
+ name: transpiler.name,
16
+ title: transpiler.title,
17
+ }));
18
+
19
+ return NextResponse.json({ transpilers });
20
+ } catch (error) {
21
+ console.error('Error getting transpilers:', error);
22
+ return NextResponse.json({ error: 'Failed to get transpilers' }, { status: 500 });
23
+ }
24
+ }
25
+
26
+ export async function POST(request: NextRequest, { params }: { params: Promise<{ agentName: string }> }) {
27
+ const agentName = (await params).agentName;
28
+
29
+ try {
30
+ const { transpilerName } = await request.json();
31
+
32
+ if (!transpilerName) {
33
+ return NextResponse.json({ error: 'Transpiler name is required' }, { status: 400 });
34
+ }
35
+
36
+ // Get the transpiler
37
+ const allTranspilers = $bookTranspilersRegister.list();
38
+ const transpiler = allTranspilers.find((t) => t.name === transpilerName);
39
+ if (!transpiler) {
40
+ return NextResponse.json({ error: 'Transpiler not found' }, { status: 404 });
41
+ }
42
+
43
+ // Get agent source
44
+ const collection = await $provideAgentCollectionForServer();
45
+ const agentSource = await collection.getAgentSource(agentName);
46
+
47
+ if (!agentSource) {
48
+ return NextResponse.json({ error: 'Agent source not found' }, { status: 404 });
49
+ }
50
+
51
+ // Get execution tools
52
+ const tools = await $provideExecutionToolsForServer();
53
+
54
+ // Transpile the code
55
+ const transpiledCode = await transpiler.transpileBook(agentSource, tools);
56
+
57
+ return NextResponse.json({
58
+ code: transpiledCode,
59
+ transpiler: {
60
+ name: transpiler.name,
61
+ title: transpiler.title,
62
+ },
63
+ });
64
+ } catch (error) {
65
+ console.error('Error transpiling code:', error);
66
+ return NextResponse.json({ error: 'Failed to transpile code' }, { status: 500 });
67
+ }
68
+ }
@@ -0,0 +1,223 @@
1
+ 'use client';
2
+
3
+ import { NEXT_PUBLIC_SITE_URL } from '@/config';
4
+ import Editor from '@monaco-editor/react';
5
+ import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
6
+ import { AgentBasicInformation } from '@promptbook-local/types';
7
+ import { ArrowLeftIcon, ChevronDownIcon, CodeIcon } from 'lucide-react';
8
+ import Link from 'next/link';
9
+ import { useCallback, useEffect, useState } from 'react';
10
+
11
+ type Transpiler = {
12
+ name: string;
13
+ title: string;
14
+ };
15
+
16
+ type TranspilationResult = {
17
+ code: string;
18
+ transpiler: Transpiler;
19
+ };
20
+
21
+ function getLanguageFromTranspiler(transpilerName?: string): string {
22
+ if (!transpilerName) return 'plaintext';
23
+
24
+ // Map transpiler names to Monaco language identifiers
25
+ if (transpilerName.includes('openai-sdk')) return 'javascript';
26
+ if (transpilerName.includes('langchain') || transpilerName.includes('python')) return 'python';
27
+ if (transpilerName.includes('markdown')) return 'markdown';
28
+
29
+ // Default to plaintext for unknown transpilers
30
+ return 'plaintext';
31
+ }
32
+
33
+ export default function AgentCodePage({ params }: { params: Promise<{ agentName: string }> }) {
34
+ const [agentName, setAgentName] = useState<string>('');
35
+ const [agentProfile, setAgentProfile] = useState<AgentBasicInformation | null>(null);
36
+ const [transpilers, setTranspilers] = useState<Transpiler[]>([]);
37
+ const [selectedTranspiler, setSelectedTranspiler] = useState<Transpiler | null>(null);
38
+ const [transpiledCode, setTranspiledCode] = useState<string>('');
39
+ const [loading, setLoading] = useState(false);
40
+ const [error, setError] = useState<string>('');
41
+
42
+ useEffect(() => {
43
+ params.then((p) => setAgentName(p.agentName));
44
+ }, [params]);
45
+
46
+ useEffect(() => {
47
+ if (!agentName) return;
48
+
49
+ // Fetch agent profile
50
+ fetch(`/api/agents/${encodeURIComponent(agentName)}`)
51
+ .then((res) => res.json())
52
+ .then((data) => setAgentProfile(data))
53
+ .catch((err) => console.error('Error fetching agent profile:', err));
54
+
55
+ // Fetch available transpilers
56
+ fetch(`/agents/${encodeURIComponent(agentName)}/code/api`)
57
+ .then((res) => res.json())
58
+ .then((data) => {
59
+ setTranspilers(data.transpilers || []);
60
+ if (data.transpilers && data.transpilers.length > 0) {
61
+ setSelectedTranspiler(data.transpilers[0]);
62
+ }
63
+ })
64
+ .catch((err) => console.error('Error fetching transpilers:', err));
65
+ }, [agentName]);
66
+
67
+ const transpileCode = useCallback(
68
+ async (transpilerName: string) => {
69
+ setLoading(true);
70
+ setError('');
71
+
72
+ try {
73
+ const response = await fetch(`/agents/${encodeURIComponent(agentName)}/code/api`, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ },
78
+ body: JSON.stringify({ transpilerName }),
79
+ });
80
+
81
+ if (!response.ok) {
82
+ const errorData = await response.json();
83
+ throw new Error(errorData.error || 'Failed to transpile code');
84
+ }
85
+
86
+ const result: TranspilationResult = await response.json();
87
+ setTranspiledCode(result.code);
88
+ } catch (err) {
89
+ setError(err instanceof Error ? err.message : 'Failed to transpile code');
90
+ setTranspiledCode('');
91
+ } finally {
92
+ setLoading(false);
93
+ }
94
+ },
95
+ [agentName],
96
+ );
97
+
98
+ useEffect(() => {
99
+ if (selectedTranspiler && agentName) {
100
+ transpileCode(selectedTranspiler.name);
101
+ }
102
+ }, [selectedTranspiler, agentName, transpileCode]);
103
+
104
+ if (!agentProfile) {
105
+ return (
106
+ <div className="min-h-screen p-6 md:p-12 flex flex-col items-center bg-gray-50">
107
+ <div className="w-full max-w-4xl bg-white rounded-xl shadow-sm border border-gray-200 p-12">
108
+ <div className="text-center">Loading...</div>
109
+ </div>
110
+ </div>
111
+ );
112
+ }
113
+
114
+ return (
115
+ <div className="min-h-screen p-6 md:p-12 flex flex-col items-center bg-gray-50">
116
+ <div className="w-full max-w-4xl bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
117
+ {/* Header */}
118
+ <div className="p-6 border-b border-gray-200 flex items-center gap-4">
119
+ {/* eslint-disable @typescript-eslint/no-explicit-any, @next/next/no-img-element */}
120
+
121
+ <img
122
+ src={
123
+ agentProfile.meta.image ||
124
+ generatePlaceholderAgentProfileImageUrl(
125
+ agentProfile.permanentId || agentName,
126
+ NEXT_PUBLIC_SITE_URL, // <- TODO: !!!! Use here `const { publicUrl } = await $provideServer();`
127
+ )
128
+ }
129
+ alt={agentProfile.meta.fullname || agentName}
130
+ className="w-16 h-16 rounded-full object-cover border-2 border-gray-200"
131
+ />
132
+
133
+ <div className="flex-1">
134
+ {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
135
+ <h1 className="text-2xl font-bold text-gray-900">
136
+ {(agentProfile as any)?.meta?.fullname || agentName}
137
+ </h1>
138
+ <p className="text-gray-500 flex items-center gap-2">
139
+ <CodeIcon className="w-4 h-4" />
140
+ Generated Code
141
+ </p>
142
+ </div>
143
+ <Link
144
+ href={`/agents/${encodeURIComponent(agentName)}`}
145
+ className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full transition-colors"
146
+ title="Back to Agent"
147
+ >
148
+ <ArrowLeftIcon className="w-6 h-6" />
149
+ </Link>
150
+ </div>
151
+
152
+ <div className="p-6">
153
+ {/* Transpiler Selector */}
154
+ <div className="mb-6">
155
+ <label className="block text-sm font-medium text-gray-700 mb-2">Select Transpiler</label>
156
+ <div className="relative">
157
+ <select
158
+ value={selectedTranspiler?.name || ''}
159
+ onChange={(e) => {
160
+ const transpiler = transpilers.find((t) => t.name === e.target.value);
161
+ if (transpiler) setSelectedTranspiler(transpiler);
162
+ }}
163
+ className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
164
+ >
165
+ {transpilers.map((transpiler) => (
166
+ <option key={transpiler.name} value={transpiler.name}>
167
+ {transpiler.title}
168
+ </option>
169
+ ))}
170
+ </select>
171
+ <ChevronDownIcon className="absolute right-3 top-3 w-4 h-4 text-gray-400 pointer-events-none" />
172
+ </div>
173
+ </div>
174
+
175
+ {/* Code Display */}
176
+ <div className="bg-gray-50 rounded-lg border border-gray-200 overflow-hidden">
177
+ <div className="p-4 border-b border-gray-200 flex items-center justify-between">
178
+ <h2 className="text-lg font-semibold text-gray-900">
179
+ {selectedTranspiler?.title || 'Generated Code'}
180
+ </h2>
181
+ {loading && <div className="text-sm text-gray-500">Generating...</div>}
182
+ </div>
183
+ <div className="p-4">
184
+ {error && (
185
+ <div className="text-red-600 text-sm mb-4 p-3 bg-red-50 rounded border border-red-200">
186
+ {error}
187
+ </div>
188
+ )}
189
+ {transpiledCode ? (
190
+ <div className="h-96 border border-gray-200 rounded">
191
+ <Editor
192
+ value={transpiledCode}
193
+ language={getLanguageFromTranspiler(selectedTranspiler?.name)}
194
+ options={{
195
+ readOnly: true,
196
+ minimap: { enabled: false },
197
+ fontSize: 14,
198
+ lineNumbers: 'on',
199
+ scrollBeyondLastLine: false,
200
+ automaticLayout: true,
201
+ wordWrap: 'on',
202
+ }}
203
+ loading={
204
+ <div className="flex items-center justify-center h-full text-gray-500">
205
+ Loading editor...
206
+ </div>
207
+ }
208
+ />
209
+ </div>
210
+ ) : loading ? (
211
+ <div className="text-gray-500 text-center py-8">Generating code...</div>
212
+ ) : (
213
+ <div className="text-gray-500 text-center py-8">
214
+ Select a transpiler to generate code
215
+ </div>
216
+ )}
217
+ </div>
218
+ </div>
219
+ </div>
220
+ </div>
221
+ </div>
222
+ );
223
+ }
@@ -15,6 +15,8 @@ export async function generateAgentMetadata({ params }: { params: Promise<{ agen
15
15
  // Use the agent's icon-256.png as the favicon
16
16
  const iconUrl = `/agents/${encodeURIComponent(agentName)}/images/icon-256.png`;
17
17
 
18
+ const canonicalUrl = `/agents/${encodeURIComponent(agentProfile.permanentId || agentName)}`;
19
+
18
20
  const metadata = {
19
21
  metadataBase: publicUrl,
20
22
  title,
@@ -24,6 +26,9 @@ export async function generateAgentMetadata({ params }: { params: Promise<{ agen
24
26
  shortcut: iconUrl,
25
27
  apple: iconUrl,
26
28
  },
29
+ alternates: {
30
+ canonical: canonicalUrl,
31
+ },
27
32
  openGraph: {
28
33
  title,
29
34
  description,
@@ -5,8 +5,8 @@ import { revalidatePath } from 'next/cache';
5
5
 
6
6
  export async function restoreAgentVersion(agentName: string, historyId: number) {
7
7
  const collection = await $provideAgentCollectionForServer();
8
- await collection.restoreAgent(historyId);
9
-
8
+ await collection.restoreAgentFromHistory(historyId);
9
+
10
10
  revalidatePath(`/agents/${agentName}`);
11
11
  revalidatePath(`/agents/${agentName}/history`);
12
12
  }
@@ -10,7 +10,8 @@ export const metadata = {
10
10
  export default async function AgentHistoryPage({ params }: { params: Promise<{ agentName: string }> }) {
11
11
  const { agentName } = await params;
12
12
  const collection = await $provideAgentCollectionForServer();
13
- const history = await collection.listAgentHistory(agentName);
13
+ const agentId = await collection.getAgentPermanentId(agentName);
14
+ const history = await collection.listAgentHistory(agentId);
14
15
 
15
16
  return (
16
17
  <div className="container mx-auto p-6 max-w-4xl">
@@ -21,7 +22,10 @@ export default async function AgentHistoryPage({ params }: { params: Promise<{ a
21
22
  <div>
22
23
  <h1 className="text-3xl font-bold text-gray-900">History: {agentName}</h1>
23
24
  <p className="text-gray-600">
24
- Previous versions of this agent. <Link href={`/agents/${agentName}`} className="text-blue-600 hover:underline">Back to agent</Link>
25
+ Previous versions of this agent.{' '}
26
+ <Link href={`/agents/${agentName}`} className="text-blue-600 hover:underline">
27
+ Back to agent
28
+ </Link>
25
29
  </p>
26
30
  </div>
27
31
  </header>
@@ -47,7 +51,10 @@ export default async function AgentHistoryPage({ params }: { params: Promise<{ a
47
51
  Version {history.length - index}
48
52
  </h3>
49
53
  <p className="text-sm text-gray-500">
50
- Hash: <code className="bg-gray-100 px-1 rounded">{item.agentHash.substring(0, 8)}</code>
54
+ Hash:{' '}
55
+ <code className="bg-gray-100 px-1 rounded">
56
+ {item.agentHash.substring(0, 8)}
57
+ </code>
51
58
  </p>
52
59
  </div>
53
60
  <RestoreVersionButton agentName={agentName} historyId={item.id} />
@@ -0,0 +1,31 @@
1
+ import { AgentBasicInformation } from '@promptbook-local/types';
2
+ import spaceTrim from 'spacetrim';
3
+ import { string_prompt_image } from '../../../../../../../../src/types/typeAliases';
4
+
5
+ export function getAgentDefaultAvatarPrompt(agent: AgentBasicInformation): string_prompt_image {
6
+ const {
7
+ agentName,
8
+ personaDescription,
9
+ meta: { fullname, color },
10
+ } = agent;
11
+
12
+ return spaceTrim(
13
+ (block) => `
14
+ Professional corporate headshot of ${fullname || agentName}
15
+
16
+ ${block(personaDescription || '')}
17
+
18
+ - Professional business portrait photograph
19
+ - Photorealistic, studio quality lighting
20
+ - Shot with 85mm lens, shallow depth of field
21
+ - Neutral gray or soft gradient background
22
+ - Subject wearing professional attire with accent colors: ${color}
23
+ - Confident, approachable expression with slight smile
24
+ - Eye-level camera angle, centered composition
25
+ - Soft diffused lighting, subtle rim light
26
+ - Sharp focus on eyes, cinematic color grading
27
+ - 8K resolution, ultra detailed
28
+
29
+ `,
30
+ );
31
+ }