@promptbook/cli 0.112.0-118 → 0.112.0-119

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 (59) hide show
  1. package/apps/agents-server/src/app/api/page-preview/check/route.ts +31 -0
  2. package/apps/agents-server/src/app/api/page-preview/screenshot/route.ts +57 -0
  3. package/apps/agents-server/src/app/api/upload/route.ts +10 -1
  4. package/apps/agents-server/src/app/s3/[first]/[second]/[hash]/[filename]/route.ts +52 -0
  5. package/apps/agents-server/src/database/$provideClientSql.ts +37 -0
  6. package/apps/agents-server/src/database/$provideSupabaseForServer.ts +41 -0
  7. package/apps/agents-server/src/tools/$provideCdnForServer.ts +24 -0
  8. package/apps/agents-server/src/utils/cdn/classes/DigitalOceanSpaces.ts +30 -2
  9. package/apps/agents-server/src/utils/cdn/utils/getUserFileCdnKey.ts +10 -3
  10. package/apps/agents-server/src/utils/iframe/checkIfUrlCanBeEmbedded.ts +68 -0
  11. package/esm/index.es.js +26 -3
  12. package/esm/index.es.js.map +1 -1
  13. package/esm/src/book-components/BookEditor/BookEditor.d.ts +1 -1
  14. package/esm/src/book-components/BookEditor/BookEditorForClient.d.ts +1 -1
  15. package/esm/src/book-components/Chat/Chat/CitationIframePreview.d.ts +20 -0
  16. package/esm/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
  17. package/esm/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +1 -1
  18. package/esm/src/book-components/_common/Modal/Modal.d.ts +1 -1
  19. package/esm/src/book-components/icons/AboutIcon.d.ts +1 -1
  20. package/esm/src/book-components/icons/DownloadIcon.d.ts +1 -1
  21. package/esm/src/book-components/icons/ExitFullscreenIcon.d.ts +1 -1
  22. package/esm/src/book-components/icons/FullscreenIcon.d.ts +1 -1
  23. package/esm/src/version.d.ts +1 -1
  24. package/package.json +1 -1
  25. package/src/book-3.0/LiteAgent.ts +1 -1
  26. package/src/book-components/BookEditor/BookEditor.tsx +6 -6
  27. package/src/book-components/BookEditor/BookEditorForClient.tsx +1 -1
  28. package/src/book-components/Chat/Chat/Chat.module.css +45 -0
  29. package/src/book-components/Chat/Chat/ChatCitationModal.tsx +2 -2
  30. package/src/book-components/Chat/Chat/CitationIframePreview.tsx +83 -0
  31. package/src/book-components/_common/Dropdown/Dropdown.tsx +1 -1
  32. package/src/book-components/_common/MenuHoisting/MenuHoistingContext.tsx +1 -1
  33. package/src/book-components/_common/Modal/Modal.tsx +1 -1
  34. package/src/book-components/icons/AboutIcon.tsx +1 -1
  35. package/src/book-components/icons/DownloadIcon.tsx +1 -1
  36. package/src/book-components/icons/ExitFullscreenIcon.tsx +1 -1
  37. package/src/book-components/icons/FullscreenIcon.tsx +1 -1
  38. package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +31 -1
  39. package/src/execution/createPipelineExecutor/getKnowledgeForTask.ts +1 -1
  40. package/src/llm-providers/openai/OpenAiAgentKitExecutionToolsToolBuilder.ts +1 -1
  41. package/src/llm-providers/openai/OpenAiAssistantExecutionToolsToolRunner.ts +1 -1
  42. package/src/llm-providers/openai/OpenAiVectorStoreKnowledgeSourcePreparer.ts +1 -1
  43. package/src/other/templates/getTemplatesPipelineCollection.ts +732 -687
  44. package/src/scripting/javascript/JavascriptEvalExecutionTools.ts +1 -1
  45. package/src/version.ts +2 -2
  46. package/src/versions.txt +1 -0
  47. package/umd/index.umd.js +26 -3
  48. package/umd/index.umd.js.map +1 -1
  49. package/umd/src/book-components/BookEditor/BookEditor.d.ts +1 -1
  50. package/umd/src/book-components/BookEditor/BookEditorForClient.d.ts +1 -1
  51. package/umd/src/book-components/Chat/Chat/CitationIframePreview.d.ts +20 -0
  52. package/umd/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
  53. package/umd/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +1 -1
  54. package/umd/src/book-components/_common/Modal/Modal.d.ts +1 -1
  55. package/umd/src/book-components/icons/AboutIcon.d.ts +1 -1
  56. package/umd/src/book-components/icons/DownloadIcon.d.ts +1 -1
  57. package/umd/src/book-components/icons/ExitFullscreenIcon.d.ts +1 -1
  58. package/umd/src/book-components/icons/FullscreenIcon.d.ts +1 -1
  59. package/umd/src/version.d.ts +1 -1
