@promptbook/cli 0.112.0-103 → 0.112.0-105

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 (190) hide show
  1. package/apps/agents-server/src/app/AddAgentButton.tsx +0 -5
  2. package/apps/agents-server/src/app/actions.ts +50 -0
  3. package/apps/agents-server/src/app/admin/image-generator-test/ImageAttachmentsEditor.tsx +19 -3
  4. package/apps/agents-server/src/app/admin/limits/LimitsClient.tsx +11 -12
  5. package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +34 -2
  6. package/apps/agents-server/src/app/admin/servers/CreateServerDialog.tsx +6 -1
  7. package/apps/agents-server/src/app/admin/servers/useCreateServerWizard.ts +13 -1
  8. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +11 -2
  9. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +14 -5
  10. package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +7 -1
  11. package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +11 -1
  12. package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +6 -2
  13. package/apps/agents-server/src/app/api/health/route.ts +18 -0
  14. package/apps/agents-server/src/app/api/images/[filename]/route.ts +6 -2
  15. package/apps/agents-server/src/app/api/internal/agent-runner-limits/route.ts +51 -0
  16. package/apps/agents-server/src/app/api/upload/route.ts +48 -12
  17. package/apps/agents-server/src/app/layout.tsx +13 -0
  18. package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +1 -4
  19. package/apps/agents-server/src/components/FileUploadAvailability/FileUploadAvailabilityContext.tsx +50 -0
  20. package/apps/agents-server/src/components/FileUploadAvailability/FileUploadUnavailableNotice.tsx +45 -0
  21. package/apps/agents-server/src/components/Header/Header.tsx +0 -11
  22. package/apps/agents-server/src/components/Header/useHeaderAgentMenus.tsx +0 -5
  23. package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +85 -76
  24. package/apps/agents-server/src/components/NewAgentDialog/NewAgentDialog.tsx +7 -3
  25. package/apps/agents-server/src/components/NewAgentDialog/NewAgentWizardKnowledgeStep.tsx +6 -0
  26. package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +39 -16
  27. package/apps/agents-server/src/components/NewAgentDialog/useNewAgentWizardKnowledgeState.ts +8 -1
  28. package/apps/agents-server/src/constants/defaultAgentAvatarVisual.ts +1 -1
  29. package/apps/agents-server/src/constants/serverLimits.ts +22 -2
  30. package/apps/agents-server/src/database/migrations/2026-06-0200-default-agent-avatar-visual-octopus3d3.sql +16 -0
  31. package/apps/agents-server/src/database/seedDefaultAgents.ts +218 -0
  32. package/apps/agents-server/src/middleware.ts +2 -1
  33. package/apps/agents-server/src/tools/$provideCdnForServer.ts +114 -9
  34. package/apps/agents-server/src/utils/agentRouting/resolveAgentRouteTarget.ts +27 -4
  35. package/apps/agents-server/src/utils/defaultAgents/loadDefaultAgentBooks.ts +103 -0
  36. package/apps/agents-server/src/utils/knowledge/createInlineKnowledgeSourceUploader.ts +24 -5
  37. package/apps/agents-server/src/utils/serverLimits.ts +26 -1
  38. package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerDefaultAgents.ts +1 -85
  39. package/apps/agents-server/src/utils/shareTargetPayloads.ts +20 -2
  40. package/apps/agents-server/src/utils/upload/fileUploadAvailability.ts +91 -0
  41. package/apps/agents-server/src/utils/upload/uploadFileToServer.ts +46 -2
  42. package/esm/apps/agents-server/src/constants/federatedAgentImport.d.ts +42 -0
  43. package/esm/apps/agents-server/src/constants/serverLimits.d.ts +207 -0
  44. package/esm/apps/agents-server/src/constants/toolUsageLimits.d.ts +55 -0
  45. package/esm/index.es.js +1109 -35
  46. package/esm/index.es.js.map +1 -1
  47. package/esm/scripts/run-agent-messages/main/AgentMessageFailureTracker.d.ts +27 -0
  48. package/esm/scripts/run-agent-messages/main/handleAgentWatchError.d.ts +4 -0
  49. package/esm/scripts/run-agent-messages/main/runAgentMessages.d.ts +1 -0
  50. package/esm/scripts/run-agent-messages/messages/moveAgentMessageToFailed.d.ts +17 -0
  51. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  52. package/esm/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
  53. package/esm/src/book-components/BookEditor/BookEditor.d.ts +5 -4
  54. package/esm/src/book-components/BookEditor/BookEditorTheme.d.ts +24 -0
  55. package/esm/src/book-components/BookEditor/useBookEditorMonacoLanguage.d.ts +1 -6
  56. package/esm/src/book-components/BookEditor/useBookEditorMonacoLifecycle.d.ts +1 -4
  57. package/esm/src/book-components/BookEditor/useBookEditorMonacoStyles.d.ts +2 -1
  58. package/esm/src/cli/cli-commands/agent-folder/agentProjectPaths.d.ts +6 -0
  59. package/esm/src/version.d.ts +1 -1
  60. package/package.json +1 -1
  61. package/src/avatars/types/AvatarVisualDefinition.ts +1 -0
  62. package/src/avatars/visuals/avatarVisualRegistry.ts +2 -0
  63. package/src/avatars/visuals/octopus3d3AvatarVisual.ts +902 -0
  64. package/src/book-components/BookEditor/BookEditor.tsx +10 -7
  65. package/src/book-components/BookEditor/BookEditorMonaco.tsx +3 -1
  66. package/src/book-components/BookEditor/BookEditorTheme.ts +32 -0
  67. package/src/book-components/BookEditor/useBookEditorMonacoLanguage.ts +12 -15
  68. package/src/book-components/BookEditor/useBookEditorMonacoLifecycle.ts +1 -5
  69. package/src/book-components/BookEditor/useBookEditorMonacoStyles.ts +2 -1
  70. package/src/cli/cli-commands/agent-folder/agentProjectPaths.ts +7 -0
  71. package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +109 -9
  72. package/src/cli/cli-commands/agents-server/startAgentsServer.ts +132 -4
  73. package/src/other/templates/getTemplatesPipelineCollection.ts +690 -747
  74. package/src/utils/agents/resolveAgentAvatarImageUrl.ts +1 -1
  75. package/src/version.ts +2 -2
  76. package/src/versions.txt +2 -1
  77. package/umd/apps/agents-server/src/constants/federatedAgentImport.d.ts +42 -0
  78. package/umd/apps/agents-server/src/constants/serverLimits.d.ts +207 -0
  79. package/umd/apps/agents-server/src/constants/toolUsageLimits.d.ts +55 -0
  80. package/umd/index.umd.js +1109 -35
  81. package/umd/index.umd.js.map +1 -1
  82. package/umd/scripts/run-agent-messages/main/AgentMessageFailureTracker.d.ts +27 -0
  83. package/umd/scripts/run-agent-messages/main/handleAgentWatchError.d.ts +4 -0
  84. package/umd/scripts/run-agent-messages/main/runAgentMessages.d.ts +1 -0
  85. package/umd/scripts/run-agent-messages/messages/moveAgentMessageToFailed.d.ts +17 -0
  86. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  87. package/umd/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
  88. package/umd/src/book-components/BookEditor/BookEditor.d.ts +5 -4
  89. package/umd/src/book-components/BookEditor/BookEditorTheme.d.ts +24 -0
  90. package/umd/src/book-components/BookEditor/useBookEditorMonacoLanguage.d.ts +1 -6
  91. package/umd/src/book-components/BookEditor/useBookEditorMonacoLifecycle.d.ts +1 -4
  92. package/umd/src/book-components/BookEditor/useBookEditorMonacoStyles.d.ts +2 -1
  93. package/umd/src/cli/cli-commands/agent-folder/agentProjectPaths.d.ts +6 -0
  94. package/umd/src/version.d.ts +1 -1
  95. package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.test.ts.todo +0 -108
  96. package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.test.ts.todo +0 -117
  97. package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.test.ts.todo +0 -119
  98. package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.test.ts.todo +0 -74
  99. package/apps/agents-server/tests/e2e/authentication-and-navigation.spec.ts.todo +0 -178
  100. package/src/_packages/browser.index.ts +0 -31
  101. package/src/_packages/browser.readme.md +0 -43
  102. package/src/book-2.0/agent-source/parseAgentSourceWithCommitments.test.ts.todo +0 -265
  103. package/src/book-components/BookEditor/BookEditorMonaco.test.tsx.todo +0 -115
  104. package/src/book-components/Chat/utils/renderMarkdown.test.ts.tmp +0 -199
  105. package/src/collection/agent-collection/constructors/agent-collection-in-directory/AgentCollectionInDirectory.test.ts.todo +0 -131
  106. package/src/commands/_common/parseCommand.test.ts.todo +0 -48
  107. package/src/commitments/META_LINK/META_LINK.test.ts.todo +0 -75
  108. package/src/conversion/validation/pipelineStringToJson-errors.test.ts.todo +0 -33
  109. package/src/dialogs/simple-prompt/SimplePromptInterfaceTools.ts +0 -51
  110. package/src/executables/browsers/locateSafari.test.ts.tmp +0 -15
  111. package/src/execution/PromptbookFetch.test-type.ts +0 -14
  112. package/src/execution/createPipelineExecutor/00-createPipelineExecutor.test.ts.todo +0 -0
  113. package/src/execution/execution-report/executionReportJsonToString.test.ts.todo +0 -83
  114. package/src/execution/utils/usageToHuman.test.ts.todo +0 -80
  115. package/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.ts +0 -76
  116. package/src/llm-providers/_common/utils/assertUniqueModels.ts +0 -27
  117. package/src/llm-providers/_multiple/playground/playground.ts +0 -141
  118. package/src/llm-providers/_multiple/playground/tsconfig.json +0 -19
  119. package/src/llm-providers/agent/playground/playground.ts +0 -190
  120. package/src/llm-providers/agent/playground/tsconfig.json +0 -19
  121. package/src/llm-providers/anthropic-claude/playground/playground.ts +0 -99
  122. package/src/llm-providers/anthropic-claude/playground/tsconfig.json +0 -19
  123. package/src/llm-providers/azure-openai/playground/playground.ts +0 -101
  124. package/src/llm-providers/azure-openai/playground/tsconfig.json +0 -19
  125. package/src/llm-providers/ollama/playground/playground.ts +0 -120
  126. package/src/llm-providers/ollama/playground/tsconfig.json +0 -19
  127. package/src/llm-providers/openai/playground/playground.ts +0 -406
  128. package/src/llm-providers/openai/playground/tsconfig.json +0 -19
  129. package/src/llm-providers/remote/playground/playground.ts +0 -144
  130. package/src/llm-providers/remote/playground/tsconfig.json +0 -19
  131. package/src/llm-providers/vercel/playground/playground.ts +0 -133
  132. package/src/llm-providers/vercel/playground/tsconfig.json +0 -19
  133. package/src/personas/preparePersona.test.ts.todo +0 -126
  134. package/src/playground/backup/_playground-boilerplate.ts.txt +0 -37
  135. package/src/playground/backup/playground-agent-os.txt +0 -62
  136. package/src/playground/backup/playground-brj-app.ts.txt +0 -302
  137. package/src/playground/backup/playground-browser-playwright.txt +0 -110
  138. package/src/playground/backup/playground-claude-mcp.txt +0 -43
  139. package/src/playground/backup/playground-document-conversion.txt +0 -84
  140. package/src/playground/backup/playground-glob.ts.txt +0 -42
  141. package/src/playground/backup/playground-mcp-server.txt +0 -1
  142. package/src/playground/backup/playground-openai-agent-kit.txt +0 -73
  143. package/src/playground/backup/playground-openai-function-calling.txt +0 -131
  144. package/src/playground/backup/playground-openai-streaming.ts.txt +0 -68
  145. package/src/playground/backup/playground-scrape-knowledge.txt +0 -65
  146. package/src/playground/backup/playground-scraperFetch.ts.txt +0 -44
  147. package/src/playground/backup/playground-using-openai-compatible-route-on-agents-server.ts.txt +0 -49
  148. package/src/playground/backup/playground-write-pavolhejny-bio.txt +0 -120
  149. package/src/playground/permanent/_boilerplate.ts +0 -54
  150. package/src/playground/permanent/agent-with-browser-playground.ts +0 -92
  151. package/src/playground/permanent/error-handling-playground.ts +0 -103
  152. package/src/playground/playground.ts +0 -36
  153. package/src/playground/tsconfig.json +0 -19
  154. package/src/scrapers/_boilerplate/BoilerplateScraper.test.ts.todo +0 -73
  155. package/src/scrapers/_boilerplate/playground/boilerplate-scraper-playground.ts +0 -79
  156. package/src/scrapers/_boilerplate/playground/tsconfig.json +0 -19
  157. package/src/scrapers/_common/utils/files/blobToDataurl.test.ts.todo +0 -17
  158. package/src/scrapers/_common/utils/files/dataurlToBlob.test.ts.todo +0 -52
  159. package/src/scrapers/_common/utils/files/isValidDataurl.test.ts.todo +0 -42
  160. package/src/scrapers/_common/utils/files/shorten.test.ts.todo +0 -13
  161. package/src/scrapers/document/playground/document-scraper-playground.ts +0 -80
  162. package/src/scrapers/document/playground/tsconfig.json +0 -19
  163. package/src/scrapers/document-legacy/playground/legacy-document-scraper-playground.ts +0 -80
  164. package/src/scrapers/document-legacy/playground/tsconfig.json +0 -19
  165. package/src/scrapers/markdown/playground/markdown-scraper-playground.ts +0 -74
  166. package/src/scrapers/markdown/playground/tsconfig.json +0 -19
  167. package/src/scrapers/markitdown/MarkitdownScraper.test.ts.todo +0 -132
  168. package/src/scrapers/markitdown/playground/markitdown-scraper-playground.ts +0 -91
  169. package/src/scrapers/markitdown/playground/tsconfig.json +0 -19
  170. package/src/scrapers/pdf/PdfScraper.test.ts.todo +0 -52
  171. package/src/scrapers/pdf/playground/pdf-scraper-playground.ts +0 -75
  172. package/src/scrapers/pdf/playground/tsconfig.json +0 -19
  173. package/src/scrapers/website/playground/tsconfig.json +0 -19
  174. package/src/scrapers/website/playground/website-scraper-playground.ts +0 -82
  175. package/src/storage/_common/PromptbookStorage.test-type.ts +0 -14
  176. package/src/storage/local-storage/getIndexedDbStorage.ts +0 -36
  177. package/src/storage/local-storage/getLocalStorage.ts +0 -33
  178. package/src/storage/local-storage/getSessionStorage.ts +0 -33
  179. package/src/storage/local-storage/utils/IndexedDbStorageOptions.ts +0 -16
  180. package/src/storage/local-storage/utils/makePromptbookStorageFromIndexedDb.ts +0 -58
  181. package/src/storage/local-storage/utils/makePromptbookStorageFromWebStorage.ts +0 -45
  182. package/src/transpilers/formatted-book-in-markdown/FormattedBookInMarkdownTranspiler.test.ts.todo +0 -35
  183. package/src/transpilers/openai-sdk/playground/playground.ts +0 -85
  184. package/src/transpilers/openai-sdk/playground/tmp/chatbot-openaisdk-1.js +0 -194
  185. package/src/transpilers/openai-sdk/playground/tmp/package.json +0 -3
  186. package/src/transpilers/openai-sdk/playground/tsconfig.json +0 -18
  187. package/src/utils/editable/utils/findUsableParameters.test.ts.todo +0 -43
  188. package/src/utils/editable/utils/stringifyPipelineJson.test.ts.todo +0 -38
  189. package/src/utils/markdown/prettifyMarkdown.test.ts.tmp +0 -42
  190. package/src/utils/serialization/serializeToPromptbookJavascript.test.ts.todo +0 -116