@@ -1,4 +1,4 @@
1
- import { CSSProperties } from 'react';
1
+ import { type CSSProperties } from 'react';
2
2
  import type { Promisable } from 'type-fest';
3
3
  import type { string_book } from '../../book-2.0/agent-source/string_book';
4
4
  import type { number_percent } from '../../types/number_percent';
@@ -1,4 +1,4 @@
1
- import { BookEditorProps } from './BookEditor';
1
+ import type { BookEditorProps } from './BookEditor';
2
2
  /**
3
3
  * Renders a book editor
4
4
  *
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Props for the citation iframe preview component.
3
+ *
4
+ * @private component of `<ChatCitationModal/>`
5
+ */
6
+ export type CitationIframePreviewProps = {
7
+ src: string;
8
+ title: string;
9
+ };
10
+ /**
11
+ * Renders a citation URL preview as an iframe when the target page allows embedding,
12
+ * or falls back to a server-side screenshot with an "Open in new tab" link when it
13
+ * does not (e.g. X-Frame-Options: DENY / SAMEORIGIN).
14
+ *
15
+ * Embedding capability is determined by `GET /api/page-preview/check?url=<url>`.
16
+ * If that endpoint is unavailable the component falls back to the iframe directly.
17
+ *
18
+ * @private component of `<ChatCitationModal/>`
19
+ */
20
+ export declare function CitationIframePreview({ src, title }: CitationIframePreviewProps): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,4 @@
1
- import { ReactNode } from 'react';
1
+ import { type ReactNode } from 'react';
2
2
  /**
3
3
  * Props for dropdown.
4
4
  */
@@ -1,4 +1,4 @@
1
- import { ReactNode } from 'react';
1
+ import { type ReactNode } from 'react';
2
2
  /**
3
3
  * Item that can be hoisted to the top menu
4
4
  *
@@ -1,4 +1,4 @@
1
- import { ReactNode } from 'react';
1
+ import { type ReactNode } from 'react';
2
2
  /**
3
3
  * Handles modal.
4
4
  *
@@ -1,4 +1,4 @@
1
- import { SVGProps } from 'react';
1
+ import type { SVGProps } from 'react';
2
2
  /**
3
3
  * Renders an information/about icon.
4
4
  *
@@ -1,4 +1,4 @@
1
- import { SVGProps } from 'react';
1
+ import type { SVGProps } from 'react';
2
2
  /**
3
3
  * Renders a download icon.
4
4
  *
@@ -1,4 +1,4 @@
1
- import { JSX } from 'react';
1
+ import type { JSX } from 'react';
2
2
  /**
3
3
  * Renders an icon that represents the exit fullscreen action
4
4
  *
@@ -1,4 +1,4 @@
1
- import { JSX } from 'react';
1
+ import type { JSX } from 'react';
2
2
  /**
3
3
  * Renders an icon that represents the fullscreen action
4
4
  *
@@ -15,7 +15,7 @@ export declare const BOOK_LANGUAGE_VERSION: string_semantic_version;
15
15
  export declare const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version;
16
16
  /**
17
17
  * Represents the version string of the Promptbook engine.
18
- * It follows semantic versioning (e.g., `0.112.0-117`).
18
+ * It follows semantic versioning (e.g., `0.112.0-118`).
19
19
  *
20
20
  * @generated
21
21
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptbook/cli",
3
- "version": "0.112.0-118",
3
+ "version": "0.112.0-119",
4
4
  "description": "Promptbook: Create persistent AI agents that turn your company's scattered knowledge into action",
5
5
  "private": false,
6
6
  "sideEffects": false,
@@ -305,7 +305,7 @@ async function resolveLiteAgentScriptExecutionTools(
305
305
  if (options.scriptExecutionTools) {
306
306
  return Array.isArray(options.scriptExecutionTools)
307
307
  ? options.scriptExecutionTools
308
- : [options.scriptExecutionTools];
308
+ : [options.scriptExecutionTools as ScriptExecutionTools];
309
309
  }
310
310
 
311
311
  return $provideScriptingForNode({
@@ -2,7 +2,7 @@
2
2
  // <- Note: [👲] 'use client' is enforced by Next.js when building the https://book-components.ptbk.io/ but in ideal case,
3
3
  // this would not be here because the `@promptbook/components` package should be React library independent of Next.js specifics
4
4
 
5
- import { CSSProperties, useState } from 'react';
5
+ import { type CSSProperties, useState } from 'react';
6
6
  import { createPortal } from 'react-dom';
7
7
  import type { Promisable } from 'type-fest';
8
8
  import type { string_book } from '../../book-2.0/agent-source/string_book';
@@ -14,8 +14,8 @@ import type { string_css_value } from '../../types/string_markdown';
14
14
  import { countLines } from '../../utils/expectation-counters/countLines';
15
15
  import type { HoistedMenuItem } from '../_common/MenuHoisting/MenuHoistingContext';
16
16
  import { classNames } from '../_common/react-utils/classNames';
17
- import { DEFAULT_IS_VERBOSE } from './BookEditorBrowserConfig';
18
17
  import styles from './BookEditor.module.css';
18
+ import { DEFAULT_IS_VERBOSE } from './BookEditorBrowserConfig';
19
19
  import { BookEditorMonaco } from './BookEditorMonaco';
20
20
  import type { BookEditorTheme } from './BookEditorTheme';
21
21
  import { BOOK_EDITOR_RENDER_THEME, resolveBookEditorRenderTheme } from './BookEditorTheme';
@@ -300,11 +300,11 @@ export function BookEditor(props: BookEditorProps) {
300
300
  isBorderRadiusDisabled = false,
301
301
  isReadonly = false,
302
302
  translations,
303
- isUploadButtonShown = true,
303
+ isUploadButtonShown = false,
304
304
  isCameraButtonShown,
305
- isDownloadButtonShown = true,
306
- isAboutButtonShown = true,
307
- isFullscreenButtonShown = true,
305
+ isDownloadButtonShown = false,
306
+ isAboutButtonShown = false,
307
+ isFullscreenButtonShown = false,
308
308
  sync,
309
309
  monacoModelPath,
310
310
  hoistedMenuItems,
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState } from 'react';
2
- import { BookEditorProps } from './BookEditor';
2
+ import type { BookEditorProps } from './BookEditor';
3
3
 
4
4
  type BookEditorComponent = typeof import('./BookEditor').BookEditor;
5
5
 
@@ -3311,6 +3311,51 @@
3311
3311
  display: block;
3312
3312
  }
3313
3313
 
3314
+ .citationIframeLoading {
3315
+ width: 100%;
3316
+ height: 60vh;
3317
+ min-height: 400px;
3318
+ display: flex;
3319
+ align-items: center;
3320
+ justify-content: center;
3321
+ color: #888;
3322
+ font-size: 0.9em;
3323
+ }
3324
+
3325
+ .citationScreenshotFallback {
3326
+ width: 100%;
3327
+ position: relative;
3328
+ display: flex;
3329
+ flex-direction: column;
3330
+ }
3331
+
3332
+ .citationScreenshotImage {
3333
+ width: 100%;
3334
+ max-height: 60vh;
3335
+ min-height: 400px;
3336
+ object-fit: cover;
3337
+ object-position: top;
3338
+ display: block;
3339
+ }
3340
+
3341
+ .citationScreenshotLink {
3342
+ display: block;
3343
+ text-align: center;
3344
+ padding: 10px 16px;
3345
+ background: #f0f0f0;
3346
+ color: #333;
3347
+ font-size: 0.9em;
3348
+ font-weight: 500;
3349
+ text-decoration: none;
3350
+ border-top: 1px solid #ddd;
3351
+ transition: background 0.15s;
3352
+ }
3353
+
3354
+ .citationScreenshotLink:hover {
3355
+ background: #e0e0e0;
3356
+ text-decoration: underline;
3357
+ }
3358
+
3314
3359
  .citationMetadata {
3315
3360
  background: #f8f8f8;
3316
3361
  padding: 16px;
@@ -8,6 +8,7 @@ import type { ChatParticipant } from '../types/ChatParticipant';
8
8
  import { getCitationLabel, isPlainTextCitation, resolveCitationPreviewUrl } from '../utils/citationHelpers';
9
9
  import type { ParsedCitation } from '../utils/parseCitationsFromContent';
10
10
  import styles from './Chat.module.css';
11
+ import { CitationIframePreview } from './CitationIframePreview';
11
12
  import type { ChatSoundSystem } from './ChatProps';
12
13
 
13
14
  /**
@@ -84,9 +85,8 @@ export function ChatCitationModal(props: ChatCitationModalProps) {
84
85
  }}
85
86
  />
86
87
  ) : (
87
- <iframe
88
+ <CitationIframePreview
88
89
  src={previewUrl ?? citation.source}
89
- className={styles.citationIframe}
90
90
  title={`Preview of ${label}`}
91
91
  />
92
92
  )}
@@ -0,0 +1,83 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import styles from './Chat.module.css';
5
+
6
+ /**
7
+ * Props for the citation iframe preview component.
8
+ *
9
+ * @private component of `<ChatCitationModal/>`
10
+ */
11
+ export type CitationIframePreviewProps = {
12
+ src: string;
13
+ title: string;
14
+ };
15
+
16
+ /**
17
+ * Internal status of the iframe embed check.
18
+ *
19
+ * @private type of `<CitationIframePreview/>`
20
+ */
21
+ type EmbedStatus = 'loading' | 'embed' | 'screenshot';
22
+
23
+ /**
24
+ * Renders a citation URL preview as an iframe when the target page allows embedding,
25
+ * or falls back to a server-side screenshot with an "Open in new tab" link when it
26
+ * does not (e.g. X-Frame-Options: DENY / SAMEORIGIN).
27
+ *
28
+ * Embedding capability is determined by `GET /api/page-preview/check?url=<url>`.
29
+ * If that endpoint is unavailable the component falls back to the iframe directly.
30
+ *
31
+ * @private component of `<ChatCitationModal/>`
32
+ */
33
+ export function CitationIframePreview({ src, title }: CitationIframePreviewProps) {
34
+ const [status, setStatus] = useState<EmbedStatus>('loading');
35
+
36
+ useEffect(() => {
37
+ let cancelled = false;
38
+
39
+ fetch(`/api/page-preview/check?url=${encodeURIComponent(src)}`)
40
+ .then((response) => response.json())
41
+ .then((data: { canEmbed: boolean }) => {
42
+ if (!cancelled) {
43
+ setStatus(data.canEmbed ? 'embed' : 'screenshot');
44
+ }
45
+ })
46
+ .catch(() => {
47
+ // API not available — fall back to iframe (e.g. outside agents-server)
48
+ if (!cancelled) {
49
+ setStatus('embed');
50
+ }
51
+ });
52
+
53
+ return () => {
54
+ cancelled = true;
55
+ };
56
+ }, [src]);
57
+
58
+ if (status === 'loading') {
59
+ return <div className={styles.citationIframeLoading}>Loading preview…</div>;
60
+ }
61
+
62
+ if (status === 'screenshot') {
63
+ return (
64
+ <div className={styles.citationScreenshotFallback}>
65
+ <img
66
+ src={`/api/page-preview/screenshot?url=${encodeURIComponent(src)}`}
67
+ alt={`Screenshot of ${title}`}
68
+ className={styles.citationScreenshotImage}
69
+ />
70
+ <a
71
+ href={src}
72
+ target="_blank"
73
+ rel="noopener noreferrer"
74
+ className={styles.citationScreenshotLink}
75
+ >
76
+ Open in new tab ↗
77
+ </a>
78
+ </div>
79
+ );
80
+ }
81
+
82
+ return <iframe src={src} className={styles.citationIframe} title={title} />;
83
+ }
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import React, { ReactNode, useState } from 'react';
3
+ import React, { type ReactNode, useState } from 'react';
4
4
  import { HamburgerMenu } from '../HamburgerMenu/HamburgerMenu';