@@ -5,8 +5,9 @@ import type { LlmExecutionTools } from '../../../../../../../src/execution/LlmEx
5
5
  import { getSingleLlmExecutionTools } from '../../../../../../../src/llm-providers/_multiple/getSingleLlmExecutionTools';
6
6
  import type { ImageGenerationModelRequirements } from '../../../../../../../src/types/ModelRequirements';
7
7
  import { string_url } from '../../../../../../../src/types/typeAliases';
8
- import { $provideCdnForServer } from '../../../../tools/$provideCdnForServer';
8
+ import { $provideCdnForServer, resolveCdnPublicUrlForServer } from '../../../../tools/$provideCdnForServer';
9
9
  import { $provideExecutionToolsForServer } from '../../../../tools/$provideExecutionToolsForServer';
10
+ import { $provideServer } from '../../../../tools/$provideServer';
10
11
  import { getGeneratedImageCdnKey } from '../../../../utils/cdn/utils/getGeneratedImageCdnKey';
11
12
  import { ensureGeneratedImage } from '../../../../utils/imageGeneration/ensureGeneratedImage';
12
13
  import { filenameToPrompt } from '../../../../utils/normalization/filenameToPrompt';
@@ -47,6 +48,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
47
48
 
48
49
  const prompt = filenameToPrompt(filename);