5
5
  import { classNames } from '../react-utils/classNames';
6
6
  import styles from './Dropdown.module.css';
@@ -1,4 +1,4 @@
1
- import { createContext, ReactNode, useContext, useState } from 'react';
1
+ import { createContext, type ReactNode, useContext, useState } from 'react';
2
2
 
3
3
  /**
4
4
  * Item that can be hoisted to the top menu
@@ -1,4 +1,4 @@
1
- import { ReactNode, useEffect } from 'react';
1
+ import { type ReactNode, useEffect } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
3
  import { classNames } from '../react-utils/classNames';
4
4
  import styles from './Modal.module.css';
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { SVGProps } from 'react';
3
+ import type { SVGProps } from 'react';
4
4
 
5
5
  /**
6
6
  * Renders an information/about icon.
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { SVGProps } from 'react';
3
+ import type { SVGProps } from 'react';
4
4
 
5
5
  /**
6
6
  * Renders a download icon.
@@ -1,4 +1,4 @@
1
- import { JSX } from 'react';
1
+ import type { JSX } from 'react';
2
2
  import iconAsset from './ExitFullscreenIcon.svg';
3
3
  // <- TODO: [😺] Is this type of SVG import working correctly?
4
4
  // <- TODO: [😺] Try also the png import if SVG works
@@ -1,4 +1,4 @@
1
- import { JSX } from 'react';
1
+ import type { JSX } from 'react';
2
2
 
3
3
  /**
4
4
  * Renders an icon that represents the fullscreen action
@@ -34,6 +34,17 @@ const AGENTS_SERVER_NEXT_BUILD_ID_FILENAME = 'BUILD_ID';
34
34
  */
35
35
  const DEFAULT_AGENTS_SERVER_NEXT_DIST_DIRECTORY_NAME = '.next';
36
36
 
37
+ /**
38
+ * Node.js heap size limit (in MiB) injected into `NODE_OPTIONS` for the Next.js production build.
39
+ *
40
+ * Next.js webpack peaks at ~1.9 GiB on a fresh install; the Node.js default cap is ~1.7 GiB,
41
+ * which causes an OOM crash on first-run VPS installations where swap is the primary resource.
42
+ * Raising the limit lets the build complete on the first attempt.
43
+ *
44
+ * @private internal constant of `ptbk agents-server`
45
+ */
46
+ const AGENTS_SERVER_BUILD_MAX_OLD_SPACE_MIB = 4096;
47
+
37
48
  /**
38
49
  * Environment variable passed to the bundled Next app so webpack can resolve dependencies
39
50
  * installed beside `ptbk` even when the app sources are materialized into a project cache.
@@ -618,7 +629,13 @@ async function runNextBuild(options: {
618
629
  await new Promise<void>((resolveBuild, rejectBuild) => {
619
630
  const buildProcess = spawn(process.execPath, [options.nextCliPath, 'build'], {
620
631
  cwd: options.appPath,
621
- env: options.environment,
632
+ env: {
633
+ ...options.environment,
634
+ NODE_OPTIONS: mergeNodeOptionsWithHeapSize(
635
+ options.environment.NODE_OPTIONS,
636
+ AGENTS_SERVER_BUILD_MAX_OLD_SPACE_MIB,
637
+ ),
638
+ },
622
639
  stdio: ['ignore', 'pipe', 'pipe'],
623
640
  });
624
641
 
@@ -641,6 +658,19 @@ async function runNextBuild(options: {
641
658
  });
642
659
  }
643
660
 
661
+ /**
662
+ * Prepends `--max-old-space-size=<mib>` to `NODE_OPTIONS` unless the caller already set one.
663
+ */
664
+ function mergeNodeOptionsWithHeapSize(existingNodeOptions: string | undefined, maxOldSpaceMib: number): string {
665
+ if (existingNodeOptions !== undefined && /--max-old-space-size[= ]/u.test(existingNodeOptions)) {
666
+ return existingNodeOptions;
667
+ }
668
+
669
+ const heapFlag = `--max-old-space-size=${maxOldSpaceMib}`;
670
+
671
+ return existingNodeOptions ? `${heapFlag} ${existingNodeOptions}` : heapFlag;
672
+ }
673
+
644
674
  /**
645
675
  * Sends one Next build output chunk through the caller handler or to the foreground terminal.
646
676
  */