49
50
  const executionTools = await $provideExecutionToolsForServer();
51
+ const providedServer = await $provideServer();
50
52
  const llmTools = getSingleLlmExecutionTools(executionTools.llm) as LlmExecutionTools;
51
53
 
52
54
  if (!llmTools.callImageGenerationModel) {
@@ -89,7 +91,9 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
89
91
  const imageBuffer = await imageResponse.arrayBuffer();
90
92
  const buffer = Buffer.from(imageBuffer);
91
93
 
92
- const cdn = $provideCdnForServer();
94
+ const cdn = $provideCdnForServer({
95
+ cdnPublicUrl: resolveCdnPublicUrlForServer(providedServer.publicUrl),
96
+ });
93
97
  const cdnKey = getGeneratedImageCdnKey({ filename, pathPrefix: cdn.pathPrefix });
94
98
  await cdn.setItem(cdnKey, {
95
99
  type: 'image/png',
@@ -0,0 +1,51 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { resolveUserChatWorkerInternalToken } from '@/src/utils/userChat';
3
+ import { getLocalAgentRunnerLimits } from '@/src/utils/serverLimits';
4
+
5
+ /**
6
+ * Loads local agent-runner limits for the foreground CLI worker.
7
+ */
8
+ export async function GET(request: Request) {
9
+ return handleAgentRunnerLimitsRequest(request);
10
+ }
11
+
12
+ /**
13
+ * Loads local agent-runner limits for the foreground CLI worker.
14
+ */
15
+ export async function POST(request: Request) {
16
+ return handleAgentRunnerLimitsRequest(request);
17
+ }
18
+
19
+ /**
20
+ * Validates authorization and returns the current local runner retry limits.
21
+ *
22
+ * @param request - Incoming route request.
23
+ * @returns Local runner limits response.
24
+ */
25
+ async function handleAgentRunnerLimitsRequest(request: Request) {
26
+ if (!isAuthorizedInternalWorkerRequest(request)) {
27
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
28
+ }
29
+
30
+ try {
31
+ return NextResponse.json(await getLocalAgentRunnerLimits());
32
+ } catch (error) {
33
+ return NextResponse.json(
34
+ {
35
+ error: error instanceof Error ? error.message : 'Failed to load local agent runner limits.',
36
+ },
37
+ { status: 500 },
38
+ );
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Validates the shared internal worker token.
44
+ *
45
+ * @param request - Incoming route request.
46
+ * @returns `true` when the internal worker token matches.
47
+ */
48
+ function isAuthorizedInternalWorkerRequest(request: Request): boolean {
49
+ const token = request.headers.get('x-user-chat-worker-token');
50
+ return token === resolveUserChatWorkerInternalToken();
51
+ }
@@ -3,15 +3,22 @@ import { NextRequest, NextResponse } from 'next/server';
3
3
  import { spaceTrim } from 'spacetrim';
4
4
  import { assertsError } from '../../../../../../src/errors/assertsError';
5
5
  import { LimitReachedError } from '../../../../../../src/errors/LimitReachedError';
6
+ import { NotAllowed } from '../../../../../../src/errors/NotAllowed';
6
7
  import { UnexpectedError } from '../../../../../../src/errors/UnexpectedError';
7
8
  import { $getTableName } from '../../../database/$getTableName';
8
9
  import { $provideSupabase } from '../../../database/$provideSupabase';
9
10
  import type { AgentsServerDatabase } from '../../../database/schema';
10
- import { $provideCdnForServer } from '../../../tools/$provideCdnForServer';
11
+ import {
12
+ $provideCdnForServer,
13
+ isSelfContainedS3StorageSelected,
14
+ resolveCdnPublicUrlForServer,
15
+ } from '../../../tools/$provideCdnForServer';
16
+ import { $provideServer } from '../../../tools/$provideServer';
11
17
  import { getSafeCdnPath } from '../../../utils/cdn/utils/getSafeCdnPath';
12
18
  import { FILE_SECURITY_CHECKERS } from '../../../file-security-checkers';
13
19
  import { getUserIdFromRequest } from '../../../utils/getUserIdFromRequest';
14
20
  import { getMaxFileUploadSizeBytes } from '../../../utils/serverLimits';
21
+ import { resolveFileUploadAvailability } from '../../../utils/upload/fileUploadAvailability';
15
22
  import { validateMimeType } from '../../../utils/validators/validateMimeType';
16
23
 
17
24
  /**
@@ -47,6 +54,13 @@ type ParsedUploadRequest = {
47
54
  contentType: string;
48
55
  };
49
56
 
57
+ /**
58
+ * Server context returned by `$provideServer`.
59
+ *
60
+ * @private
61
+ */
62
+ type ProvidedServer = Awaited<ReturnType<typeof $provideServer>>;
63
+
50
64
  /**
51
65
  * Normalizes upload purpose to a non-empty string.
52
66
  *
@@ -182,11 +196,33 @@ async function updateUploadedFileSecurityResult(
182
196
  }
183
197
  }
184
198
 
199
+ /**
200
+ * Ensures the current server/domain can accept file uploads.
201
+ *
202
+ * @param providedServer - Current server routing context.
203
+ * @throws `NotAllowed` when uploads would be published without a server domain.
204
+ * @private
205
+ */
206
+ function assertFileUploadAvailable(providedServer: ProvidedServer): void {
207
+ const fileUploadAvailability = resolveFileUploadAvailability({
208
+ serverId: providedServer.id,
209
+ serverPublicUrl: providedServer.publicUrl,
210
+ isSelfContainedS3StorageSelected: isSelfContainedS3StorageSelected(),
211
+ });
212
+
213
+ if (!fileUploadAvailability.isUploadAvailable) {
214
+ throw new NotAllowed(fileUploadAvailability.message || 'File uploads are not available for this server.');
215
+ }
216
+ }
217
+
185
218
  /**
186
219
  * Handles file upload requests.
187
220
  */
188
221
  export async function POST(request: NextRequest) {
189
222
  try {
223
+ const providedServer = await $provideServer();
224
+ assertFileUploadAvailable(providedServer);
225
+
190
226
  const { file, pathname, purpose, contentType } = await parseUploadRequest(request);
191
227
  const fileBuffer = Buffer.from(await file.arrayBuffer());
192
228
  const maxFileSize = await getMaxFileUploadSizeBytes();
@@ -201,7 +237,9 @@ export async function POST(request: NextRequest) {
201
237
  );
202
238
  }
203
239
 
204
- const cdn = $provideCdnForServer();
240
+ const cdn = $provideCdnForServer({
241
+ cdnPublicUrl: resolveCdnPublicUrlForServer(providedServer.publicUrl),
242
+ });
205
243
  const storageUrl = cdn.getItemUrl(pathname).href;
206
244
  const userId = await getUserIdFromRequest(request);
207
245
 
@@ -227,17 +265,15 @@ export async function POST(request: NextRequest) {
227
265
 
228
266
  console.error('Upload failed:', error);
229
267
 
230
- return new Response(
231
- JSON.stringify(
232
- serializeError(error),
233
- // <- TODO: [🐱‍🚀] Rename `serializeError` to `errorToJson`
234
- null,
235
- 4,
236
- // <- TODO: [🐱‍🚀] Allow to configure pretty print for agent server
237
- ),
268
+ const serializedError = serializeError(error);
269
+
270
+ return NextResponse.json(
271
+ {
272
+ ...serializedError,
273
+ error: serializedError.message,
274
+ },
238
275
  {
239
- status: 400, // <- TODO: [🐱‍🚀] Make `errorToHttpStatusCode`
240
- headers: { 'Content-Type': 'application/json' },
276
+ status: error instanceof NotAllowed ? 403 : 400, // <- TODO: [🐱‍🚀] Make `errorToHttpStatusCode`
241
277
  },
242
278
  );
243
279
  }
@@ -16,6 +16,7 @@ import {
16
16
  SERVER_LANGUAGE_METADATA_KEY,
17
17
  } from '../languages/ServerLanguageRegistry';
18
18
  import { $provideServer } from '../tools/$provideServer';
19
+ import { isSelfContainedS3StorageSelected } from '../tools/$provideCdnForServer';
19
20
  import { loadAgentOrganizationState } from '../utils/agentOrganization/loadAgentOrganizationState';
20
21
  import type { AgentOrganizationAgent, AgentOrganizationFolder } from '../utils/agentOrganization/types';
21
22
  import { getAgentNaming } from '../utils/getAgentNaming';
@@ -50,6 +51,7 @@ import {
50
51
  SHIBBOLETH_AUTHENTICATION_METADATA_KEYS,
51
52
  resolveShibbolethAuthenticationMenuStatus,
52
53
  } from '../constants/shibbolethAuth';
54
+ import { resolveFileUploadAvailability } from '../utils/upload/fileUploadAvailability';
53
55
  import '@prisma/studio-core/ui/index.css';
54
56
  import './globals.css';
55
57
 
@@ -267,6 +269,7 @@ export default async function RootLayout({
267
269
  const currentUserPromise = getCurrentUser();
268
270
  const isAdminPromise = isUserAdmin();
269
271
  const isGlobalAdminPromise = isUserGlobalAdmin();
272
+ const providedServerPromise = $provideServer();
270
273
  const serverVisibilityPromise = getServerVisibility();
271
274
  const agentNamingPromise = getAgentNaming();
272
275
  const organizationStatePromise = isAdminPromise.then((isAdmin) =>
@@ -274,6 +277,13 @@ export default async function RootLayout({
274
277
  );
275
278
  const chatPreferencesPromise = getDefaultChatPreferences();
276
279
  const defaultIsNotificationsOnPromise = getDefaultIsNotificationsOn();
280
+ const fileUploadAvailabilityPromise = providedServerPromise.then((providedServer) =>
281
+ resolveFileUploadAvailability({
282
+ serverId: providedServer.id,
283
+ serverPublicUrl: providedServer.publicUrl,
284
+ isSelfContainedS3StorageSelected: isSelfContainedS3StorageSelected(),
285
+ }),
286
+ );
277
287
  const customStylesheetCssPromise = resolveOptionalLayoutText(
278
288
  'custom stylesheet CSS',
279
289
  getAggregatedCustomStylesheetCss,
@@ -340,6 +350,7 @@ export default async function RootLayout({
340
350
  federatedServers,
341
351
  footerLinks,
342
352
  serverVisibility,
353
+ fileUploadAvailability,
343
354
  ] = await Promise.all([
344
355
  isAdminPromise,
345
356
  isGlobalAdminPromise,
@@ -356,6 +367,7 @@ export default async function RootLayout({
356
367
  federatedServersPromise,
357
368
  footerLinksPromise,
358
369
  serverVisibilityPromise,
370
+ fileUploadAvailabilityPromise,
359
371
  ]);
360
372
 
361
373
  const serverName = layoutMetadata.SERVER_NAME || 'Promptbook Agents Server';
@@ -429,6 +441,7 @@ export default async function RootLayout({
429
441
  defaultChatVisualMode={defaultChatVisualMode}
430
442
  defaultAgentAvatarVisualId={defaultAgentAvatarVisualId}
431
443
  webPushPublicKey={webPushPublicKey}
444
+ fileUploadAvailability={fileUploadAvailability}
432
445
  >
433
446
  {children}
434
447
  </LayoutWrapper>
@@ -186,10 +186,7 @@ export function AgentProfile(props: AgentProfileProps) {
186
186
  ) : (
187
187
  <div className="flex h-full w-full items-center justify-center overflow-hidden p-4 md:p-8">
188
188
  {/* Keep built-in visuals inside a centered square stage so different avatar renderers fit the tall profile card consistently. */}
189
- <div
190
- className="flex h-full w-full max-h-[80%] max-w-[80%] items-center justify-center"
191
- style={{ aspectRatio: '1 / 1' }}
192
- >
189
+ <div className="flex aspect-square w-[80%] items-center justify-center">
193
190
  <AgentAvatar
194
191
  agent={agent}
195
192
  baseUrl={publicUrl}
@@ -0,0 +1,50 @@
1
+ 'use client';
2
+
3
+ import { createContext, useContext, type ReactNode } from 'react';
4
+ import {
5
+ AVAILABLE_FILE_UPLOAD,
6
+ type FileUploadAvailability,
7
+ } from '../../utils/upload/fileUploadAvailability';
8
+
9
+ /**
10
+ * Context carrying file upload availability for the current server/domain.
11
+ */
12
+ const FileUploadAvailabilityContext = createContext<FileUploadAvailability>(AVAILABLE_FILE_UPLOAD);
13
+
14
+ /**
15
+ * Props consumed by `FileUploadAvailabilityProvider`.
16
+ */
17
+ type FileUploadAvailabilityProviderProps = {
18
+ /**
19
+ * Current upload availability state.
20
+ */
21
+ readonly value: FileUploadAvailability;
22
+
23
+ /**
24
+ * Nested app content.
25
+ */
26
+ readonly children: ReactNode;
27
+ };
28
+
29
+ /**
30
+ * Provides file upload availability to upload controls.
31
+ *
32
+ * @param props - Provider props.
33
+ * @returns Provider-wrapped children.
34
+ */
35
+ export function FileUploadAvailabilityProvider(props: FileUploadAvailabilityProviderProps) {
36
+ return (
37
+ <FileUploadAvailabilityContext.Provider value={props.value}>
38
+ {props.children}
39
+ </FileUploadAvailabilityContext.Provider>
40
+ );
41
+ }
42
+
43
+ /**
44
+ * Reads the current file upload availability state.
45
+ *
46
+ * @returns Current upload availability state.
47
+ */
48
+ export function useFileUploadAvailability(): FileUploadAvailability {
49
+ return useContext(FileUploadAvailabilityContext);
50
+ }
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+
3
+ import { AlertTriangle } from 'lucide-react';
4
+ import Link from 'next/link';
5
+ import { useFileUploadAvailability } from './FileUploadAvailabilityContext';
6
+
7
+ /**
8
+ * Props consumed by `FileUploadUnavailableNotice`.
9
+ */
10
+ type FileUploadUnavailableNoticeProps = {
11
+ /**
12
+ * Optional classes appended to the notice root.
13
+ */
14
+ readonly className?: string;
15
+ };
16
+
17
+ /**
18
+ * Shows a shared notice when file uploads are disabled for the current server.
19
+ *
20
+ * @param props - Notice props.
21
+ * @returns Upload notice or `null` when uploads are available.
22
+ */
23
+ export function FileUploadUnavailableNotice({ className }: FileUploadUnavailableNoticeProps) {
24
+ const fileUploadAvailability = useFileUploadAvailability();
25
+
26
+ if (fileUploadAvailability.isUploadAvailable || !fileUploadAvailability.message) {
27
+ return null;
28
+ }
29
+
30
+ return (
31
+ <div
32
+ className={`flex items-start gap-3 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900 ${
33
+ className || ''
34
+ }`}
35
+ >
36
+ <AlertTriangle className="mt-0.5 h-4 w-4 flex-shrink-0" aria-hidden="true" />
37
+ <div className="space-y-1">
38
+ <p className="font-medium">{fileUploadAvailability.message}</p>
39
+ <Link href="/admin/servers" className="inline-flex font-semibold underline underline-offset-2">
40
+ Open server/domain settings
41
+ </Link>
42
+ </div>
43
+ </div>
44
+ );
45
+ }
@@ -9,7 +9,6 @@ import { HamburgerMenu } from '../../../../../src/book-components/_common/Hambur
9
9
  import { useMenuHoisting } from '../../../../../src/book-components/_common/MenuHoisting/MenuHoistingContext';
10
10
  import { just } from '../../../../../src/utils/organization/just';
11
11
  import { getVisibleCommitmentDefinitions } from '../../utils/getVisibleCommitmentDefinitions';
12
- import { pushWithHeadless, useIsHeadless } from '../_utils/headlessParam';
13
12
  import { useInstallPromptState, type AgentContextMenuRenamePayload } from '../AgentContextMenu/AgentContextMenu';
14
13
  import { useAgentNaming } from '../AgentNaming/AgentNamingContext';
15
14
  import { QrCodeModal } from '../AgentProfile/QrCodeModal';
@@ -58,11 +57,9 @@ export function Header(props: HeaderProps) {
58
57
  feedbackMode = 'stars',
59
58
  shibbolethAuthenticationStatus,
60
59
  } = props;
61
-
62
60
  const [isChangePasswordOpen, setIsChangePasswordOpen] = useState(false);
63
61
  const router = useRouter();
64
62
  const pathname = usePathname();
65
- const isHeadless = useIsHeadless();
66
63
  const menuHoisting = useMenuHoisting();
67
64
  const mobileMenuHoisting = useMobileMenuHoisting();
68
65
  const { naming } = useAgentNaming();
@@ -73,13 +70,6 @@ export function Header(props: HeaderProps) {
73
70
  () => buildDocumentationDropdownItems(visibleDocumentationCommitments, t),
74
71
  [t, visibleDocumentationCommitments],
75
72
  );
76
-
77
- const fallbackNavigateToHref = useCallback(
78
- (href: string) => {
79
- pushWithHeadless(router, href, isHeadless);
80
- },
81
- [isHeadless, router],
82
- );
83
73
  const hoistedMobileMenuItems = mobileMenuHoisting?.menuItems || EMPTY_HOISTED_MOBILE_MENU_ITEMS;
84
74
  const {
85
75
  cancelMenuClose,
@@ -201,7 +191,6 @@ export function Header(props: HeaderProps) {
201
191
  isAdmin,
202
192
  isAuthenticated: Boolean(currentUser),
203
193
  isInstalled,
204
- navigateToHref: fallbackNavigateToHref,
205
194
  namingPlural: naming.plural,
206
195
  namingSingular: naming.singular,
207
196
  onAgentRenamed: handleAgentRenamedFromHeader,
@@ -44,7 +44,6 @@ type UseHeaderAgentMenusOptions = {
44
44
  readonly isAdmin: boolean;
45
45
  readonly isAuthenticated: boolean;
46
46
  readonly isInstalled: boolean;
47
- readonly navigateToHref: (href: string) => void;
48
47
  readonly namingPlural: string;
49
48
  readonly namingSingular: string;
50
49
  readonly onAgentRenamed: (payload: AgentContextMenuRenamePayload) => void;
@@ -160,7 +159,6 @@ export function useHeaderAgentMenus({
160
159
  isAdmin,
161
160
  isAuthenticated,
162
161
  isInstalled,
163
- navigateToHref,
164
162
  namingPlural,
165
163
  namingSingular,
166
164
  onAgentRenamed,
@@ -214,9 +212,6 @@ export function useHeaderAgentMenus({
214
212
  openNewAgentDialog,
215
213
  dialog: newAgentDialog,
216
214
  } = useNewAgentDialog({
217
- onCreated: ({ targetPath }) => {
218
- navigateToHref(targetPath);
219
- },
220
215
  onCreateFailed: async (error) => {
221
216
  await showNewAgentFailure('Failed to create agent:', error, namingSingular, translate);
222
217
  },
@@ -16,6 +16,7 @@ import { ChatVisualModeProvider } from '../ChatVisualMode/ChatVisualModeProvider
16
16
  import { ClientVersionMismatchListener } from '../ClientVersion/ClientVersionMismatchListener';
17
17
  import { ChatEnterBehaviorPreferencesProvider } from '../ChatEnterBehavior/ChatEnterBehaviorPreferencesProvider';
18
18
  import { HomepageOptimisticNavigation } from '../Homepage/HomepageOptimisticNavigation';
19
+ import { FileUploadAvailabilityProvider } from '../FileUploadAvailability/FileUploadAvailabilityContext';
19
20
  import { Footer, type FooterLink } from '../Footer/Footer';
20
21
  import { Header } from '../Header/Header';
21
22
  import { MobileMenuHoistingProvider } from '../Header/MobileMenuHoistingContext';
@@ -30,6 +31,7 @@ import { SoundSystemProvider } from '../SoundSystemProvider/SoundSystemProvider'
30
31
  import { ThemeModeProvider } from '../ThemeMode/ThemeModeProvider';
31
32
  import { ViewportHeightController } from '../ViewportHeightController/ViewportHeightController';
32
33
  import type { ControlPanelOptionAvailability } from '../../utils/getControlPanelOptionAvailability';
34
+ import type { FileUploadAvailability } from '../../utils/upload/fileUploadAvailability';
33
35
 
34
36
  /**
35
37
  * Props for layout wrapper.
@@ -73,6 +75,10 @@ type LayoutWrapperProps = {
73
75
  defaultChatVisualMode: string;
74
76
  defaultAgentAvatarVisualId: AvatarVisualId;
75
77
  webPushPublicKey: string | null;
78
+ /**
79
+ * Current file upload availability for the active server/domain.
80
+ */
81
+ fileUploadAvailability: FileUploadAvailability;
76
82
  };
77
83
 
78
84
  /**
@@ -105,6 +111,7 @@ export function LayoutWrapper({
105
111
  defaultChatVisualMode,
106
112
  defaultAgentAvatarVisualId,
107
113
  webPushPublicKey,
114
+ fileUploadAvailability,
108
115
  }: LayoutWrapperProps) {
109
116
  const pathname = usePathname();
110
117
  const searchParams = useSearchParams();
@@ -127,83 +134,85 @@ export function LayoutWrapper({
127
134
  defaultLanguage={defaultServerLanguage}
128
135
  isServerLanguageEnforced={isServerLanguageEnforced}
129
136
  >
130
- <DefaultAgentAvatarVisualProvider defaultAgentAvatarVisualId={defaultAgentAvatarVisualId}>
131
- <ThemeModeProvider defaultThemeMode={defaultThemeMode}>
132
- <ChatVisualModeProvider defaultChatVisualMode={defaultChatVisualMode}>
133
- <AsyncDialogsProvider>
134
- <AgentNamingProvider naming={agentNaming}>
135
- <LegacyUiAutoTranslator />
136
- <PrivateModePreferencesProvider>
137
- <SelfLearningPreferencesProvider>
138
- <SoundSystemProvider
139
- initialIsSoundsOn={defaultIsSoundsOn}
140
- initialIsVibrationOn={defaultIsVibrationOn}
141
- >
142
- <NotificationsProvider>
143
- <BrowserPushNotificationsProvider
144
- defaultEnabled={defaultIsNotificationsOn}
145
- pushPublicKey={webPushPublicKey}
146
- isMetadataAvailable={controlPanelOptionAvailability.notifications}
147
- >
148
- <ChatEnterBehaviorPreferencesProvider>
149
- <ClientVersionMismatchListener />
150
- <ViewportHeightController />
151
- <NavigationProgressBar />
152
- <MenuHoistingProvider>
153
- <MobileMenuHoistingProvider>
154
- <MetadataFlagsProvider
155
- value={{
156
- isExperimentalPwaAppEnabled,
157
- controlPanelOptionAvailability,
158
- }}
159
- >
160
- {shouldRenderMinimalShell ? (
161
- <main className={minimalMainClassName}>
162
- {children}
163
- </main>
164
- ) : (
165
- <div className="agents-server-app-shell flex flex-col">
166
- <Header
167
- isAdmin={isAdmin}
168
- isGlobalAdmin={isGlobalAdmin}
169
- currentUser={currentUser}
170
- serverName={serverName}
171
- serverLogoUrl={serverLogoUrl}
172
- agents={agents}
173
- agentFolders={agentFolders}
174
- federatedServers={federatedServers}
175
- isExperimental={isExperimental}
176
- feedbackMode={feedbackMode}
177
- shibbolethAuthenticationStatus={
178
- shibbolethAuthenticationStatus
179
- }
180
- />
181
- <main className={mainClassName}>
182
- <HomepageOptimisticNavigation
183
- pathname={pathname}
184
- >
185
- {children}
186
- </HomepageOptimisticNavigation>
137
+ <FileUploadAvailabilityProvider value={fileUploadAvailability}>
138
+ <DefaultAgentAvatarVisualProvider defaultAgentAvatarVisualId={defaultAgentAvatarVisualId}>
139
+ <ThemeModeProvider defaultThemeMode={defaultThemeMode}>
140
+ <ChatVisualModeProvider defaultChatVisualMode={defaultChatVisualMode}>
141
+ <AsyncDialogsProvider>
142
+ <AgentNamingProvider naming={agentNaming}>
143
+ <LegacyUiAutoTranslator />
144
+ <PrivateModePreferencesProvider>
145
+ <SelfLearningPreferencesProvider>
146
+ <SoundSystemProvider
147
+ initialIsSoundsOn={defaultIsSoundsOn}
148
+ initialIsVibrationOn={defaultIsVibrationOn}
149
+ >
150
+ <NotificationsProvider>
151
+ <BrowserPushNotificationsProvider
152
+ defaultEnabled={defaultIsNotificationsOn}
153
+ pushPublicKey={webPushPublicKey}
154
+ isMetadataAvailable={controlPanelOptionAvailability.notifications}
155
+ >
156
+ <ChatEnterBehaviorPreferencesProvider>
157
+ <ClientVersionMismatchListener />
158
+ <ViewportHeightController />
159
+ <NavigationProgressBar />
160
+ <MenuHoistingProvider>
161
+ <MobileMenuHoistingProvider>
162
+ <MetadataFlagsProvider
163
+ value={{
164
+ isExperimentalPwaAppEnabled,
165
+ controlPanelOptionAvailability,
166
+ }}
167
+ >
168
+ {shouldRenderMinimalShell ? (
169
+ <main className={minimalMainClassName}>
170
+ {children}
187
171
  </main>
188
- {isFooterShown && !isFooterHiddenOnPage && (
189
- <Footer extraLinks={footerLinks} />
190
- )}
191
- </div>
192
- )}
193
- </MetadataFlagsProvider>
194
- </MobileMenuHoistingProvider>
195
- </MenuHoistingProvider>
196
- </ChatEnterBehaviorPreferencesProvider>
197
- </BrowserPushNotificationsProvider>
198
- </NotificationsProvider>
199
- </SoundSystemProvider>
200
- </SelfLearningPreferencesProvider>
201
- </PrivateModePreferencesProvider>
202
- </AgentNamingProvider>
203
- </AsyncDialogsProvider>
204
- </ChatVisualModeProvider>
205
- </ThemeModeProvider>
206
- </DefaultAgentAvatarVisualProvider>
172
+ ) : (
173
+ <div className="agents-server-app-shell flex flex-col">
174
+ <Header
175
+ isAdmin={isAdmin}
176
+ isGlobalAdmin={isGlobalAdmin}
177
+ currentUser={currentUser}
178
+ serverName={serverName}
179
+ serverLogoUrl={serverLogoUrl}
180
+ agents={agents}
181
+ agentFolders={agentFolders}
182
+ federatedServers={federatedServers}
183
+ isExperimental={isExperimental}
184
+ feedbackMode={feedbackMode}
185
+ shibbolethAuthenticationStatus={
186
+ shibbolethAuthenticationStatus
187
+ }
188
+ />
189
+ <main className={mainClassName}>
190
+ <HomepageOptimisticNavigation
191
+ pathname={pathname}
192
+ >
193
+ {children}
194
+ </HomepageOptimisticNavigation>
195
+ </main>
196
+ {isFooterShown && !isFooterHiddenOnPage && (
197
+ <Footer extraLinks={footerLinks} />
198
+ )}
199
+ </div>
200
+ )}
201
+ </MetadataFlagsProvider>
202
+ </MobileMenuHoistingProvider>
203
+ </MenuHoistingProvider>
204
+ </ChatEnterBehaviorPreferencesProvider>
205
+ </BrowserPushNotificationsProvider>
206
+ </NotificationsProvider>
207
+ </SoundSystemProvider>
208
+ </SelfLearningPreferencesProvider>
209
+ </PrivateModePreferencesProvider>
210
+ </AgentNamingProvider>
211
+ </AsyncDialogsProvider>
212
+ </ChatVisualModeProvider>
213
+ </ThemeModeProvider>
214
+ </DefaultAgentAvatarVisualProvider>
215
+ </FileUploadAvailabilityProvider>
207
216
  </ServerLanguageProvider>
208
217
  );
209
218
  }