@@ -4,7 +4,7 @@ import { getSingleLlmExecutionTools } from '../../llm-providers/_multiple/getSin
4
4
  import type { PipelineJson } from '../../pipeline/PipelineJson/PipelineJson';
5
5
  import type { TaskJson } from '../../pipeline/PipelineJson/TaskJson';
6
6
  import type { Parameters } from '../../types/Parameters';
7
- import { Prompt } from '../../types/Prompt';
7
+ import type { Prompt } from '../../types/Prompt';
8
8
  import type { string_markdown } from '../../types/string_markdown';
9
9
  import type { string_parameter_value } from '../../types/string_name';
10
10
  import type { ExecutionTools } from '../ExecutionTools';
@@ -449,7 +449,7 @@ export class OpenAiAgentKitExecutionToolsToolBuilder {
449
449
  );
450
450
  }
451
451
 
452
- return Array.isArray(executionTools.script) ? executionTools.script : [executionTools.script];
452
+ return Array.isArray(executionTools.script) ? executionTools.script : [executionTools.script as ScriptExecutionTools];
453
453
  }
454
454
 
455
455
  /**
@@ -436,7 +436,7 @@ export class OpenAiAssistantExecutionToolsToolRunner {
436
436
 
437
437
  return Array.isArray(this.options.scriptExecutionTools)
438
438
  ? this.options.scriptExecutionTools
439
- : [this.options.scriptExecutionTools];
439
+ : [this.options.scriptExecutionTools as ScriptExecutionTools];
440
440
  }
441
441
 
442
442
  /**
@@ -134,7 +134,7 @@ export class OpenAiVectorStoreKnowledgeSourcePreparer {
134
134
  }
135
135
 
136
136
  return {
137
- file: new File([parsed.buffer], parsed.filename, {
137
+ file: new File([new Uint8Array(parsed.buffer)], parsed.filename, {
138
138
  type: parsed.mimeType,
139
139
  }),
140
140
  sizeBytes: parsed.buffer.length,