@promptbook/components 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 (57) hide show
  1. package/esm/index.es.js +689 -247
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/servers.d.ts +8 -0
  4. package/esm/typings/src/_packages/core.index.d.ts +2 -0
  5. package/esm/typings/src/_packages/types.index.d.ts +16 -2
  6. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +29 -1
  7. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
  8. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.closed.test.d.ts +1 -0
  9. package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +3 -3
  10. package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +5 -1
  11. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  12. package/esm/typings/src/book-components/Chat/CodeBlock/CodeBlock.d.ts +13 -0
  13. package/esm/typings/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
  14. package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +9 -13
  15. package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +3 -3
  16. package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +1 -1
  17. package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
  18. package/esm/typings/src/book-components/icons/AboutIcon.d.ts +1 -1
  19. package/esm/typings/src/book-components/icons/AttachmentIcon.d.ts +1 -1
  20. package/esm/typings/src/book-components/icons/CameraIcon.d.ts +1 -1
  21. package/esm/typings/src/book-components/icons/DownloadIcon.d.ts +1 -1
  22. package/esm/typings/src/book-components/icons/MenuIcon.d.ts +1 -1
  23. package/esm/typings/src/book-components/icons/SaveIcon.d.ts +1 -1
  24. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +22 -12
  25. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +27 -15
  26. package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
  27. package/esm/typings/src/commitments/index.d.ts +2 -1
  28. package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +1 -1
  29. package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
  30. package/esm/typings/src/llm-providers/agent/Agent.d.ts +6 -1
  31. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
  32. package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
  33. package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
  34. package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
  35. package/esm/typings/src/remote-server/ui/ServerApp.d.ts +1 -1
  36. package/esm/typings/src/search-engines/SearchEngine.d.ts +9 -0
  37. package/esm/typings/src/search-engines/SearchResult.d.ts +18 -0
  38. package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +15 -0
  39. package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +15 -0
  40. package/esm/typings/src/types/Message.d.ts +49 -0
  41. package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
  42. package/esm/typings/src/types/typeAliases.d.ts +23 -1
  43. package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
  44. package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
  45. package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
  46. package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
  47. package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
  48. package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
  49. package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
  50. package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
  51. package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +3 -2
  52. package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
  53. package/esm/typings/src/version.d.ts +1 -1
  54. package/package.json +1 -2
  55. package/umd/index.umd.js +697 -256
  56. package/umd/index.umd.js.map +1 -1
  57. package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
package/umd/index.umd.js CHANGED
@@ -1,15 +1,14 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react/jsx-runtime'), require('react'), require('spacetrim'), require('crypto-js'), require('crypto-js/enc-hex'), require('path'), require('crypto'), require('react-dom'), require('@monaco-editor/react'), require('destroyable'), require('highlight.js'), require('katex'), require('showdown'), require('rxjs'), require('waitasecond'), require('crypto-js/sha256'), require('mime-types'), require('papaparse'), require('colors'), require('bottleneck'), require('openai'), require('qrcode')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'react/jsx-runtime', 'react', 'spacetrim', 'crypto-js', 'crypto-js/enc-hex', 'path', 'crypto', 'react-dom', '@monaco-editor/react', 'destroyable', 'highlight.js', 'katex', 'showdown', 'rxjs', 'waitasecond', 'crypto-js/sha256', 'mime-types', 'papaparse', 'colors', 'bottleneck', 'openai', 'qrcode'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-components"] = {}, global.jsxRuntime, global.react, global.spaceTrim$1, global.cryptoJs, global.hexEncoder, global.path, global.crypto, global.reactDom, global.Editor, global.destroyable, global.hljs, global.katex, global.showdown, global.rxjs, global.waitasecond, global.sha256, global.mimeTypes, global.papaparse, global.colors, global.Bottleneck, global.OpenAI, global.QRCode));
5
- })(this, (function (exports, jsxRuntime, react, spaceTrim$1, cryptoJs, hexEncoder, path, crypto, reactDom, Editor, destroyable, hljs, katex, showdown, rxjs, waitasecond, sha256, mimeTypes, papaparse, colors, Bottleneck, OpenAI, QRCode) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react/jsx-runtime'), require('react'), require('spacetrim'), require('crypto-js'), require('crypto-js/enc-hex'), require('path'), require('crypto'), require('react-dom'), require('@monaco-editor/react'), require('destroyable'), require('katex'), require('react-dom/client'), require('showdown'), require('rxjs'), require('waitasecond'), require('crypto-js/sha256'), require('mime-types'), require('papaparse'), require('colors'), require('bottleneck'), require('openai'), require('qrcode')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react/jsx-runtime', 'react', 'spacetrim', 'crypto-js', 'crypto-js/enc-hex', 'path', 'crypto', 'react-dom', '@monaco-editor/react', 'destroyable', 'katex', 'react-dom/client', 'showdown', 'rxjs', 'waitasecond', 'crypto-js/sha256', 'mime-types', 'papaparse', 'colors', 'bottleneck', 'openai', 'qrcode'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-components"] = {}, global.jsxRuntime, global.react, global.spaceTrim$1, global.cryptoJs, global.hexEncoder, global.path, global.crypto, global.reactDom, global.Editor, global.destroyable, global.katex, global.client, global.showdown, global.rxjs, global.waitasecond, global.sha256, global.mimeTypes, global.papaparse, global.colors, global.Bottleneck, global.OpenAI, global.QRCode));
5
+ })(this, (function (exports, jsxRuntime, react, spaceTrim$1, cryptoJs, hexEncoder, path, crypto, reactDom, Editor, destroyable, katex, client, showdown, rxjs, waitasecond, sha256, mimeTypes, papaparse, colors, Bottleneck, OpenAI, QRCode) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
9
9
  var spaceTrim__default = /*#__PURE__*/_interopDefaultLegacy(spaceTrim$1);
10
10
  var hexEncoder__default = /*#__PURE__*/_interopDefaultLegacy(hexEncoder);
11
11
  var Editor__default = /*#__PURE__*/_interopDefaultLegacy(Editor);
12
- var hljs__default = /*#__PURE__*/_interopDefaultLegacy(hljs);
13
12
  var katex__default = /*#__PURE__*/_interopDefaultLegacy(katex);
14
13
  var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
15
14
  var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
@@ -31,7 +30,7 @@
31
30
  * @generated
32
31
  * @see https://github.com/webgptorg/promptbook
33
32
  */
34
- const PROMPTBOOK_ENGINE_VERSION = '0.104.0-1';
33
+ const PROMPTBOOK_ENGINE_VERSION = '0.104.0-11';
35
34
  /**
36
35
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
37
36
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
@@ -80,9 +79,9 @@
80
79
  }
81
80
  }
82
81
 
83
- var css_248z$9 = ".AvatarChip-module_AvatarChip__4sA0u{align-items:center;background:#e0e7ef;border:1px solid #b3c2d1;border-radius:16px;color:#2a3b4d;cursor:pointer;display:inline-flex;font-size:.95em;font-weight:500;margin:2px;padding:4px 12px}.AvatarChip-module_Avatar__mN2sc{border-radius:50%;height:24px;margin-right:8px;object-fit:cover;width:24px}.AvatarChip-module_TemplateLabel__-7vVI{background:#f0f4f8;border-radius:12px;color:#3a4752;font-size:.8em;margin-left:8px;margin-right:0;padding:2px 6px;text-transform:uppercase}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkF2YXRhckNoaXAubW9kdWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxxQ0FFSSxrQkFBbUIsQ0FHbkIsa0JBQW1CLENBS25CLHdCQUF5QixDQU56QixrQkFBbUIsQ0FFbkIsYUFBYyxDQU1kLGNBQWUsQ0FYZixtQkFBb0IsQ0FPcEIsZUFBaUIsQ0FEakIsZUFBZ0IsQ0FFaEIsVUFBVyxDQU5YLGdCQVVKLENBRUEsaUNBR0ksaUJBQWtCLENBRGxCLFdBQVksQ0FHWixnQkFBaUIsQ0FEakIsZ0JBQWlCLENBSGpCLFVBS0osQ0FFQSx3Q0FDSSxrQkFBbUIsQ0FJbkIsa0JBQW1CLENBSG5CLGFBQWMsQ0FDZCxjQUFnQixDQUdoQixlQUFnQixDQUNoQixjQUFlLENBSGYsZUFBZ0IsQ0FJaEIsd0JBQ0oiLCJmaWxlIjoiQXZhdGFyQ2hpcC5tb2R1bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLkF2YXRhckNoaXAge1xuICAgIGRpc3BsYXk6IGlubGluZS1mbGV4O1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgcGFkZGluZzogNHB4IDEycHg7XG4gICAgYm9yZGVyLXJhZGl1czogMTZweDtcbiAgICBiYWNrZ3JvdW5kOiAjZTBlN2VmO1xuICAgIGNvbG9yOiAjMmEzYjRkO1xuICAgIGZvbnQtd2VpZ2h0OiA1MDA7XG4gICAgZm9udC1zaXplOiAwLjk1ZW07XG4gICAgbWFyZ2luOiAycHg7XG4gICAgYm9yZGVyOiAxcHggc29saWQgI2IzYzJkMTtcblxuICAgIGN1cnNvcjogcG9pbnRlcjtcbn1cblxuLkF2YXRhciB7XG4gICAgd2lkdGg6IDI0cHg7XG4gICAgaGVpZ2h0OiAyNHB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBvYmplY3QtZml0OiBjb3ZlcjtcbiAgICBtYXJnaW4tcmlnaHQ6IDhweDtcbn1cblxuLlRlbXBsYXRlTGFiZWwge1xuICAgIGJhY2tncm91bmQ6ICNmMGY0Zjg7XG4gICAgY29sb3I6ICMzYTQ3NTI7XG4gICAgZm9udC1zaXplOiAwLjhlbTtcbiAgICBwYWRkaW5nOiAycHggNnB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDEycHg7XG4gICAgbWFyZ2luLWxlZnQ6IDhweDtcbiAgICBtYXJnaW4tcmlnaHQ6IDA7XG4gICAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtcbn1cbiJdfQ== */";
84
- var styles$8 = {"AvatarChip":"AvatarChip-module_AvatarChip__4sA0u","Avatar":"AvatarChip-module_Avatar__mN2sc","TemplateLabel":"AvatarChip-module_TemplateLabel__-7vVI"};
85
- styleInject(css_248z$9);
82
+ var css_248z$a = ".AvatarChip-module_AvatarChip__4sA0u{align-items:center;background:#e0e7ef;border:1px solid #b3c2d1;border-radius:16px;color:#2a3b4d;cursor:pointer;display:inline-flex;font-size:.95em;font-weight:500;margin:2px;padding:4px 12px}.AvatarChip-module_Avatar__mN2sc{border-radius:50%;height:24px;margin-right:8px;object-fit:cover;width:24px}.AvatarChip-module_TemplateLabel__-7vVI{background:#f0f4f8;border-radius:12px;color:#3a4752;font-size:.8em;margin-left:8px;margin-right:0;padding:2px 6px;text-transform:uppercase}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkF2YXRhckNoaXAubW9kdWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxxQ0FFSSxrQkFBbUIsQ0FHbkIsa0JBQW1CLENBS25CLHdCQUF5QixDQU56QixrQkFBbUIsQ0FFbkIsYUFBYyxDQU1kLGNBQWUsQ0FYZixtQkFBb0IsQ0FPcEIsZUFBaUIsQ0FEakIsZUFBZ0IsQ0FFaEIsVUFBVyxDQU5YLGdCQVVKLENBRUEsaUNBR0ksaUJBQWtCLENBRGxCLFdBQVksQ0FHWixnQkFBaUIsQ0FEakIsZ0JBQWlCLENBSGpCLFVBS0osQ0FFQSx3Q0FDSSxrQkFBbUIsQ0FJbkIsa0JBQW1CLENBSG5CLGFBQWMsQ0FDZCxjQUFnQixDQUdoQixlQUFnQixDQUNoQixjQUFlLENBSGYsZUFBZ0IsQ0FJaEIsd0JBQ0oiLCJmaWxlIjoiQXZhdGFyQ2hpcC5tb2R1bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLkF2YXRhckNoaXAge1xuICAgIGRpc3BsYXk6IGlubGluZS1mbGV4O1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgcGFkZGluZzogNHB4IDEycHg7XG4gICAgYm9yZGVyLXJhZGl1czogMTZweDtcbiAgICBiYWNrZ3JvdW5kOiAjZTBlN2VmO1xuICAgIGNvbG9yOiAjMmEzYjRkO1xuICAgIGZvbnQtd2VpZ2h0OiA1MDA7XG4gICAgZm9udC1zaXplOiAwLjk1ZW07XG4gICAgbWFyZ2luOiAycHg7XG4gICAgYm9yZGVyOiAxcHggc29saWQgI2IzYzJkMTtcblxuICAgIGN1cnNvcjogcG9pbnRlcjtcbn1cblxuLkF2YXRhciB7XG4gICAgd2lkdGg6IDI0cHg7XG4gICAgaGVpZ2h0OiAyNHB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICBvYmplY3QtZml0OiBjb3ZlcjtcbiAgICBtYXJnaW4tcmlnaHQ6IDhweDtcbn1cblxuLlRlbXBsYXRlTGFiZWwge1xuICAgIGJhY2tncm91bmQ6ICNmMGY0Zjg7XG4gICAgY29sb3I6ICMzYTQ3NTI7XG4gICAgZm9udC1zaXplOiAwLjhlbTtcbiAgICBwYWRkaW5nOiAycHggNnB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDEycHg7XG4gICAgbWFyZ2luLWxlZnQ6IDhweDtcbiAgICBtYXJnaW4tcmlnaHQ6IDA7XG4gICAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtcbn1cbiJdfQ== */";
83
+ var styles$9 = {"AvatarChip":"AvatarChip-module_AvatarChip__4sA0u","Avatar":"AvatarChip-module_Avatar__mN2sc","TemplateLabel":"AvatarChip-module_TemplateLabel__-7vVI"};
84
+ styleInject(css_248z$a);
86
85
 
87
86
  /**
88
87
  * Shows a chip with avatar's avatar and name
@@ -92,7 +91,7 @@
92
91
  function AvatarChip(props) {
93
92
  const { avatarBasicInformation, className, onSelect, isSelected, isTemplate } = props;
94
93
  const { agentName, meta } = avatarBasicInformation;
95
- return (jsxRuntime.jsxs("div", { className: classNames(styles$8.AvatarChip, className, isSelected ? styles$8.Selected : undefined), onClick: () => onSelect === null || onSelect === void 0 ? void 0 : onSelect(avatarBasicInformation), style: { cursor: onSelect ? 'pointer' : undefined }, children: [jsxRuntime.jsx("img", { src: meta.image, alt: agentName || '', className: styles$8.Avatar }), meta.fullname || agentName, isTemplate && jsxRuntime.jsx("span", { className: styles$8.TemplateLabel, children: "Template" })] }));
94
+ return (jsxRuntime.jsxs("div", { className: classNames(styles$9.AvatarChip, className, isSelected ? styles$9.Selected : undefined), onClick: () => onSelect === null || onSelect === void 0 ? void 0 : onSelect(avatarBasicInformation), style: { cursor: onSelect ? 'pointer' : undefined }, children: [jsxRuntime.jsx("img", { src: meta.image, alt: agentName || '', className: styles$9.Avatar }), meta.fullname || agentName, isTemplate && jsxRuntime.jsx("span", { className: styles$9.TemplateLabel, children: "Template" })] }));
96
95
  }
97
96
 
98
97
  /**
@@ -149,48 +148,12 @@
149
148
  * TODO: [๐ŸŒบ] Use some intermediate util splitWords
150
149
  */
151
150
 
152
- /**
153
- * Generates a gravatar URL based on agent name for fallback avatar
154
- *
155
- * @param agentName The agent name to generate avatar for
156
- * @returns Gravatar URL
157
- *
158
- * @private - [๐Ÿคน] The fact that profile image is Gravatar is just implementation detail which should be hidden for consumer
159
- */
160
- function generateGravatarUrl(agentName) {
161
- // Use a default name if none provided
162
- const safeName = agentName || 'Anonymous Agent';
163
- // Create a simple hash from the name for consistent avatar
164
- let hash = 0;
165
- for (let i = 0; i < safeName.length; i++) {
166
- const char = safeName.charCodeAt(i);
167
- hash = (hash << 5) - hash + char;
168
- hash = hash & hash; // Convert to 32bit integer
169
- }
170
- const avatarId = Math.abs(hash).toString();
171
- return `https://www.gravatar.com/avatar/${avatarId}?default=robohash&size=200&rating=x`;
172
- }
173
-
174
- /**
175
- * Generates an image for the agent to use as profile image
176
- *
177
- * @param agentName The agent name to generate avatar for
178
- * @returns The placeholder profile image URL for the agent
179
- *
180
- * @public exported from `@promptbook/core`
181
- */
182
- function generatePlaceholderAgentProfileImageUrl(agentName) {
183
- // Note: [๐Ÿคน] The fact that profile image is Gravatar is just implementation detail which should be hidden for consumer
184
- return generateGravatarUrl(agentName);
185
- }
186
- /**
187
- * TODO: [๐Ÿคน] Figure out best placeholder image generator https://i.pravatar.cc/1000?u=568
188
- */
189
-
190
151
  /**
191
152
  * Core Promptbook server configuration.
192
153
  *
193
154
  * This server is also used for auto-federation in the Agents Server.
155
+ *
156
+ * @public exported from `@promptbook/core`
194
157
  */
195
158
  const CORE_SERVER = {
196
159
  title: 'Promptbook Core',
@@ -3043,13 +3006,14 @@
3043
3006
  *
3044
3007
  * @public exported from `@promptbook/utils`
3045
3008
  */
3046
- const $isRunningInBrowser = new Function(`
3047
- try {
3048
- return this === window;
3049
- } catch (e) {
3050
- return false;
3009
+ function $isRunningInBrowser() {
3010
+ try {
3011
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined';
3012
+ }
3013
+ catch (e) {
3014
+ return false;
3015
+ }
3051
3016
  }
3052
- `);
3053
3017
  /**
3054
3018
  * TODO: [๐ŸŽบ]
3055
3019
  */
@@ -3061,13 +3025,15 @@
3061
3025
  *
3062
3026
  * @public exported from `@promptbook/utils`
3063
3027
  */
3064
- const $isRunningInJest = new Function(`
3065
- try {
3066
- return process.env.JEST_WORKER_ID !== undefined;
3067
- } catch (e) {
3068
- return false;
3028
+ function $isRunningInJest() {
3029
+ var _a;
3030
+ try {
3031
+ return typeof process !== 'undefined' && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.JEST_WORKER_ID) !== undefined;
3032
+ }
3033
+ catch (e) {
3034
+ return false;
3035
+ }
3069
3036
  }
3070
- `);
3071
3037
  /**
3072
3038
  * TODO: [๐ŸŽบ]
3073
3039
  */
@@ -3079,13 +3045,14 @@
3079
3045
  *
3080
3046
  * @public exported from `@promptbook/utils`
3081
3047
  */
3082
- const $isRunningInNode = new Function(`
3083
- try {
3084
- return this === global;
3085
- } catch (e) {
3086
- return false;
3048
+ function $isRunningInNode() {
3049
+ try {
3050
+ return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
3051
+ }
3052
+ catch (e) {
3053
+ return false;
3054
+ }
3087
3055
  }
3088
- `);
3089
3056
  /**
3090
3057
  * TODO: [๐ŸŽบ]
3091
3058
  */
@@ -3097,17 +3064,17 @@
3097
3064
  *
3098
3065
  * @public exported from `@promptbook/utils`
3099
3066
  */
3100
- const $isRunningInWebWorker = new Function(`
3101
- try {
3102
- if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
3103
- return true;
3104
- } else {
3067
+ function $isRunningInWebWorker() {
3068
+ try {
3069
+ // Note: Check for importScripts which is specific to workers
3070
+ // and not available in the main browser thread
3071
+ return (typeof self !== 'undefined' &&
3072
+ typeof self.importScripts === 'function');
3073
+ }
3074
+ catch (e) {
3105
3075
  return false;
3106
3076
  }
3107
- } catch (e) {
3108
- return false;
3109
3077
  }
3110
- `);
3111
3078
  /**
3112
3079
  * TODO: [๐ŸŽบ]
3113
3080
  */
@@ -4123,6 +4090,114 @@
4123
4090
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
4124
4091
  */
4125
4092
 
4093
+ /**
4094
+ * DICTIONARY commitment definition
4095
+ *
4096
+ * The DICTIONARY commitment defines specific terms and their meanings that the agent should use correctly
4097
+ * in its reasoning and responses. This ensures consistent terminology usage.
4098
+ *
4099
+ * Key features:
4100
+ * - Multiple DICTIONARY commitments are automatically merged into one
4101
+ * - Content is placed in a dedicated section of the system message
4102
+ * - Terms and definitions are stored in metadata.DICTIONARY for debugging
4103
+ * - Agent should use the defined terms correctly in responses
4104
+ *
4105
+ * Example usage in agent source:
4106
+ *
4107
+ * ```book
4108
+ * Legal Assistant
4109
+ *
4110
+ * PERSONA You are a knowledgeable legal assistant
4111
+ * DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
4112
+ * DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
4113
+ * DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
4114
+ * ```
4115
+ *
4116
+ * @private [๐Ÿช”] Maybe export the commitments through some package
4117
+ */
4118
+ class DictionaryCommitmentDefinition extends BaseCommitmentDefinition {
4119
+ constructor() {
4120
+ super('DICTIONARY');
4121
+ }
4122
+ /**
4123
+ * Short one-line description of DICTIONARY.
4124
+ */
4125
+ get description() {
4126
+ return 'Define terms and their meanings for consistent terminology usage.';
4127
+ }
4128
+ /**
4129
+ * Icon for this commitment.
4130
+ */
4131
+ get icon() {
4132
+ return '๐Ÿ“š';
4133
+ }
4134
+ /**
4135
+ * Markdown documentation for DICTIONARY commitment.
4136
+ */
4137
+ get documentation() {
4138
+ return spaceTrim$1.spaceTrim(`
4139
+ # DICTIONARY
4140
+
4141
+ Defines specific terms and their meanings that the agent should use correctly in reasoning and responses.
4142
+
4143
+ ## Key aspects
4144
+
4145
+ - Multiple \`DICTIONARY\` commitments are merged together.
4146
+ - Terms are defined in the format: "Term is definition"
4147
+ - The agent should use these terms consistently in responses.
4148
+ - Definitions help ensure accurate and consistent terminology.
4149
+
4150
+ ## Examples
4151
+
4152
+ \`\`\`book
4153
+ Legal Assistant
4154
+
4155
+ PERSONA You are a knowledgeable legal assistant specializing in criminal law
4156
+ DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
4157
+ DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
4158
+ DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
4159
+ \`\`\`
4160
+
4161
+ \`\`\`book
4162
+ Medical Assistant
4163
+
4164
+ PERSONA You are a helpful medical assistant
4165
+ DICTIONARY Hypertension is persistently high blood pressure
4166
+ DICTIONARY Diabetes is a chronic condition that affects how the body processes blood sugar
4167
+ DICTIONARY Vaccine is a biological preparation that provides active immunity to a particular disease
4168
+ \`\`\`
4169
+ `);
4170
+ }
4171
+ applyToAgentModelRequirements(requirements, content) {
4172
+ var _a;
4173
+ const trimmedContent = content.trim();
4174
+ if (!trimmedContent) {
4175
+ return requirements;
4176
+ }
4177
+ // Get existing dictionary entries from metadata
4178
+ const existingDictionary = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.DICTIONARY) || '';
4179
+ // Merge the new dictionary entry with existing entries
4180
+ const mergedDictionary = existingDictionary
4181
+ ? `${existingDictionary}\n${trimmedContent}`
4182
+ : trimmedContent;
4183
+ // Store the merged dictionary in metadata for debugging and inspection
4184
+ const updatedMetadata = {
4185
+ ...requirements.metadata,
4186
+ DICTIONARY: mergedDictionary,
4187
+ };
4188
+ // Create the dictionary section for the system message
4189
+ // Format: "# DICTIONARY\nTerm: definition\nTerm: definition..."
4190
+ const dictionarySection = `# DICTIONARY\n${mergedDictionary}`;
4191
+ return {
4192
+ ...this.appendToSystemMessage(requirements, dictionarySection),
4193
+ metadata: updatedMetadata,
4194
+ };
4195
+ }
4196
+ }
4197
+ /**
4198
+ * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
4199
+ */
4200
+
4126
4201
  /**
4127
4202
  * FORMAT commitment definition
4128
4203
  *
@@ -6943,6 +7018,7 @@
6943
7018
  new DeleteCommitmentDefinition('CANCEL'),
6944
7019
  new DeleteCommitmentDefinition('DISCARD'),
6945
7020
  new DeleteCommitmentDefinition('REMOVE'),
7021
+ new DictionaryCommitmentDefinition(),
6946
7022
  new OpenCommitmentDefinition(),
6947
7023
  new ClosedCommitmentDefinition(),
6948
7024
  new UseBrowserCommitmentDefinition(),
@@ -7002,17 +7078,64 @@
7002
7078
  };
7003
7079
  }
7004
7080
  const lines = agentSource.split('\n');
7005
- const agentName = (((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.trim()) || null);
7081
+ let agentName = null;
7082
+ let agentNameLineIndex = -1;
7083
+ // Find the agent name: first non-empty line that is not a commitment and not a horizontal line
7084
+ for (let i = 0; i < lines.length; i++) {
7085
+ const line = lines[i];
7086
+ if (line === undefined) {
7087
+ continue;
7088
+ }
7089
+ const trimmed = line.trim();
7090
+ if (!trimmed) {
7091
+ continue;
7092
+ }
7093
+ const isHorizontal = HORIZONTAL_LINE_PATTERN.test(line);
7094
+ if (isHorizontal) {
7095
+ continue;
7096
+ }
7097
+ let isCommitment = false;
7098
+ for (const definition of COMMITMENT_REGISTRY) {
7099
+ const typeRegex = definition.createTypeRegex();
7100
+ const match = typeRegex.exec(trimmed);
7101
+ if (match && ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.type)) {
7102
+ isCommitment = true;
7103
+ break;
7104
+ }
7105
+ }
7106
+ if (!isCommitment) {
7107
+ agentName = trimmed;
7108
+ agentNameLineIndex = i;
7109
+ break;
7110
+ }
7111
+ }
7006
7112
  const commitments = [];
7007
7113
  const nonCommitmentLines = [];
7008
- // Always add the first line (agent name) to non-commitment lines
7009
- if (lines[0] !== undefined) {
7010
- nonCommitmentLines.push(lines[0]);
7114
+ // Add lines before agentName that are horizontal lines (they are non-commitment)
7115
+ for (let i = 0; i < agentNameLineIndex; i++) {
7116
+ const line = lines[i];
7117
+ if (line === undefined) {
7118
+ continue;
7119
+ }
7120
+ const trimmed = line.trim();
7121
+ if (!trimmed) {
7122
+ continue;
7123
+ }
7124
+ const isHorizontal = HORIZONTAL_LINE_PATTERN.test(line);
7125
+ if (isHorizontal) {
7126
+ nonCommitmentLines.push(line);
7127
+ }
7128
+ // Note: Commitments before agentName are not added to nonCommitmentLines
7129
+ }
7130
+ // Add the agent name line to non-commitment lines
7131
+ if (agentNameLineIndex >= 0) {
7132
+ nonCommitmentLines.push(lines[agentNameLineIndex]);
7011
7133
  }
7012
7134
  // Parse commitments with multiline support
7013
7135
  let currentCommitment = null;
7014
- // Process lines starting from the second line (skip agent name)
7015
- for (let i = 1; i < lines.length; i++) {
7136
+ // Process lines starting from after the agent name line
7137
+ const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
7138
+ for (let i = startIndex; i < lines.length; i++) {
7016
7139
  const line = lines[i];
7017
7140
  if (line === undefined) {
7018
7141
  continue;
@@ -7189,7 +7312,57 @@
7189
7312
  }
7190
7313
  const meta = {};
7191
7314
  const links = [];
7315
+ const capabilities = [];
7192
7316
  for (const commitment of parseResult.commitments) {
7317
+ if (commitment.type === 'USE BROWSER') {
7318
+ capabilities.push({
7319
+ type: 'browser',
7320
+ label: 'Browser',
7321
+ iconName: 'Globe',
7322
+ });
7323
+ continue;
7324
+ }
7325
+ if (commitment.type === 'USE SEARCH ENGINE') {
7326
+ capabilities.push({
7327
+ type: 'search-engine',
7328
+ label: 'Search Internet',
7329
+ iconName: 'Search',
7330
+ });
7331
+ continue;
7332
+ }
7333
+ if (commitment.type === 'KNOWLEDGE') {
7334
+ const content = spaceTrim__default["default"](commitment.content).split('\n')[0] || '';
7335
+ let label = content;
7336
+ let iconName = 'Book';
7337
+ if (content.startsWith('http://') || content.startsWith('https://')) {
7338
+ try {
7339
+ const url = new URL(content);
7340
+ if (url.pathname.endsWith('.pdf')) {
7341
+ label = url.pathname.split('/').pop() || 'Document.pdf';
7342
+ iconName = 'FileText';
7343
+ }
7344
+ else {
7345
+ label = url.hostname.replace(/^www\./, '');
7346
+ }
7347
+ }
7348
+ catch (e) {
7349
+ // Invalid URL, treat as text
7350
+ }
7351
+ }
7352
+ else {
7353
+ // Text content - take first few words
7354
+ const words = content.split(/\s+/);
7355
+ if (words.length > 4) {
7356
+ label = words.slice(0, 4).join(' ') + '...';
7357
+ }
7358
+ }
7359
+ capabilities.push({
7360
+ type: 'knowledge',
7361
+ label,
7362
+ iconName,
7363
+ });
7364
+ continue;
7365
+ }
7193
7366
  if (commitment.type === 'META LINK') {
7194
7367
  const linkValue = spaceTrim__default["default"](commitment.content);
7195
7368
  links.push(linkValue);
@@ -7219,10 +7392,6 @@
7219
7392
  const metaType = normalizeTo_camelCase(metaTypeRaw);
7220
7393
  meta[metaType] = spaceTrim__default["default"](commitment.content.substring(metaTypeRaw.length));
7221
7394
  }
7222
- // Generate gravatar fallback if no meta image specified
7223
- if (!meta.image) {
7224
- meta.image = generatePlaceholderAgentProfileImageUrl(parseResult.agentName || '!!');
7225
- }
7226
7395
  // Generate fullname fallback if no meta fullname specified
7227
7396
  if (!meta.fullname) {
7228
7397
  meta.fullname = parseResult.agentName || createDefaultAgentName(agentSource);
@@ -7234,11 +7403,13 @@
7234
7403
  return {
7235
7404
  agentName: normalizeAgentName(parseResult.agentName || createDefaultAgentName(agentSource)),
7236
7405
  agentHash,
7406
+ permanentId: meta.id,
7237
7407
  personaDescription,
7238
7408
  initialMessage,
7239
7409
  meta,
7240
7410
  links,
7241
7411
  parameters,
7412
+ capabilities,
7242
7413
  };
7243
7414
  }
7244
7415
  /**
@@ -7273,9 +7444,9 @@
7273
7444
  return jsxRuntime.jsx(AvatarChip, { avatarBasicInformation: avatarBasicInformation, ...props });
7274
7445
  }
7275
7446
 
7276
- var css_248z$8 = ".Modal-module_scrim__jKO-A{align-items:center;background-color:rgba(0,0,0,.5);display:flex;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:9000000}.Modal-module_Modal__k49dY{background:#fff;border-radius:8px;max-height:90%;max-width:90%;min-height:30vh;min-width:50vw;overflow:auto;padding:20px;position:relative}.Modal-module_closeButton__dzf6l{background:transparent;border:none;cursor:pointer;font-size:24px;position:absolute;right:10px;top:10px}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIk1vZGFsLm1vZHVsZS5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsMkJBU0ksa0JBQW1CLENBSG5CLCtCQUFvQyxDQUNwQyxZQUFhLENBRmIsV0FBWSxDQUdaLHNCQUF1QixDQUx2QixNQUFPLENBRlAsY0FBZSxDQUNmLEtBQU0sQ0FFTixVQUFXLENBTVgsZUFDSixDQUVBLDJCQUNJLGVBQWlCLENBRWpCLGlCQUFrQixDQUdsQixjQUFlLENBRGYsYUFBYyxDQUdkLGVBQWdCLENBRGhCLGNBQWUsQ0FFZixhQUFjLENBUGQsWUFBYSxDQUViLGlCQU1KLENBRUEsaUNBSUksc0JBQXVCLENBQ3ZCLFdBQVksQ0FFWixjQUFlLENBRGYsY0FBZSxDQUxmLGlCQUFrQixDQUVsQixVQUFXLENBRFgsUUFNSiIsImZpbGUiOiJNb2RhbC5tb2R1bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLnNjcmltIHtcbiAgICBwb3NpdGlvbjogZml4ZWQ7XG4gICAgdG9wOiAwO1xuICAgIGxlZnQ6IDA7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgei1pbmRleDogOTAwMDAwMDtcbn1cblxuLk1vZGFsIHtcbiAgICBiYWNrZ3JvdW5kOiB3aGl0ZTtcbiAgICBwYWRkaW5nOiAyMHB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDhweDtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgbWF4LXdpZHRoOiA5MCU7XG4gICAgbWF4LWhlaWdodDogOTAlO1xuICAgIG1pbi13aWR0aDogNTB2dztcbiAgICBtaW4taGVpZ2h0OiAzMHZoO1xuICAgIG92ZXJmbG93OiBhdXRvO1xufVxuXG4uY2xvc2VCdXR0b24ge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDEwcHg7XG4gICAgcmlnaHQ6IDEwcHg7XG4gICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG4gICAgYm9yZGVyOiBub25lO1xuICAgIGZvbnQtc2l6ZTogMjRweDtcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG59XG4iXX0= */";
7277
- var styles$7 = {"scrim":"Modal-module_scrim__jKO-A","Modal":"Modal-module_Modal__k49dY","closeButton":"Modal-module_closeButton__dzf6l"};
7278
- styleInject(css_248z$8);
7447
+ var css_248z$9 = ".Modal-module_scrim__jKO-A{align-items:center;background-color:rgba(0,0,0,.5);display:flex;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:9000000}.Modal-module_Modal__k49dY{background:#fff;border-radius:8px;max-height:90%;max-width:90%;min-height:30vh;min-width:50vw;overflow:auto;padding:20px;position:relative}.Modal-module_closeButton__dzf6l{background:transparent;border:none;cursor:pointer;font-size:24px;position:absolute;right:10px;top:10px}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIk1vZGFsLm1vZHVsZS5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsMkJBU0ksa0JBQW1CLENBSG5CLCtCQUFvQyxDQUNwQyxZQUFhLENBRmIsV0FBWSxDQUdaLHNCQUF1QixDQUx2QixNQUFPLENBRlAsY0FBZSxDQUNmLEtBQU0sQ0FFTixVQUFXLENBTVgsZUFDSixDQUVBLDJCQUNJLGVBQWlCLENBRWpCLGlCQUFrQixDQUdsQixjQUFlLENBRGYsYUFBYyxDQUdkLGVBQWdCLENBRGhCLGNBQWUsQ0FFZixhQUFjLENBUGQsWUFBYSxDQUViLGlCQU1KLENBRUEsaUNBSUksc0JBQXVCLENBQ3ZCLFdBQVksQ0FFWixjQUFlLENBRGYsY0FBZSxDQUxmLGlCQUFrQixDQUVsQixVQUFXLENBRFgsUUFNSiIsImZpbGUiOiJNb2RhbC5tb2R1bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLnNjcmltIHtcbiAgICBwb3NpdGlvbjogZml4ZWQ7XG4gICAgdG9wOiAwO1xuICAgIGxlZnQ6IDA7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgei1pbmRleDogOTAwMDAwMDtcbn1cblxuLk1vZGFsIHtcbiAgICBiYWNrZ3JvdW5kOiB3aGl0ZTtcbiAgICBwYWRkaW5nOiAyMHB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDhweDtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgbWF4LXdpZHRoOiA5MCU7XG4gICAgbWF4LWhlaWdodDogOTAlO1xuICAgIG1pbi13aWR0aDogNTB2dztcbiAgICBtaW4taGVpZ2h0OiAzMHZoO1xuICAgIG92ZXJmbG93OiBhdXRvO1xufVxuXG4uY2xvc2VCdXR0b24ge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDEwcHg7XG4gICAgcmlnaHQ6IDEwcHg7XG4gICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG4gICAgYm9yZGVyOiBub25lO1xuICAgIGZvbnQtc2l6ZTogMjRweDtcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG59XG4iXX0= */";
7448
+ var styles$8 = {"scrim":"Modal-module_scrim__jKO-A","Modal":"Modal-module_Modal__k49dY","closeButton":"Modal-module_closeButton__dzf6l"};
7449
+ styleInject(css_248z$9);
7279
7450
 
7280
7451
  /**
7281
7452
  *
@@ -7293,7 +7464,7 @@
7293
7464
  window.removeEventListener('keydown', handleKeyDown);
7294
7465
  };
7295
7466
  }, [onClose]);
7296
- return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$7.scrim, onClick: onClose, children: jsxRuntime.jsxs("div", { className: classNames(styles$7.Modal, className), onClick: (e) => e.stopPropagation(), children: [jsxRuntime.jsx("button", { className: styles$7.closeButton, onClick: onClose, children: "\u00D7" }), children] }) }), document.body);
7467
+ return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$8.scrim, onClick: onClose, children: jsxRuntime.jsxs("div", { className: classNames(styles$8.Modal, className), onClick: (e) => e.stopPropagation(), children: [jsxRuntime.jsx("button", { className: styles$8.closeButton, onClick: onClose, children: "\u00D7" }), children] }) }), document.body);
7297
7468
  }
7298
7469
 
7299
7470
  /**
@@ -7378,9 +7549,9 @@
7378
7549
  // <- [๐Ÿฑโ€๐Ÿš€] Buttons into genesis book
7379
7550
  // <- TODO: [๐Ÿฑโ€๐Ÿš€] generateBookBoilerplate and deprecate `DEFAULT_BOOK`
7380
7551
 
7381
- var css_248z$7 = ".BookEditor-module_BookEditor__s-0PU{width:100%}.BookEditor-module_bookEditorContainer__wLMwM{box-sizing:border-box;height:100%;padding:10px 25px 0;position:relative;width:100%}.BookEditor-module_bookEditorContainer__wLMwM.BookEditor-module_isVerbose__VQ6iL{background-color:rgba(0,0,0,.05);outline:1px dotted rgba(0,0,0,.5)}.BookEditor-module_isVerbose__VQ6iL{outline:2px dotted #ff7526}.BookEditor-module_bookEditorWrapper__twppD{background-color:#fff;border:1px solid rgba(209,213,219,.8);border-radius:1rem;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);overflow:hidden;padding-top:10px;transition:box-shadow .2s ease-in-out}.BookEditor-module_isVerbose__VQ6iL .BookEditor-module_bookEditorWrapper__twppD{overflow:visible}.BookEditor-module_bookEditorWrapper__twppD:hover{box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.BookEditor-module_bookEditorWrapper__twppD.BookEditor-module_isBorderRadiusDisabled__h1I3v{border-radius:0}.BookEditor-module_dropOverlay__xWWoX{align-items:center;background-color:rgba(0,0,0,.5);bottom:0;color:#fff;display:flex;font-size:1.5rem;justify-content:center;left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:100}.BookEditor-module_bookEditorActionbar__KW6dc{position:absolute;right:55px;top:10px;z-index:100}.BookEditor-module_fullscreen__rktsl{border:none;border-radius:0;bottom:0;box-shadow:none;height:100%;left:0;padding-top:50px;position:fixed;right:0;top:0;width:100%;z-index:9999}.BookEditor-module_button__hS390{align-items:center;background-color:#fff;border:1px solid #d1d5db;border-radius:.375rem;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);color:#374151;cursor:pointer;display:inline-flex;gap:.5rem;padding:.5rem 1rem;transition:all .2s ease-in-out}.BookEditor-module_button__hS390:hover{background-color:#f9fafb;border-color:#b7bcce;box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06)}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkJvb2tFZGl0b3IubW9kdWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxxQ0FFSSxVQUNKLENBRUEsOENBS0kscUJBQXNCLENBSHRCLFdBQVksQ0FFWixtQkFBb0IsQ0FEcEIsaUJBQWtCLENBRmxCLFVBS0osQ0FFQSxpRkFFSSxnQ0FBcUMsQ0FDckMsaUNBRUosQ0FFQSxvQ0FDSSwwQkFDSixDQUVBLDRDQUtJLHFCQUF1QixDQUR2QixxQ0FBMEMsQ0FGMUMsa0JBQW1CLENBSW5CLHNDQUEyQyxDQUwzQyxlQUFnQixDQUVoQixnQkFBaUIsQ0FJakIscUNBQ0osQ0FDQSxnRkFFSSxnQkFFSixDQUVBLGtEQUNJLHVFQUNKLENBVUEsNEZBQ0ksZUFDSixDQUVBLHNDQVNJLGtCQUFtQixDQUhuQiwrQkFBb0MsQ0FEcEMsUUFBUyxDQUVULFVBQVksQ0FDWixZQUFhLENBR2IsZ0JBQWlCLENBRGpCLHNCQUF1QixDQVB2QixNQUFPLENBVVAsbUJBQW9CLENBWnBCLGlCQUFrQixDQUdsQixPQUFRLENBRlIsS0FBTSxDQVVOLFdBRUosQ0FRQSw4Q0FDSSxpQkFBa0IsQ0FFbEIsVUFBVyxDQURYLFFBQVMsQ0FFVCxXQUNKLENBRUEscUNBV0ksV0FBWSxDQUZaLGVBQWdCLENBSmhCLFFBQVMsQ0FPVCxlQUFnQixDQUxoQixXQUFZLENBSlosTUFBTyxDQU9QLGdCQUFpQixDQVRqQixjQUFlLENBR2YsT0FBUSxDQUZSLEtBQU0sQ0FJTixVQUFXLENBRVgsWUFLSixDQUVBLGlDQU9JLGtCQUFtQixDQU5uQixxQkFBc0IsQ0FDdEIsd0JBQXlCLENBQ3pCLHFCQUF1QixDQU92QixzQ0FBMkMsQ0FEM0MsYUFBYyxDQUpkLGNBQWUsQ0FDZixtQkFBb0IsQ0FFcEIsU0FBVyxDQUpYLGtCQUFvQixDQU9wQiw4QkFDSixDQUVBLHVDQUNJLHdCQUF5QixDQUN6QixvQkFBcUIsQ0FDckIsaUVBQ0oiLCJmaWxlIjoiQm9va0VkaXRvci5tb2R1bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLkJvb2tFZGl0b3Ige1xuICAgIC8qIGhlaWdodDogNDUwcHg7ICovXG4gICAgd2lkdGg6IDEwMCU7XG59XG5cbi5ib29rRWRpdG9yQ29udGFpbmVyIHtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIHBhZGRpbmc6IDEwcHggMjVweCAwO1xuICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG59XG5cbi5ib29rRWRpdG9yQ29udGFpbmVyLmlzVmVyYm9zZSB7XG4gICAgLyoqL1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC4wNSk7XG4gICAgb3V0bGluZTogMXB4IGRvdHRlZCByZ2JhKDAsIDAsIDAsIDAuNSk7XG4gICAgLyoqL1xufVxuXG4uaXNWZXJib3NlIHtcbiAgICBvdXRsaW5lOiAycHggZG90dGVkIHJnYigyNTUgMTE3IDM4KTtcbn1cblxuLmJvb2tFZGl0b3JXcmFwcGVyIHtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIGJvcmRlci1yYWRpdXM6IDFyZW07XG4gICAgcGFkZGluZy10b3A6IDEwcHg7XG4gICAgYm9yZGVyOiAxcHggc29saWQgcmdiYSgyMDksIDIxMywgMjE5LCAwLjgpO1xuICAgIGJhY2tncm91bmQtY29sb3I6IHdoaXRlO1xuICAgIGJveC1zaGFkb3c6IDAgMXB4IDJweCAwIHJnYmEoMCwgMCwgMCwgMC4wNSk7XG4gICAgdHJhbnNpdGlvbjogYm94LXNoYWRvdyAwLjJzIGVhc2UtaW4tb3V0O1xufVxuLmlzVmVyYm9zZSAuYm9va0VkaXRvcldyYXBwZXIge1xuICAgIC8qKi9cbiAgICBvdmVyZmxvdzogdmlzaWJsZTtcbiAgICAvKiovXG59XG5cbi5ib29rRWRpdG9yV3JhcHBlcjpob3ZlciB7XG4gICAgYm94LXNoYWRvdzogMCA0cHggNnB4IC0xcHggcmdiYSgwLCAwLCAwLCAwLjEpLCAwIDJweCA0cHggLTFweCByZ2JhKDAsIDAsIDAsIDAuMDYpO1xufVxuXG4uYm9va0VkaXRvcldyYXBwZXI6Zm9jdXMtd2l0aGluIHtcbiAgICAvKlxuICAgIG91dGxpbmU6IDJweCBzb2xpZCB0cmFuc3BhcmVudDtcbiAgICBvdXRsaW5lLW9mZnNldDogMnB4O1xuICAgIGJveC1zaGFkb3c6IDAgMCAwIDNweCByZ2JhKDk5LCAxMDIsIDI0MSwgMC40KTtcbiAgICAqL1xufVxuXG4uYm9va0VkaXRvcldyYXBwZXIuaXNCb3JkZXJSYWRpdXNEaXNhYmxlZCB7XG4gICAgYm9yZGVyLXJhZGl1czogMDtcbn1cblxuLmRyb3BPdmVybGF5IHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgdG9wOiAwO1xuICAgIGxlZnQ6IDA7XG4gICAgcmlnaHQ6IDA7XG4gICAgYm90dG9tOiAwO1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbiAgICBjb2xvcjogd2hpdGU7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgIGZvbnQtc2l6ZTogMS41cmVtO1xuICAgIHotaW5kZXg6IDEwMDtcbiAgICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuLypcbi5ib29rRWRpdG9yQ29udGFpbmVyIDpnbG9iYWwoLnZpZXctbGluZSkge1xuICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZWVlOyAvKiA8LSBOb3RlOiBgUFJPTVBUQk9PS19TWU5UQVhfQ09MT1JTLkxJTkVgICogL1xufVxuKi9cblxuLmJvb2tFZGl0b3JBY3Rpb25iYXIge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDEwcHg7XG4gICAgcmlnaHQ6IDU1cHg7XG4gICAgei1pbmRleDogMTAwO1xufVxuXG4uZnVsbHNjcmVlbiB7XG4gICAgcG9zaXRpb246IGZpeGVkO1xuICAgIHRvcDogMDtcbiAgICBsZWZ0OiAwO1xuICAgIHJpZ2h0OiAwO1xuICAgIGJvdHRvbTogMDtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgei1pbmRleDogOTk5OTtcbiAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgIHBhZGRpbmctdG9wOiA1MHB4O1xuICAgIGJvcmRlcjogbm9uZTtcbiAgICBib3gtc2hhZG93OiBub25lO1xufVxuXG4uYnV0dG9uIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmO1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNkMWQ1ZGI7XG4gICAgYm9yZGVyLXJhZGl1czogMC4zNzVyZW07XG4gICAgcGFkZGluZzogMC41cmVtIDFyZW07XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIGRpc3BsYXk6IGlubGluZS1mbGV4O1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgZ2FwOiAwLjVyZW07XG4gICAgY29sb3I6ICMzNzQxNTE7XG4gICAgYm94LXNoYWRvdzogMCAxcHggMnB4IDAgcmdiYSgwLCAwLCAwLCAwLjA1KTtcbiAgICB0cmFuc2l0aW9uOiBhbGwgMC4ycyBlYXNlLWluLW91dDtcbn1cblxuLmJ1dHRvbjpob3ZlciB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogI2Y5ZmFmYjtcbiAgICBib3JkZXItY29sb3I6ICNiN2JjY2U7XG4gICAgYm94LXNoYWRvdzogMCAxcHggM3B4IDAgcmdiYSgwLCAwLCAwLCAwLjEpLCAwIDFweCAycHggMCByZ2JhKDAsIDAsIDAsIDAuMDYpO1xufVxuIl19 */";
7382
- var styles$6 = {"BookEditor":"BookEditor-module_BookEditor__s-0PU","bookEditorContainer":"BookEditor-module_bookEditorContainer__wLMwM","isVerbose":"BookEditor-module_isVerbose__VQ6iL","bookEditorWrapper":"BookEditor-module_bookEditorWrapper__twppD","isBorderRadiusDisabled":"BookEditor-module_isBorderRadiusDisabled__h1I3v","dropOverlay":"BookEditor-module_dropOverlay__xWWoX","bookEditorActionbar":"BookEditor-module_bookEditorActionbar__KW6dc","fullscreen":"BookEditor-module_fullscreen__rktsl","button":"BookEditor-module_button__hS390"};
7383
- styleInject(css_248z$7);
7552
+ var css_248z$8 = ".BookEditor-module_BookEditor__s-0PU{width:100%}.BookEditor-module_bookEditorContainer__wLMwM{box-sizing:border-box;height:100%;padding:10px 25px 0;position:relative;width:100%}.BookEditor-module_bookEditorContainer__wLMwM.BookEditor-module_isVerbose__VQ6iL{background-color:rgba(0,0,0,.05);outline:1px dotted rgba(0,0,0,.5)}.BookEditor-module_isVerbose__VQ6iL{outline:2px dotted #ff7526}.BookEditor-module_bookEditorWrapper__twppD{background-color:#fff;border:1px solid rgba(209,213,219,.8);border-radius:1rem;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);overflow:hidden;padding-top:10px;transition:box-shadow .2s ease-in-out}.BookEditor-module_isVerbose__VQ6iL .BookEditor-module_bookEditorWrapper__twppD{overflow:visible}.BookEditor-module_bookEditorWrapper__twppD:hover{box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.BookEditor-module_bookEditorWrapper__twppD.BookEditor-module_isBorderRadiusDisabled__h1I3v{border-radius:0}.BookEditor-module_dropOverlay__xWWoX{align-items:center;background-color:rgba(0,0,0,.5);bottom:0;color:#fff;display:flex;font-size:1.5rem;justify-content:center;left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:100}.BookEditor-module_bookEditorActionbar__KW6dc{position:absolute;right:55px;top:10px;z-index:100}.BookEditor-module_fullscreen__rktsl{border:none;border-radius:0;bottom:0;box-shadow:none;height:100%;left:0;padding-top:50px;position:fixed;right:0;top:0;width:100%;z-index:9999}.BookEditor-module_button__hS390{align-items:center;background-color:#fff;border:1px solid #d1d5db;border-radius:.375rem;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);color:#374151;cursor:pointer;display:inline-flex;gap:.5rem;padding:.5rem 1rem;transition:all .2s ease-in-out}.BookEditor-module_button__hS390:hover{background-color:#f9fafb;border-color:#b7bcce;box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06)}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkJvb2tFZGl0b3IubW9kdWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxxQ0FFSSxVQUNKLENBRUEsOENBS0kscUJBQXNCLENBSHRCLFdBQVksQ0FFWixtQkFBb0IsQ0FEcEIsaUJBQWtCLENBRmxCLFVBS0osQ0FFQSxpRkFFSSxnQ0FBcUMsQ0FDckMsaUNBRUosQ0FFQSxvQ0FDSSwwQkFDSixDQUVBLDRDQUtJLHFCQUF1QixDQUR2QixxQ0FBMEMsQ0FGMUMsa0JBQW1CLENBSW5CLHNDQUEyQyxDQUwzQyxlQUFnQixDQUVoQixnQkFBaUIsQ0FJakIscUNBQ0osQ0FDQSxnRkFFSSxnQkFFSixDQUVBLGtEQUNJLHVFQUNKLENBVUEsNEZBQ0ksZUFDSixDQUVBLHNDQVNJLGtCQUFtQixDQUhuQiwrQkFBb0MsQ0FEcEMsUUFBUyxDQUVULFVBQVksQ0FDWixZQUFhLENBR2IsZ0JBQWlCLENBRGpCLHNCQUF1QixDQVB2QixNQUFPLENBVVAsbUJBQW9CLENBWnBCLGlCQUFrQixDQUdsQixPQUFRLENBRlIsS0FBTSxDQVVOLFdBRUosQ0FRQSw4Q0FDSSxpQkFBa0IsQ0FFbEIsVUFBVyxDQURYLFFBQVMsQ0FFVCxXQUNKLENBRUEscUNBV0ksV0FBWSxDQUZaLGVBQWdCLENBSmhCLFFBQVMsQ0FPVCxlQUFnQixDQUxoQixXQUFZLENBSlosTUFBTyxDQU9QLGdCQUFpQixDQVRqQixjQUFlLENBR2YsT0FBUSxDQUZSLEtBQU0sQ0FJTixVQUFXLENBRVgsWUFLSixDQUVBLGlDQU9JLGtCQUFtQixDQU5uQixxQkFBc0IsQ0FDdEIsd0JBQXlCLENBQ3pCLHFCQUF1QixDQU92QixzQ0FBMkMsQ0FEM0MsYUFBYyxDQUpkLGNBQWUsQ0FDZixtQkFBb0IsQ0FFcEIsU0FBVyxDQUpYLGtCQUFvQixDQU9wQiw4QkFDSixDQUVBLHVDQUNJLHdCQUF5QixDQUN6QixvQkFBcUIsQ0FDckIsaUVBQ0oiLCJmaWxlIjoiQm9va0VkaXRvci5tb2R1bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLkJvb2tFZGl0b3Ige1xuICAgIC8qIGhlaWdodDogNDUwcHg7ICovXG4gICAgd2lkdGg6IDEwMCU7XG59XG5cbi5ib29rRWRpdG9yQ29udGFpbmVyIHtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIHBhZGRpbmc6IDEwcHggMjVweCAwO1xuICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG59XG5cbi5ib29rRWRpdG9yQ29udGFpbmVyLmlzVmVyYm9zZSB7XG4gICAgLyoqL1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC4wNSk7XG4gICAgb3V0bGluZTogMXB4IGRvdHRlZCByZ2JhKDAsIDAsIDAsIDAuNSk7XG4gICAgLyoqL1xufVxuXG4uaXNWZXJib3NlIHtcbiAgICBvdXRsaW5lOiAycHggZG90dGVkIHJnYigyNTUgMTE3IDM4KTtcbn1cblxuLmJvb2tFZGl0b3JXcmFwcGVyIHtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIGJvcmRlci1yYWRpdXM6IDFyZW07XG4gICAgcGFkZGluZy10b3A6IDEwcHg7XG4gICAgYm9yZGVyOiAxcHggc29saWQgcmdiYSgyMDksIDIxMywgMjE5LCAwLjgpO1xuICAgIGJhY2tncm91bmQtY29sb3I6IHdoaXRlO1xuICAgIGJveC1zaGFkb3c6IDAgMXB4IDJweCAwIHJnYmEoMCwgMCwgMCwgMC4wNSk7XG4gICAgdHJhbnNpdGlvbjogYm94LXNoYWRvdyAwLjJzIGVhc2UtaW4tb3V0O1xufVxuLmlzVmVyYm9zZSAuYm9va0VkaXRvcldyYXBwZXIge1xuICAgIC8qKi9cbiAgICBvdmVyZmxvdzogdmlzaWJsZTtcbiAgICAvKiovXG59XG5cbi5ib29rRWRpdG9yV3JhcHBlcjpob3ZlciB7XG4gICAgYm94LXNoYWRvdzogMCA0cHggNnB4IC0xcHggcmdiYSgwLCAwLCAwLCAwLjEpLCAwIDJweCA0cHggLTFweCByZ2JhKDAsIDAsIDAsIDAuMDYpO1xufVxuXG4uYm9va0VkaXRvcldyYXBwZXI6Zm9jdXMtd2l0aGluIHtcbiAgICAvKlxuICAgIG91dGxpbmU6IDJweCBzb2xpZCB0cmFuc3BhcmVudDtcbiAgICBvdXRsaW5lLW9mZnNldDogMnB4O1xuICAgIGJveC1zaGFkb3c6IDAgMCAwIDNweCByZ2JhKDk5LCAxMDIsIDI0MSwgMC40KTtcbiAgICAqL1xufVxuXG4uYm9va0VkaXRvcldyYXBwZXIuaXNCb3JkZXJSYWRpdXNEaXNhYmxlZCB7XG4gICAgYm9yZGVyLXJhZGl1czogMDtcbn1cblxuLmRyb3BPdmVybGF5IHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgdG9wOiAwO1xuICAgIGxlZnQ6IDA7XG4gICAgcmlnaHQ6IDA7XG4gICAgYm90dG9tOiAwO1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbiAgICBjb2xvcjogd2hpdGU7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgIGZvbnQtc2l6ZTogMS41cmVtO1xuICAgIHotaW5kZXg6IDEwMDtcbiAgICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuLypcbi5ib29rRWRpdG9yQ29udGFpbmVyIDpnbG9iYWwoLnZpZXctbGluZSkge1xuICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZWVlOyAvKiA8LSBOb3RlOiBgUFJPTVBUQk9PS19TWU5UQVhfQ09MT1JTLkxJTkVgICogL1xufVxuKi9cblxuLmJvb2tFZGl0b3JBY3Rpb25iYXIge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDEwcHg7XG4gICAgcmlnaHQ6IDU1cHg7XG4gICAgei1pbmRleDogMTAwO1xufVxuXG4uZnVsbHNjcmVlbiB7XG4gICAgcG9zaXRpb246IGZpeGVkO1xuICAgIHRvcDogMDtcbiAgICBsZWZ0OiAwO1xuICAgIHJpZ2h0OiAwO1xuICAgIGJvdHRvbTogMDtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgei1pbmRleDogOTk5OTtcbiAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgIHBhZGRpbmctdG9wOiA1MHB4O1xuICAgIGJvcmRlcjogbm9uZTtcbiAgICBib3gtc2hhZG93OiBub25lO1xufVxuXG4uYnV0dG9uIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmO1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNkMWQ1ZGI7XG4gICAgYm9yZGVyLXJhZGl1czogMC4zNzVyZW07XG4gICAgcGFkZGluZzogMC41cmVtIDFyZW07XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIGRpc3BsYXk6IGlubGluZS1mbGV4O1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgZ2FwOiAwLjVyZW07XG4gICAgY29sb3I6ICMzNzQxNTE7XG4gICAgYm94LXNoYWRvdzogMCAxcHggMnB4IDAgcmdiYSgwLCAwLCAwLCAwLjA1KTtcbiAgICB0cmFuc2l0aW9uOiBhbGwgMC4ycyBlYXNlLWluLW91dDtcbn1cblxuLmJ1dHRvbjpob3ZlciB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogI2Y5ZmFmYjtcbiAgICBib3JkZXItY29sb3I6ICNiN2JjY2U7XG4gICAgYm94LXNoYWRvdzogMCAxcHggM3B4IDAgcmdiYSgwLCAwLCAwLCAwLjEpLCAwIDFweCAycHggMCByZ2JhKDAsIDAsIDAsIDAuMDYpO1xufVxuIl19 */";
7553
+ var styles$7 = {"BookEditor":"BookEditor-module_BookEditor__s-0PU","bookEditorContainer":"BookEditor-module_bookEditorContainer__wLMwM","isVerbose":"BookEditor-module_isVerbose__VQ6iL","bookEditorWrapper":"BookEditor-module_bookEditorWrapper__twppD","isBorderRadiusDisabled":"BookEditor-module_isBorderRadiusDisabled__h1I3v","dropOverlay":"BookEditor-module_dropOverlay__xWWoX","bookEditorActionbar":"BookEditor-module_bookEditorActionbar__KW6dc","fullscreen":"BookEditor-module_fullscreen__rktsl","button":"BookEditor-module_button__hS390"};
7554
+ styleInject(css_248z$8);
7384
7555
 
7385
7556
  /**
7386
7557
  * Converts Blob, File or MediaSource to url using URL.createObjectURL
@@ -7500,12 +7671,107 @@
7500
7671
  * Note: [๐Ÿ”ต] Code in this file should never be published outside of `@promptbook/browser`
7501
7672
  */
7502
7673
 
7674
+ /**
7675
+ * Downloads a file with the given content and filename
7676
+ *
7677
+ * @private utility of `<Chat/>` component
7678
+ */
7679
+ function downloadFile(content, filename, mimeType) {
7680
+ const blob = new Blob([content], { type: mimeType });
7681
+ const url = URL.createObjectURL(blob);
7682
+ const link = document.createElement('a');
7683
+ link.href = url;
7684
+ link.download = filename;
7685
+ document.body.appendChild(link);
7686
+ link.click();
7687
+ document.body.removeChild(link);
7688
+ // Clean up the URL object
7689
+ setTimeout(() => URL.revokeObjectURL(url), 100);
7690
+ }
7691
+
7692
+ var css_248z$7 = ".CodeBlock-module_CodeBlock__6K33Z{border:1px solid #444;border-radius:5px;margin:10px 0;overflow:hidden}.CodeBlock-module_CodeBlockHeader__tfOwl{align-items:center;background-color:#2d2d2d;border-bottom:1px solid #444;color:#ccc;display:flex;font-size:.8em;justify-content:space-between;padding:5px 10px}.CodeBlock-module_CodeBlockButtons__rz1VO{display:flex;gap:8px}.CodeBlock-module_CopyButton__M07tp,.CodeBlock-module_CreateAgentButton__kUEnp,.CodeBlock-module_DownloadButton__ZTrzQ{align-items:center;background:transparent;border:none;color:#aaa;cursor:pointer;display:flex;font-size:inherit;gap:5px;padding:0;transition:color .2s}.CodeBlock-module_CopyButton__M07tp:hover,.CodeBlock-module_CreateAgentButton__kUEnp:hover,.CodeBlock-module_DownloadButton__ZTrzQ:hover{color:#fff}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkNvZGVCbG9jay5tb2R1bGUuY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG1DQUlJLHFCQUFzQixDQUZ0QixpQkFBa0IsQ0FEbEIsYUFBYyxDQUVkLGVBRUosQ0FFQSx5Q0FRSSxrQkFBbUIsQ0FQbkIsd0JBQXlCLENBSXpCLDRCQUE2QixDQUg3QixVQUFXLENBSVgsWUFBYSxDQUZiLGNBQWdCLENBR2hCLDZCQUE4QixDQUo5QixnQkFNSixDQUVBLDBDQUNJLFlBQWEsQ0FDYixPQUNKLENBRUEsdUhBVUksa0JBQW1CLENBUG5CLHNCQUF1QixDQUN2QixXQUFZLENBQ1osVUFBVyxDQUNYLGNBQWUsQ0FHZixZQUFhLENBRmIsaUJBQWtCLENBSWxCLE9BQVEsQ0FIUixTQUFVLENBSVYsb0JBQ0osQ0FFQSx5SUFHSSxVQUNKIiwiZmlsZSI6IkNvZGVCbG9jay5tb2R1bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLkNvZGVCbG9jayB7XG4gICAgbWFyZ2luOiAxMHB4IDA7XG4gICAgYm9yZGVyLXJhZGl1czogNXB4O1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgYm9yZGVyOiAxcHggc29saWQgIzQ0NDsgLyogRGFyayBtb2RlIGJvcmRlciAqL1xufVxuXG4uQ29kZUJsb2NrSGVhZGVyIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMmQyZDJkO1xuICAgIGNvbG9yOiAjY2NjO1xuICAgIHBhZGRpbmc6IDVweCAxMHB4O1xuICAgIGZvbnQtc2l6ZTogMC44ZW07XG4gICAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICM0NDQ7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbn1cblxuLkNvZGVCbG9ja0J1dHRvbnMge1xuICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgZ2FwOiA4cHg7XG59XG5cbi5Db3B5QnV0dG9uLFxuLkRvd25sb2FkQnV0dG9uLFxuLkNyZWF0ZUFnZW50QnV0dG9uIHtcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgICBib3JkZXI6IG5vbmU7XG4gICAgY29sb3I6ICNhYWE7XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIGZvbnQtc2l6ZTogaW5oZXJpdDtcbiAgICBwYWRkaW5nOiAwO1xuICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICBnYXA6IDVweDtcbiAgICB0cmFuc2l0aW9uOiBjb2xvciAwLjJzO1xufVxuXG4uQ29weUJ1dHRvbjpob3Zlcixcbi5Eb3dubG9hZEJ1dHRvbjpob3Zlcixcbi5DcmVhdGVBZ2VudEJ1dHRvbjpob3ZlciB7XG4gICAgY29sb3I6ICNmZmY7XG59XG4iXX0= */";
7693
+ var styles$6 = {"CodeBlock":"CodeBlock-module_CodeBlock__6K33Z","CodeBlockHeader":"CodeBlock-module_CodeBlockHeader__tfOwl","CodeBlockButtons":"CodeBlock-module_CodeBlockButtons__rz1VO","CopyButton":"CodeBlock-module_CopyButton__M07tp","DownloadButton":"CodeBlock-module_DownloadButton__ZTrzQ","CreateAgentButton":"CodeBlock-module_CreateAgentButton__kUEnp"};
7694
+ styleInject(css_248z$7);
7695
+
7696
+ const LANGUAGE_EXTENSIONS = {
7697
+ python: 'py',
7698
+ javascript: 'js',
7699
+ typescript: 'ts',
7700
+ json: 'json',
7701
+ html: 'html',
7702
+ css: 'css',
7703
+ markdown: 'md',
7704
+ text: 'txt',
7705
+ xml: 'xml',
7706
+ sql: 'sql',
7707
+ sh: 'sh',
7708
+ bash: 'sh',
7709
+ zsh: 'sh',
7710
+ yaml: 'yaml',
7711
+ yml: 'yaml',
7712
+ book: 'book',
7713
+ };
7714
+ /**
7715
+ * Component to render a code block with syntax highlighting, copy, download, and create agent options.
7716
+ *
7717
+ * @private Internal utility of `<ChatMessage />` component
7718
+ */
7719
+ function CodeBlock({ code, language, className, onCreateAgent }) {
7720
+ const lines = react.useMemo(() => code.split('\n').length, [code]);
7721
+ // Note: 19px is approx line height for fontSize 14. +20 for padding.
7722
+ // We cap at 400px to avoid taking too much space, allowing scroll.
7723
+ const height = Math.min(Math.max(lines * 19, 19), 400);
7724
+ const [copied, setCopied] = react.useState(false);
7725
+ const handleDownload = () => {
7726
+ const lang = (language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) || 'text';
7727
+ const extension = LANGUAGE_EXTENSIONS[lang] || lang;
7728
+ const filename = `file.${extension}`;
7729
+ downloadFile(code, filename, 'text/plain');
7730
+ };
7731
+ const handleCopy = async () => {
7732
+ try {
7733
+ await navigator.clipboard.writeText(code);
7734
+ setCopied(true);
7735
+ setTimeout(() => setCopied(false), 2000);
7736
+ }
7737
+ catch (error) {
7738
+ console.error('Failed to copy code to clipboard:', error);
7739
+ }
7740
+ };
7741
+ const header = language ? (jsxRuntime.jsxs("div", { className: styles$6.CodeBlockHeader, children: [jsxRuntime.jsx("span", { children: language }), jsxRuntime.jsxs("div", { className: styles$6.CodeBlockButtons, children: [jsxRuntime.jsx("button", { onClick: handleCopy, className: styles$6.CopyButton, title: "Copy to clipboard", children: copied ? 'Copied!' : 'Copy' }), jsxRuntime.jsx("button", { onClick: handleDownload, className: styles$6.DownloadButton, title: "Download code", children: "Download" }), (language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) === 'book' && onCreateAgent && (jsxRuntime.jsx("button", { onClick: () => onCreateAgent(code), className: styles$6.CreateAgentButton, title: "Create agent from this book", children: "Create Agent" }))] })] })) : null;
7742
+ if ((language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) === 'book') {
7743
+ return (jsxRuntime.jsxs("div", { className: classNames(styles$6.CodeBlock, className), children: [header, jsxRuntime.jsx(BookEditor, { value: code, isReadonly: true, height: lines * 25 /* <- [๐Ÿง ] A bit more than 19px to accommodate BookEditor lines */ })] }));
7744
+ }
7745
+ return (jsxRuntime.jsxs("div", { className: classNames(styles$6.CodeBlock, className), children: [header, jsxRuntime.jsx(Editor__default["default"], { height: `${height}px`, language: language || 'plaintext', value: code, theme: "vs-dark", options: {
7746
+ readOnly: true,
7747
+ minimap: { enabled: false },
7748
+ scrollBeyondLastLine: false,
7749
+ lineNumbers: 'on',
7750
+ folding: false,
7751
+ glyphMargin: false,
7752
+ fontFamily: 'Consolas, "Courier New", monospace',
7753
+ fontSize: 14,
7754
+ lineHeight: 19,
7755
+ overviewRulerLanes: 0,
7756
+ hideCursorInOverviewRuler: true,
7757
+ renderLineHighlight: 'none',
7758
+ contextmenu: false,
7759
+ scrollbar: {
7760
+ vertical: 'auto',
7761
+ horizontal: 'auto',
7762
+ useShadows: false,
7763
+ },
7764
+ domReadOnly: true,
7765
+ wordWrap: 'off',
7766
+ } })] }));
7767
+ }
7768
+
7503
7769
  var css_248z$6 = ".MarkdownContent-module_MarkdownContent__2JuyX h1{font-size:2em}.MarkdownContent-module_MarkdownContent__2JuyX h2{font-size:1.75em}.MarkdownContent-module_MarkdownContent__2JuyX h3{font-size:1.5em}.MarkdownContent-module_MarkdownContent__2JuyX h4{font-size:1.25em}.MarkdownContent-module_MarkdownContent__2JuyX h5{font-size:1.1em}.MarkdownContent-module_MarkdownContent__2JuyX p{text-wrap:auto}.MarkdownContent-module_MarkdownContent__2JuyX ul{list-style:disc;margin-left:20px}.MarkdownContent-module_MarkdownContent__2JuyX ol{list-style:decimal;margin-left:20px}.MarkdownContent-module_MarkdownContent__2JuyX blockquote,.MarkdownContent-module_MarkdownContent__2JuyX img,.MarkdownContent-module_MarkdownContent__2JuyX pre,.MarkdownContent-module_MarkdownContent__2JuyX table{border-radius:8px;margin-bottom:10px;margin-top:10px}.MarkdownContent-module_MarkdownContent__2JuyX pre{background:#000;border:none;box-shadow:none;color:#fff;display:block;font-size:inherit;line-height:inherit;padding:1em}.MarkdownContent-module_MarkdownContent__2JuyX blockquote{background:#ffffffcc;border:none;box-shadow:none;color:#000;display:block;font-size:inherit;line-height:inherit;padding:1em}.MarkdownContent-module_MarkdownContent__2JuyX code{background:#cccccc55;border:none;box-shadow:none;color:inherit;display:inline-block;font-size:inherit;line-height:inherit;margin:0;padding:0}.MarkdownContent-module_MarkdownContent__2JuyX pre code{background-color:#000000cc;border-radius:8px}.MarkdownContent-module_MarkdownContent__2JuyX .MarkdownContent-module_chat-code-block__ZffFg{background:#181c23;border-color:#23272f;box-shadow:0 2px 8px rgba(0,0,0,.12);color:#f8fafc;font-family:Fira Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:14px;line-height:1.6;overflow-x:auto}.MarkdownContent-module_MarkdownContent__2JuyX .MarkdownContent-module_chat-code-block__ZffFg code{background:none!important;border:none!important;box-shadow:none!important;color:inherit!important;display:block;font-family:inherit!important;font-size:inherit!important;overflow-x:auto;padding:0!important;white-space:pre;word-break:break-word}.MarkdownContent-module_MarkdownContent__2JuyX table{background:#f8fafc;border-collapse:separate;border-spacing:0;box-shadow:0 2px 8px rgba(0,0,0,.08);color:#17223b;font-size:14px;margin:16px 0;width:100%}.MarkdownContent-module_MarkdownContent__2JuyX td,.MarkdownContent-module_MarkdownContent__2JuyX th{background:none;border-bottom:1px solid #d1dbe8;color:#17223b;padding:10px 16px;text-align:left}.MarkdownContent-module_MarkdownContent__2JuyX th{background:linear-gradient(90deg,#eaf3fa 80%,#d1e3f8);border-bottom:2px solid #b5c7de;color:#17223b;font-weight:700}.MarkdownContent-module_MarkdownContent__2JuyX tr:last-child td{border-bottom:none}.MarkdownContent-module_MarkdownContent__2JuyX tr:nth-child(2n) td{background:#eaf3fa}.MarkdownContent-module_MarkdownContent__2JuyX tr:hover td{background:#cbe0f7;transition:background .2s}.MarkdownContent-module_MarkdownContent__2JuyX table{border-radius:12px;overflow:hidden}.MarkdownContent-module_MarkdownContent__2JuyX td:first-child,.MarkdownContent-module_MarkdownContent__2JuyX th:first-child{border-top-left-radius:12px}.MarkdownContent-module_MarkdownContent__2JuyX td:last-child,.MarkdownContent-module_MarkdownContent__2JuyX th:last-child{border-top-right-radius:12px}.MarkdownContent-module_citation__11SMw{background:#e7f1ff;border-radius:4px;color:#007bff;cursor:default;display:inline-block;font-size:.7em;font-weight:700;margin:0 2px;padding:0 4px;user-select:none;vertical-align:super}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIk1hcmtkb3duQ29udGVudC5tb2R1bGUuY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGtEQUNJLGFBQ0osQ0FFQSxrREFDSSxnQkFDSixDQUVBLGtEQUNJLGVBQ0osQ0FFQSxrREFDSSxnQkFDSixDQUVBLGtEQUNJLGVBQ0osQ0FFQSxpREFDSSxjQUNKLENBRUEsa0RBQ0ksZUFBZ0IsQ0FDaEIsZ0JBQ0osQ0FFQSxrREFDSSxrQkFBbUIsQ0FDbkIsZ0JBQ0osQ0FFQSxxTkFNSSxpQkFBa0IsQ0FEbEIsa0JBQW1CLENBRG5CLGVBR0osQ0FFQSxtREFJSSxlQUFxQixDQUZyQixXQUFZLENBQ1osZUFBZ0IsQ0FJaEIsVUFBVyxDQU5YLGFBQWMsQ0FJZCxpQkFBa0IsQ0FDbEIsbUJBQW9CLENBRXBCLFdBQ0osQ0FFQSwwREFJSSxvQkFBcUIsQ0FGckIsV0FBWSxDQUNaLGVBQWdCLENBSWhCLFVBQVcsQ0FOWCxhQUFjLENBSWQsaUJBQWtCLENBQ2xCLG1CQUFvQixDQUVwQixXQUNKLENBRUEsb0RBTUksb0JBQXFCLENBRnJCLFdBQVksQ0FDWixlQUFnQixDQUloQixhQUFjLENBUmQsb0JBQXFCLENBTXJCLGlCQUFrQixDQUNsQixtQkFBb0IsQ0FOcEIsUUFBUyxDQUNULFNBT0osQ0FFQSx3REFDSSwwQkFBMkIsQ0FDM0IsaUJBQ0osQ0FFQSw4RkFDSSxrQkFBbUIsQ0FLbkIsb0JBQXFCLENBQ3JCLG9DQUF5QyxDQUx6QyxhQUFjLENBTWQsOERBQTJFLENBTDNFLGNBQWUsQ0FDZixlQUFnQixDQUNoQixlQUlKLENBQ0EsbUdBQ0kseUJBQTJCLENBSzNCLHFCQUF1QixDQUN2Qix5QkFBMkIsQ0FMM0IsdUJBQXlCLENBU3pCLGFBQWMsQ0FSZCw2QkFBK0IsQ0FDL0IsMkJBQTZCLENBTTdCLGVBQWdCLENBTGhCLG1CQUFxQixDQUdyQixlQUFnQixDQUNoQixxQkFHSixDQUNBLHFEQUtJLGtCQUFtQixDQUhuQix3QkFBeUIsQ0FDekIsZ0JBQWlCLENBS2pCLG9DQUF5QyxDQUV6QyxhQUFjLENBRGQsY0FBZSxDQUxmLGFBQWMsQ0FIZCxVQVVKLENBQ0Esb0dBTUksZUFBZ0IsQ0FIaEIsK0JBQWdDLENBRWhDLGFBQWMsQ0FIZCxpQkFBa0IsQ0FFbEIsZUFHSixDQUNBLGtEQUNJLHFEQUE2RCxDQUc3RCwrQkFBZ0MsQ0FEaEMsYUFBYyxDQURkLGVBR0osQ0FDQSxnRUFDSSxrQkFDSixDQUNBLG1FQUNJLGtCQUNKLENBQ0EsMkRBQ0ksa0JBQW1CLENBQ25CLHlCQUNKLENBQ0EscURBQ0ksa0JBQW1CLENBQ25CLGVBQ0osQ0FDQSw0SEFFSSwyQkFDSixDQUNBLDBIQUVJLDRCQUNKLENBRUEsd0NBTUksa0JBQW1CLENBRW5CLGlCQUFrQixDQUhsQixhQUFjLENBS2QsY0FBZSxDQVRmLG9CQUFxQixDQUVyQixjQUFnQixDQUNoQixlQUFpQixDQUtqQixZQUFhLENBRmIsYUFBYyxDQUlkLGdCQUFpQixDQVRqQixvQkFVSiIsImZpbGUiOiJNYXJrZG93bkNvbnRlbnQubW9kdWxlLmNzcyIsInNvdXJjZXNDb250ZW50IjpbIi5NYXJrZG93bkNvbnRlbnQgaDEge1xuICAgIGZvbnQtc2l6ZTogMmVtO1xufVxuXG4uTWFya2Rvd25Db250ZW50IGgyIHtcbiAgICBmb250LXNpemU6IDEuNzVlbTtcbn1cblxuLk1hcmtkb3duQ29udGVudCBoMyB7XG4gICAgZm9udC1zaXplOiAxLjVlbTtcbn1cblxuLk1hcmtkb3duQ29udGVudCBoNCB7XG4gICAgZm9udC1zaXplOiAxLjI1ZW07XG59XG5cbi5NYXJrZG93bkNvbnRlbnQgaDUge1xuICAgIGZvbnQtc2l6ZTogMS4xZW07XG59XG5cbi5NYXJrZG93bkNvbnRlbnQgcCB7XG4gICAgdGV4dC13cmFwOiBhdXRvO1xufVxuXG4uTWFya2Rvd25Db250ZW50IHVsIHtcbiAgICBsaXN0LXN0eWxlOiBkaXNjO1xuICAgIG1hcmdpbi1sZWZ0OiAyMHB4O1xufVxuXG4uTWFya2Rvd25Db250ZW50IG9sIHtcbiAgICBsaXN0LXN0eWxlOiBkZWNpbWFsO1xuICAgIG1hcmdpbi1sZWZ0OiAyMHB4O1xufVxuXG4uTWFya2Rvd25Db250ZW50IGltZyxcbi5NYXJrZG93bkNvbnRlbnQgcHJlLFxuLk1hcmtkb3duQ29udGVudCBibG9ja3F1b3RlLFxuLk1hcmtkb3duQ29udGVudCB0YWJsZSB7XG4gICAgbWFyZ2luLXRvcDogMTBweDtcbiAgICBtYXJnaW4tYm90dG9tOiAxMHB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDhweDtcbn1cblxuLk1hcmtkb3duQ29udGVudCBwcmUge1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGJvcmRlcjogbm9uZTtcbiAgICBib3gtc2hhZG93OiBub25lO1xuICAgIGJhY2tncm91bmQ6ICMwMDAwMDBmZjtcbiAgICBmb250LXNpemU6IGluaGVyaXQ7XG4gICAgbGluZS1oZWlnaHQ6IGluaGVyaXQ7XG4gICAgY29sb3I6ICNmZmY7XG4gICAgcGFkZGluZzogMWVtO1xufVxuXG4uTWFya2Rvd25Db250ZW50IGJsb2NrcXVvdGUge1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGJvcmRlcjogbm9uZTtcbiAgICBib3gtc2hhZG93OiBub25lO1xuICAgIGJhY2tncm91bmQ6ICNmZmZmZmZjYztcbiAgICBmb250LXNpemU6IGluaGVyaXQ7XG4gICAgbGluZS1oZWlnaHQ6IGluaGVyaXQ7XG4gICAgY29sb3I6ICMwMDA7XG4gICAgcGFkZGluZzogMWVtO1xufVxuXG4uTWFya2Rvd25Db250ZW50IGNvZGUge1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICBtYXJnaW46IDA7XG4gICAgcGFkZGluZzogMDtcbiAgICBib3JkZXI6IG5vbmU7XG4gICAgYm94LXNoYWRvdzogbm9uZTtcbiAgICBiYWNrZ3JvdW5kOiAjY2NjY2NjNTU7XG4gICAgZm9udC1zaXplOiBpbmhlcml0O1xuICAgIGxpbmUtaGVpZ2h0OiBpbmhlcml0O1xuICAgIGNvbG9yOiBpbmhlcml0O1xufVxuXG4uTWFya2Rvd25Db250ZW50IHByZSBjb2RlIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwMDAwY2M7XG4gICAgYm9yZGVyLXJhZGl1czogOHB4O1xufVxuXG4uTWFya2Rvd25Db250ZW50IC5jaGF0LWNvZGUtYmxvY2sge1xuICAgIGJhY2tncm91bmQ6ICMxODFjMjM7XG4gICAgY29sb3I6ICNmOGZhZmM7XG4gICAgZm9udC1zaXplOiAxNHB4O1xuICAgIGxpbmUtaGVpZ2h0OiAxLjY7XG4gICAgb3ZlcmZsb3cteDogYXV0bztcbiAgICBib3JkZXItY29sb3I6ICMyMzI3MmY7XG4gICAgYm94LXNoYWRvdzogMCAycHggOHB4IHJnYmEoMCwgMCwgMCwgMC4xMik7XG4gICAgZm9udC1mYW1pbHk6ICdGaXJhIE1vbm8nLCAnTWVubG8nLCAnQ29uc29sYXMnLCAnTGliZXJhdGlvbiBNb25vJywgbW9ub3NwYWNlO1xufVxuLk1hcmtkb3duQ29udGVudCAuY2hhdC1jb2RlLWJsb2NrIGNvZGUge1xuICAgIGJhY2tncm91bmQ6IG5vbmUgIWltcG9ydGFudDtcbiAgICBjb2xvcjogaW5oZXJpdCAhaW1wb3J0YW50O1xuICAgIGZvbnQtZmFtaWx5OiBpbmhlcml0ICFpbXBvcnRhbnQ7XG4gICAgZm9udC1zaXplOiBpbmhlcml0ICFpbXBvcnRhbnQ7XG4gICAgcGFkZGluZzogMCAhaW1wb3J0YW50O1xuICAgIGJvcmRlcjogbm9uZSAhaW1wb3J0YW50O1xuICAgIGJveC1zaGFkb3c6IG5vbmUgIWltcG9ydGFudDtcbiAgICB3aGl0ZS1zcGFjZTogcHJlO1xuICAgIHdvcmQtYnJlYWs6IGJyZWFrLXdvcmQ7XG4gICAgb3ZlcmZsb3cteDogYXV0bztcbiAgICBkaXNwbGF5OiBibG9jaztcbn1cbi5NYXJrZG93bkNvbnRlbnQgdGFibGUge1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIGJvcmRlci1jb2xsYXBzZTogc2VwYXJhdGU7XG4gICAgYm9yZGVyLXNwYWNpbmc6IDA7XG4gICAgbWFyZ2luOiAxNnB4IDA7XG4gICAgYmFja2dyb3VuZDogI2Y4ZmFmYzsgLyogU3Ryb25nZXIgbGlnaHQgYmFja2dyb3VuZCBmb3IgY29udHJhc3QgKi9cbiAgICBib3JkZXItcmFkaXVzOiAxMnB4O1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgYm94LXNoYWRvdzogMCAycHggOHB4IHJnYmEoMCwgMCwgMCwgMC4wOCk7XG4gICAgZm9udC1zaXplOiAxNHB4O1xuICAgIGNvbG9yOiAjMTcyMjNiOyAvKiBEYXJrIHRleHQgZm9yIGNvbnRyYXN0ICovXG59XG4uTWFya2Rvd25Db250ZW50IHRoLFxuLk1hcmtkb3duQ29udGVudCB0ZCB7XG4gICAgcGFkZGluZzogMTBweCAxNnB4O1xuICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZDFkYmU4O1xuICAgIHRleHQtYWxpZ246IGxlZnQ7XG4gICAgY29sb3I6ICMxNzIyM2I7IC8qIEVuc3VyZSBzdHJvbmcgdGV4dCBjb2xvciBmb3IgYWxsIGNlbGxzICovXG4gICAgYmFja2dyb3VuZDogbm9uZTtcbn1cbi5NYXJrZG93bkNvbnRlbnQgdGgge1xuICAgIGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCg5MGRlZywgI2VhZjNmYSA4MCUsICNkMWUzZjggMTAwJSk7XG4gICAgZm9udC13ZWlnaHQ6IDcwMDtcbiAgICBjb2xvcjogIzE3MjIzYjsgLyogU3Ryb25nIGhlYWRlciB0ZXh0ICovXG4gICAgYm9yZGVyLWJvdHRvbTogMnB4IHNvbGlkICNiNWM3ZGU7XG59XG4uTWFya2Rvd25Db250ZW50IHRyOmxhc3QtY2hpbGQgdGQge1xuICAgIGJvcmRlci1ib3R0b206IG5vbmU7XG59XG4uTWFya2Rvd25Db250ZW50IHRyOm50aC1jaGlsZChldmVuKSB0ZCB7XG4gICAgYmFja2dyb3VuZDogI2VhZjNmYTtcbn1cbi5NYXJrZG93bkNvbnRlbnQgdHI6aG92ZXIgdGQge1xuICAgIGJhY2tncm91bmQ6ICNjYmUwZjc7XG4gICAgdHJhbnNpdGlvbjogYmFja2dyb3VuZCAwLjJzO1xufVxuLk1hcmtkb3duQ29udGVudCB0YWJsZSB7XG4gICAgYm9yZGVyLXJhZGl1czogMTJweDtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xufVxuLk1hcmtkb3duQ29udGVudCB0aDpmaXJzdC1jaGlsZCxcbi5NYXJrZG93bkNvbnRlbnQgdGQ6Zmlyc3QtY2hpbGQge1xuICAgIGJvcmRlci10b3AtbGVmdC1yYWRpdXM6IDEycHg7XG59XG4uTWFya2Rvd25Db250ZW50IHRoOmxhc3QtY2hpbGQsXG4uTWFya2Rvd25Db250ZW50IHRkOmxhc3QtY2hpbGQge1xuICAgIGJvcmRlci10b3AtcmlnaHQtcmFkaXVzOiAxMnB4O1xufVxuXG4uY2l0YXRpb24ge1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICB2ZXJ0aWNhbC1hbGlnbjogc3VwZXI7XG4gICAgZm9udC1zaXplOiAwLjdlbTtcbiAgICBmb250LXdlaWdodDogYm9sZDtcbiAgICBjb2xvcjogIzAwN2JmZjtcbiAgICBiYWNrZ3JvdW5kOiAjZTdmMWZmO1xuICAgIHBhZGRpbmc6IDAgNHB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDRweDtcbiAgICBtYXJnaW46IDAgMnB4O1xuICAgIGN1cnNvcjogZGVmYXVsdDtcbiAgICB1c2VyLXNlbGVjdDogbm9uZTtcbn1cblxuLyoqXG4gKiBUT0RPOiBb8J+MiV0gRFJZIE1hcmtkb3duIHByaW1pdGl2ZXMgc3R5bGluZ1xuICovXG4iXX0= */";
7504
7770
  var styles$5 = {"MarkdownContent":"MarkdownContent-module_MarkdownContent__2JuyX","chat-code-block":"MarkdownContent-module_chat-code-block__ZffFg","citation":"MarkdownContent-module_citation__11SMw"};
7505
7771
  styleInject(css_248z$6);
7506
7772
 
7507
7773
  /**
7508
- * @@@
7774
+ * Creates a showdown converter configured for chat markdown rendering
7509
7775
  *
7510
7776
  * @private utility of `MarkdownContent` component
7511
7777
  */
@@ -7553,13 +7819,13 @@
7553
7819
  });
7554
7820
  }
7555
7821
  /**
7556
- * @@@
7822
+ * Pre-configured showdown converter for chat markdown
7557
7823
  *
7558
7824
  * @private utility of `MarkdownContent` component
7559
7825
  */
7560
7826
  const chatMarkdownConverter = createChatMarkdownConverter();
7561
7827
  /**
7562
- * @@@
7828
+ * Renders math expressions in markdown using KaTeX
7563
7829
  *
7564
7830
  * @private utility of `MarkdownContent` component
7565
7831
  */
@@ -7602,32 +7868,8 @@
7602
7868
  }
7603
7869
  try {
7604
7870
  const processedMarkdown = renderMathInMarkdown(markdown);
7605
- let html = chatMarkdownConverter.makeHtml(processedMarkdown);
7606
- if (typeof window === 'undefined') {
7607
- html = html.replace(/<pre><code( class="language-([^"]+)")?>([\s\S]*?)<\/code><\/pre>/g, (match, _langClass, lang, code) => {
7608
- const decoded = code
7609
- .replace(/&/g, '&')
7610
- .replace(/</g, '<')
7611
- .replace(/>/g, '>')
7612
- .replace(/"/g, '"')
7613
- .replace(/&#39;/g, "'");
7614
- const highlighted = lang
7615
- ? hljs__default["default"].highlight(decoded, { language: lang }).value
7616
- : hljs__default["default"].highlightAuto(decoded).value;
7617
- return `<pre class="chat-code-block"><code class="hljs${lang ? ' language-' + lang : ''}">${highlighted}</code></pre>`;
7618
- });
7619
- }
7620
- else {
7621
- if (html.match(/<pre><code/)) {
7622
- const cssId = 'hljs-github-dark-css';
7623
- if (!window.document.getElementById(cssId)) {
7624
- const link = window.document.createElement('link');
7625
- link.id = cssId;
7626
- link.rel = 'stylesheet';
7627
- link.href = 'https://book-components.ptbk.io/cdn/highlightjs/github-dark.css';
7628
- window.document.head.appendChild(link);
7629
- }
7630
- }
7871
+ const html = chatMarkdownConverter.makeHtml(processedMarkdown);
7872
+ if (typeof window !== 'undefined') {
7631
7873
  if (html.match(/class="katex/)) {
7632
7874
  const katexCssId = 'katex-css';
7633
7875
  if (!window.document.getElementById(katexCssId)) {
@@ -7638,38 +7880,6 @@
7638
7880
  window.document.head.appendChild(link);
7639
7881
  }
7640
7882
  }
7641
- const parser = new window.DOMParser();
7642
- const doc = parser.parseFromString(html, 'text/html');
7643
- doc.querySelectorAll('pre > code').forEach((codeEl) => {
7644
- var _a;
7645
- const preEl = codeEl.parentElement;
7646
- if (!preEl)
7647
- return;
7648
- const lang = (_a = Array.from(codeEl.classList)
7649
- .find((cls) => cls.startsWith('language-'))) === null || _a === void 0 ? void 0 : _a.replace('language-', '');
7650
- const code = codeEl.innerHTML;
7651
- let highlighted = '';
7652
- try {
7653
- const decoded = code
7654
- .replace(/&/g, '&')
7655
- .replace(/</g, '<')
7656
- .replace(/>/g, '>')
7657
- .replace(/"/g, '"')
7658
- .replace(/&#39;/g, "'");
7659
- highlighted = lang
7660
- ? hljs__default["default"].highlight(decoded, { language: lang }).value
7661
- : hljs__default["default"].highlightAuto(decoded).value;
7662
- }
7663
- catch (_b) {
7664
- highlighted = code;
7665
- }
7666
- codeEl.innerHTML = highlighted;
7667
- codeEl.classList.add('hljs');
7668
- if (lang)
7669
- codeEl.classList.add(`language-${lang}`);
7670
- preEl.classList.add('chat-code-block');
7671
- });
7672
- html = doc.body.innerHTML;
7673
7883
  }
7674
7884
  const sanitizedHtml = html
7675
7885
  .replace(/<\s*(script|style|iframe|object|embed)[^>]*>[\s\S]*?<\s*\/\s*\1\s*>/gi, '')
@@ -7699,9 +7909,50 @@
7699
7909
  * @public exported from `@promptbook/components`
7700
7910
  */
7701
7911
  function MarkdownContent(props) {
7702
- const { content, className } = props;
7912
+ const { content, className, onCreateAgent } = props;
7703
7913
  const htmlContent = react.useMemo(() => renderMarkdown(content), [content]);
7704
- return (jsxRuntime.jsx("div", { className: classNames(styles$5.MarkdownContent, className), dangerouslySetInnerHTML: {
7914
+ const containerRef = react.useRef(null);
7915
+ const rootsRef = react.useRef([]);
7916
+ react.useEffect(() => {
7917
+ // Cleanup previous roots
7918
+ rootsRef.current.forEach((root) => root.unmount());
7919
+ rootsRef.current = [];
7920
+ if (!containerRef.current) {
7921
+ return;
7922
+ }
7923
+ const preElements = containerRef.current.querySelectorAll('pre');
7924
+ preElements.forEach((pre) => {
7925
+ // Check if it is a code block (has code element)
7926
+ const codeElement = pre.querySelector('code');
7927
+ if (!codeElement) {
7928
+ return;
7929
+ }
7930
+ // Get language and code
7931
+ const className = codeElement.className; // e.g. language-python
7932
+ const match = className.match(/language-([^\s]+)/);
7933
+ const language = match ? match[1] : undefined;
7934
+ const code = codeElement.textContent || '';
7935
+ // Clear the pre element content
7936
+ pre.innerHTML = '';
7937
+ pre.className = ''; // remove existing classes if any
7938
+ pre.style.background = 'none'; // reset styles
7939
+ pre.style.padding = '0';
7940
+ pre.style.margin = '0';
7941
+ pre.style.overflow = 'visible';
7942
+ // Create a container for the CodeBlock
7943
+ const mountPoint = document.createElement('div');
7944
+ pre.appendChild(mountPoint);
7945
+ // Render CodeBlock
7946
+ const root = client.createRoot(mountPoint);
7947
+ root.render(jsxRuntime.jsx(CodeBlock, { code: code, language: language, onCreateAgent: onCreateAgent }));
7948
+ rootsRef.current.push(root);
7949
+ });
7950
+ return () => {
7951
+ rootsRef.current.forEach((root) => root.unmount());
7952
+ rootsRef.current = [];
7953
+ };
7954
+ }, [htmlContent, onCreateAgent]);
7955
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: classNames(styles$5.MarkdownContent, className), dangerouslySetInnerHTML: {
7705
7956
  __html: htmlContent,
7706
7957
  } }));
7707
7958
  }
@@ -7771,7 +8022,7 @@
7771
8022
  }
7772
8023
 
7773
8024
  /**
7774
- * @@@
8025
+ * Renders an about icon
7775
8026
  *
7776
8027
  * @private internal subcomponent used by various components
7777
8028
  */
@@ -7781,7 +8032,7 @@
7781
8032
  }
7782
8033
 
7783
8034
  /**
7784
- * @@@
8035
+ * Renders an attachment icon
7785
8036
  *
7786
8037
  * @public exported from `@promptbook/components`
7787
8038
  */
@@ -7790,7 +8041,7 @@
7790
8041
  }
7791
8042
 
7792
8043
  /**
7793
- * @@@
8044
+ * Renders a camera icon
7794
8045
  *
7795
8046
  * @public exported from `@promptbook/components`
7796
8047
  */
@@ -7799,7 +8050,7 @@
7799
8050
  }
7800
8051
 
7801
8052
  /**
7802
- * @@@
8053
+ * Renders a download icon
7803
8054
  *
7804
8055
  * @private internal subcomponent used by various components
7805
8056
  */
@@ -7893,7 +8144,7 @@
7893
8144
  styleInject(css_248z$5);
7894
8145
 
7895
8146
  /**
7896
- * @@@
8147
+ * An animated hamburger menu button component.
7897
8148
  *
7898
8149
  * @private Internal component
7899
8150
  */
@@ -7906,7 +8157,7 @@
7906
8157
  styleInject(css_248z$4);
7907
8158
 
7908
8159
  /**
7909
- * @@@
8160
+ * A dropdown menu component that displays a list of actions triggered by a hamburger menu button.
7910
8161
  *
7911
8162
  * @private internal subcomponent used by various components
7912
8163
  */
@@ -7918,6 +8169,16 @@
7918
8169
  }, children: [icon, jsxRuntime.jsx("span", { children: name })] }, name))) }))] }));
7919
8170
  }
7920
8171
 
8172
+ const MenuHoistingContext = react.createContext(null);
8173
+ /**
8174
+ * Hook to use the menu hoisting system
8175
+ *
8176
+ * @private mechanism inside Promptbook
8177
+ */
8178
+ function useMenuHoisting() {
8179
+ return react.useContext(MenuHoistingContext);
8180
+ }
8181
+
7921
8182
  /**
7922
8183
  *
7923
8184
  * @private Internal component used by `BookEditor`
@@ -7925,50 +8186,83 @@
7925
8186
  function BookEditorActionbar(props) {
7926
8187
  const { value, isDownloadButtonShown, isUploadButtonShown, isCameraButtonShown, isAboutButtonShown, isFullscreenButtonShown, onFullscreenClick, onUploadDocument, onTakePhoto, isFullscreen, } = props;
7927
8188
  const [isAboutModalOpen, setIsAboutModalOpen] = react.useState(false);
7928
- const handleDownload = () => {
7929
- const book = validateBook(value || DEFAULT_BOOK);
8189
+ const menuHoisting = useMenuHoisting();
8190
+ // Note: [1] We use ref to avoid re-creating the handleDownload function (and thus the actions array) on every value change
8191
+ const valueRef = react.useRef(value);
8192
+ react.useEffect(() => {
8193
+ valueRef.current = value;
8194
+ }, [value]);
8195
+ const handleDownload = react.useCallback(() => {
8196
+ const book = validateBook(valueRef.current || DEFAULT_BOOK);
7930
8197
  /* not await */ $induceBookDownload(book);
7931
- };
7932
- const actions = [];
7933
- if (isUploadButtonShown && onUploadDocument) {
7934
- actions.push({
7935
- icon: jsxRuntime.jsx(AttachmentIcon, {}),
7936
- name: 'Upload document',
7937
- onClick: onUploadDocument,
7938
- });
7939
- }
7940
- if (isCameraButtonShown && onTakePhoto) {
7941
- actions.push({
7942
- icon: jsxRuntime.jsx(CameraIcon, {}),
7943
- name: 'Take photo',
7944
- onClick: onTakePhoto,
7945
- });
7946
- }
7947
- if (isDownloadButtonShown) {
7948
- actions.push({
7949
- icon: jsxRuntime.jsx(DownloadIcon, {}),
7950
- name: 'Download',
7951
- onClick: handleDownload,
7952
- });
7953
- }
7954
- if (isAboutButtonShown) {
7955
- actions.push({
7956
- icon: jsxRuntime.jsx(AboutIcon, {}),
7957
- name: 'About',
7958
- onClick: () => setIsAboutModalOpen(true),
7959
- });
7960
- }
7961
- if (isFullscreenButtonShown && onFullscreenClick) {
7962
- actions.push({
7963
- icon: jsxRuntime.jsx(FullscreenIcon, {}),
7964
- name: 'Fullscreen',
7965
- onClick: onFullscreenClick,
7966
- });
7967
- }
8198
+ }, []);
8199
+ const actions = react.useMemo(() => {
8200
+ const _actions = [];
8201
+ if (isUploadButtonShown && onUploadDocument) {
8202
+ _actions.push({
8203
+ icon: jsxRuntime.jsx(AttachmentIcon, {}),
8204
+ name: 'Upload document',
8205
+ onClick: onUploadDocument,
8206
+ });
8207
+ }
8208
+ if (isCameraButtonShown && onTakePhoto) {
8209
+ _actions.push({
8210
+ icon: jsxRuntime.jsx(CameraIcon, {}),
8211
+ name: 'Take photo',
8212
+ onClick: onTakePhoto,
8213
+ });
8214
+ }
8215
+ if (isDownloadButtonShown) {
8216
+ _actions.push({
8217
+ icon: jsxRuntime.jsx(DownloadIcon, {}),
8218
+ name: 'Download',
8219
+ onClick: handleDownload,
8220
+ });
8221
+ }
8222
+ if (isAboutButtonShown) {
8223
+ _actions.push({
8224
+ icon: jsxRuntime.jsx(AboutIcon, {}),
8225
+ name: 'About',
8226
+ onClick: () => setIsAboutModalOpen(true),
8227
+ });
8228
+ }
8229
+ if (isFullscreenButtonShown && onFullscreenClick) {
8230
+ _actions.push({
8231
+ icon: jsxRuntime.jsx(FullscreenIcon, {}),
8232
+ name: 'Fullscreen',
8233
+ onClick: onFullscreenClick,
8234
+ });
8235
+ }
8236
+ return _actions;
8237
+ }, [
8238
+ isUploadButtonShown,
8239
+ onUploadDocument,
8240
+ isCameraButtonShown,
8241
+ onTakePhoto,
8242
+ isDownloadButtonShown,
8243
+ handleDownload,
8244
+ isAboutButtonShown,
8245
+ isFullscreenButtonShown,
8246
+ onFullscreenClick,
8247
+ ]);
8248
+ react.useEffect(() => {
8249
+ if (!menuHoisting || isFullscreen) {
8250
+ return;
8251
+ }
8252
+ menuHoisting.setMenu(actions);
8253
+ return () => {
8254
+ menuHoisting.setMenu([]);
8255
+ };
8256
+ }, [menuHoisting, actions, isFullscreen]);
7968
8257
  if (isFullscreen) {
7969
- return (jsxRuntime.jsx("div", { className: styles$6.bookEditorActionbar, children: jsxRuntime.jsx("button", { className: styles$6.button, onClick: onFullscreenClick, children: jsxRuntime.jsx(ExitFullscreenIcon, {}) }) }));
8258
+ return (jsxRuntime.jsx("div", { className: styles$7.bookEditorActionbar, children: jsxRuntime.jsx("button", { className: styles$7.button, onClick: onFullscreenClick, children: jsxRuntime.jsx(ExitFullscreenIcon, {}) }) }));
7970
8259
  }
7971
- return (jsxRuntime.jsxs("div", { className: styles$6.bookEditorActionbar, children: [actions.length >= 2 ? (jsxRuntime.jsx(Dropdown, { actions: actions })) : (actions.map(({ icon, name, onClick }) => (jsxRuntime.jsx("button", { className: styles$6.button, onClick: onClick, children: icon }, name)))), isAboutModalOpen && (jsxRuntime.jsx(Modal, { onClose: () => {
8260
+ if (menuHoisting && !isFullscreen) {
8261
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: isAboutModalOpen && (jsxRuntime.jsx(Modal, { onClose: () => {
8262
+ setIsAboutModalOpen(false);
8263
+ }, children: jsxRuntime.jsx(AboutPromptbookInformation, {}) })) }));
8264
+ }
8265
+ return (jsxRuntime.jsxs("div", { className: styles$7.bookEditorActionbar, children: [actions.length >= 2 ? (jsxRuntime.jsx(Dropdown, { actions: actions })) : (actions.map(({ icon, name, onClick }) => (jsxRuntime.jsx("button", { className: styles$7.button, onClick: onClick, children: icon }, name)))), isAboutModalOpen && (jsxRuntime.jsx(Modal, { onClose: () => {
7972
8266
  setIsAboutModalOpen(false);
7973
8267
  }, children: jsxRuntime.jsx(AboutPromptbookInformation, {}) }))] }));
7974
8268
  }
@@ -8080,6 +8374,7 @@
8080
8374
  const parameterRegex = /@([a-zA-Z0-9_รก-ลพร-ลฝฤ-ล™ฤŒ-ล˜ลก-ลพล -ลฝะฐ-ัะ-ะฏั‘ะ]+)/;
8081
8375
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8082
8376
  const bookRules = [
8377
+ [/^---[-]*$/, ''],
8083
8378
  [parameterRegex, 'parameter'],
8084
8379
  [/\{[^}]+\}/, 'parameter'],
8085
8380
  [commitmentRegex, 'commitment'],
@@ -8088,7 +8383,12 @@
8088
8383
  const tokenProvider = monaco.languages.setMonarchTokensProvider(BOOK_LANGUAGE_ID, {
8089
8384
  ignoreCase: true,
8090
8385
  tokenizer: {
8091
- root: [[/^.*$/, 'title', '@body']],
8386
+ root: [
8387
+ [/^\s*$/, 'empty'],
8388
+ [/^-*$/, 'line'],
8389
+ [/^.*$/, 'title', '@body'],
8390
+ [commitmentRegex, 'commitment'],
8391
+ ],
8092
8392
  body: bookRules,
8093
8393
  },
8094
8394
  });
@@ -8306,7 +8606,7 @@
8306
8606
  event.preventDefault();
8307
8607
  setIsDragOver(false);
8308
8608
  }, []);
8309
- return (jsxRuntime.jsxs("div", { className: classNames(styles$6.bookEditorContainer, instanceClass), onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [(isUploadButtonShown ||
8609
+ return (jsxRuntime.jsxs("div", { className: classNames(styles$7.bookEditorContainer, instanceClass), onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [(isUploadButtonShown ||
8310
8610
  isCameraButtonShown ||
8311
8611
  isDownloadButtonShown ||
8312
8612
  isAboutButtonShown ||
@@ -8319,7 +8619,7 @@
8319
8619
  onFullscreenClick,
8320
8620
  onUploadDocument: handleUploadDocument,
8321
8621
  onTakePhoto: handleTakePhoto,
8322
- isFullscreen })), jsxRuntime.jsx("input", { type: "file", ref: fileUploadInputRef, style: { display: 'none' }, onChange: handleFileInputChange, multiple: true }), jsxRuntime.jsx("input", { type: "file", ref: cameraInputRef, style: { display: 'none' }, accept: "image/*", capture: "environment", onChange: handleFileInputChange }), isDragOver && jsxRuntime.jsx("div", { className: styles$6.dropOverlay, children: "Drop files to upload" }), jsxRuntime.jsxs("div", { style: {
8622
+ isFullscreen })), jsxRuntime.jsx("input", { type: "file", ref: fileUploadInputRef, style: { display: 'none' }, onChange: handleFileInputChange, multiple: true }), jsxRuntime.jsx("input", { type: "file", ref: cameraInputRef, style: { display: 'none' }, accept: "image/*", capture: "environment", onChange: handleFileInputChange }), isDragOver && jsxRuntime.jsx("div", { className: styles$7.dropOverlay, children: "Drop files to upload" }), jsxRuntime.jsxs("div", { style: {
8323
8623
  position: 'relative',
8324
8624
  flex: 1,
8325
8625
  height: '100%',
@@ -8384,7 +8684,7 @@
8384
8684
  arrowSize: 0,
8385
8685
  useShadows: false,
8386
8686
  },
8387
- }, loading: jsxRuntime.jsx("div", { className: styles$6.loading, children: "\uD83D\uDCD6" }) })] })] }));
8687
+ }, loading: jsxRuntime.jsx("div", { className: styles$7.loading, children: "\uD83D\uDCD6" }) })] })] }));
8388
8688
  }
8389
8689
 
8390
8690
  /**
@@ -8406,7 +8706,7 @@
8406
8706
  const handleFullscreenToggle = () => {
8407
8707
  setIsFullscreen(!isFullscreen);
8408
8708
  };
8409
- const editorContent = (jsxRuntime.jsx("div", { "data-book-component": "BookEditor", className: classNames(styles$6.BookEditor, isVerbose && styles$6.isVerbose, styles$6.bookEditorWrapper, isBorderRadiusDisabled && styles$6.isBorderRadiusDisabled, isFullscreen && styles$6.fullscreen, className), style: isFullscreen
8709
+ const editorContent = (jsxRuntime.jsx("div", { "data-book-component": "BookEditor", className: classNames(styles$7.BookEditor, isVerbose && styles$7.isVerbose, styles$7.bookEditorWrapper, isBorderRadiusDisabled && styles$7.isBorderRadiusDisabled, isFullscreen && styles$7.fullscreen, className), style: isFullscreen
8410
8710
  ? style
8411
8711
  : {
8412
8712
  ...(style || {}),
@@ -8532,6 +8832,52 @@
8532
8832
  */
8533
8833
  const textColor = furthest(Color.get('white'), Color.from('black'));
8534
8834
 
8835
+ /**
8836
+ * Makes data url from color
8837
+ *
8838
+ * @public exported from `@promptbook/color`
8839
+ */
8840
+ function colorToDataUrl(color) {
8841
+ if (typeof color === 'string') {
8842
+ color = Color.fromHex(color);
8843
+ }
8844
+ return rgbDataURL(color.red, color.green, color.blue);
8845
+ }
8846
+ /**
8847
+ * Pixel GIF code adapted from https://stackoverflow.com/a/33919020/266535
8848
+ *
8849
+ * @private util of `colorToDataUrl`
8850
+ */
8851
+ const keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
8852
+ /**
8853
+ * Generates a base64-encoded triplet string
8854
+ *
8855
+ * @param e1 - The first element in the triplet.
8856
+ * @param e2 - The second element in the triplet.
8857
+ * @param e3 - The third element in the triplet.
8858
+ * @returns The base64-encoded triplet string.
8859
+ *
8860
+ * @private util of `colorToDataUrl`
8861
+ */
8862
+ const triplet = (e1, e2, e3) => keyStr.charAt(e1 >> 2) +
8863
+ keyStr.charAt(((e1 & 3) << 4) | (e2 >> 4)) +
8864
+ keyStr.charAt(((e2 & 15) << 2) | (e3 >> 6)) +
8865
+ keyStr.charAt(e3 & 63);
8866
+ /**
8867
+ * Converts RGB values to a data URL string
8868
+ *
8869
+ * @param r - The red channel value.
8870
+ * @param g - The green channel value.
8871
+ * @param b - The blue channel value.
8872
+ * @returns The RGB data URL string.
8873
+ *
8874
+ * @private util of `colorToDataUrl`
8875
+ */
8876
+ const rgbDataURL = (r, g, b) => `data:image/gif;base64,R0lGODlhAQABAPAA${triplet(0, r, g) + triplet(b, 255, 255)}/yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==`;
8877
+ /**
8878
+ * TODO: Make as functions NOT const
8879
+ */
8880
+
8535
8881
  /**
8536
8882
  * Restricts an Updatable to a (2) BehaviorSubject variant
8537
8883
  *
@@ -8734,7 +9080,7 @@
8734
9080
  const ResetIcon = () => (jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsxRuntime.jsx("path", { d: "M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4L17.65,6.35z" }) }));
8735
9081
 
8736
9082
  /**
8737
- * @@@
9083
+ * Renders a save icon
8738
9084
  *
8739
9085
  * @public exported from `@promptbook/components`
8740
9086
  */
@@ -9014,15 +9360,15 @@
9014
9360
  ASSISTANT: '#ffb300',
9015
9361
  SYSTEM: '#888',
9016
9362
  };
9017
- const bgColor = participantColors[String(message.from)] || '#2b7cff';
9363
+ const bgColor = participantColors[String(message.sender)] || '#2b7cff';
9018
9364
  const textColor = getTextColor(bgColor);
9019
9365
  return spaceTrim__default["default"](`
9020
9366
  <div class="chat-message">
9021
9367
  <div class="avatar" style="background:${bgColor};color:${getTextColor(bgColor)};">
9022
- ${String(message.from)[0] || '?'}
9368
+ ${String(message.sender)[0] || '?'}
9023
9369
  </div>
9024
9370
  <div class="bubble" style="background:${bgColor};color:${textColor};">
9025
- <span class="from-label">${String(message.from)}:</span>
9371
+ <span class="from-label">${String(message.sender)}:</span>
9026
9372
  ${message.content}
9027
9373
  </div>
9028
9374
  </div>
@@ -9068,7 +9414,7 @@
9068
9414
  getContent: ({ messages }) => spaceTrim$1.spaceTrim(`
9069
9415
  ${messages
9070
9416
  .map((message) => spaceTrim$1.spaceTrim(`
9071
- **${message.from}:**
9417
+ **${message.sender}:**
9072
9418
 
9073
9419
  > ${message.content.replace(/\n/g, '\n> ')}
9074
9420
  `))
@@ -9258,8 +9604,8 @@
9258
9604
  *
9259
9605
  * @private internal subcomponent of `<Chat>` component
9260
9606
  */
9261
- const ChatMessageItem = react.memo(({ message, participant, participants, isLastMessage, onMessage, setExpandedMessageId, isExpanded, currentRating, handleRating, mode, isCopyButtonEnabled, isFeedbackEnabled, onCopy, }) => {
9262
- const avatarSrc = (participant === null || participant === void 0 ? void 0 : participant.avatarSrc) || '';
9607
+ const ChatMessageItem = react.memo(({ message, participant, participants, isLastMessage, onMessage, setExpandedMessageId, isExpanded, currentRating, handleRating, mode, isCopyButtonEnabled, isFeedbackEnabled, onCopy, onCreateAgent, }) => {
9608
+ const avatarSrc = (participant === null || participant === void 0 ? void 0 : participant.avatarSrc) || null;
9263
9609
  const [isAvatarTooltipVisible, setIsAvatarTooltipVisible] = react.useState(false);
9264
9610
  const [avatarTooltipPosition, setAvatarTooltipPosition] = react.useState(null);
9265
9611
  const hoverTimeoutRef = react.useRef(null);
@@ -9350,9 +9696,14 @@
9350
9696
  console.info('participant avatarSrc', avatarSrc);
9351
9697
  console.info('participant color', { color, colorOfText });
9352
9698
  console.groupEnd();
9353
- }, children: [avatarSrc && (jsxRuntime.jsxs("div", { ref: avatarRef, className: chatStyles.avatar, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: showTooltip, children: [jsxRuntime.jsx("img", { width: AVATAR_SIZE, src: avatarSrc, alt: `Avatar of ${message.from.toString().toLocaleLowerCase()}`, style: {
9699
+ }, children: [avatarSrc && (jsxRuntime.jsxs("div", { ref: avatarRef, className: chatStyles.avatar, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: showTooltip, children: [jsxRuntime.jsx("img", { width: AVATAR_SIZE, src: avatarSrc, alt: `Avatar of ${message.sender.toString().toLocaleLowerCase()}`, style: {
9354
9700
  '--avatar-bg-color': color.toHex(),
9701
+ objectFit: 'cover',
9702
+ objectPosition: '50% 20%',
9355
9703
  width: AVATAR_SIZE,
9704
+ height: AVATAR_SIZE,
9705
+ aspectRatio: '1 / 1',
9706
+ backgroundImage: `url(${colorToDataUrl(color)})`,
9356
9707
  } }), isAvatarTooltipVisible && (participant === null || participant === void 0 ? void 0 : participant.agentSource) && avatarTooltipPosition && (jsxRuntime.jsx(AvatarProfileTooltip, { ref: tooltipRef, agentSource: participant.agentSource, position: avatarTooltipPosition }))] })), jsxRuntime.jsxs("div", { className: chatStyles.messageText, style: {
9357
9708
  '--message-bg-color': color.toHex(),
9358
9709
  '--message-text-color': colorOfText.toHex(),
@@ -9401,7 +9752,7 @@
9401
9752
  ? ' ' + chatStyles.copiedTooltipLeft
9402
9753
  : tooltipAlign === 'right'
9403
9754
  ? ' ' + chatStyles.copiedTooltipRight
9404
- : ''), children: "Copied!" }))] }) })), message.isVoiceCall && (jsxRuntime.jsx("div", { className: chatStyles.voiceCallIndicator, children: jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsxRuntime.jsx("path", { d: "M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" }) }) })), message.content === LOADING_INTERACTIVE_IMAGE ? (jsxRuntime.jsx(jsxRuntime.Fragment, {})) : (jsxRuntime.jsx("div", { ref: contentWithoutButtonsRef, children: jsxRuntime.jsx(MarkdownContent, { content: contentWithoutButtons }) })), !message.isComplete && jsxRuntime.jsx("span", { className: chatStyles.NonCompleteMessageFiller, children: '_'.repeat(70) }), shouldShowButtons && (jsxRuntime.jsx("div", { className: chatStyles.messageButtons, children: buttons.map((button, buttonIndex) => (jsxRuntime.jsx("button", { className: chatStyles.messageButton, onClick: (event) => {
9755
+ : ''), children: "Copied!" }))] }) })), message.isVoiceCall && (jsxRuntime.jsx("div", { className: chatStyles.voiceCallIndicator, children: jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsxRuntime.jsx("path", { d: "M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" }) }) })), message.content === LOADING_INTERACTIVE_IMAGE ? (jsxRuntime.jsx(jsxRuntime.Fragment, {})) : (jsxRuntime.jsx("div", { ref: contentWithoutButtonsRef, children: jsxRuntime.jsx(MarkdownContent, { content: contentWithoutButtons, onCreateAgent: onCreateAgent }) })), !message.isComplete && jsxRuntime.jsx("span", { className: chatStyles.NonCompleteMessageFiller, children: '_'.repeat(70) }), shouldShowButtons && (jsxRuntime.jsx("div", { className: chatStyles.messageButtons, children: buttons.map((button, buttonIndex) => (jsxRuntime.jsx("button", { className: chatStyles.messageButton, onClick: (event) => {
9405
9756
  event.stopPropagation();
9406
9757
  if (onMessage) {
9407
9758
  onMessage(button.message);
@@ -9484,7 +9835,7 @@
9484
9835
  // isExperimental = false,
9485
9836
  // TODO: [๐Ÿ˜…]> isSaveButtonEnabled = false,
9486
9837
  // exportHeaderMarkdown,
9487
- participants = [], extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, } = props;
9838
+ participants = [], extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, onCreateAgent, } = props;
9488
9839
  const buttonColor = react.useMemo(() => Color.from(buttonColorRaw || '#0066cc'), [buttonColorRaw]);
9489
9840
  // Use the auto-scroll hook
9490
9841
  const { isAutoScrolling, chatMessagesRef, handleScroll, handleMessagesChange, scrollToBottom, isMobile: isMobileFromHook, } = useChatAutoScroll();
@@ -9699,7 +10050,7 @@
9699
10050
  }
9700
10051
  }, [ratingModalOpen, isMobile]);
9701
10052
  // Determine alignment for actions (Reset button) based on the first message
9702
- const firstMessageFromUser = ((_a = messages[0]) === null || _a === void 0 ? void 0 : _a.from) === 'USER';
10053
+ const firstMessageFromUser = ((_a = messages[0]) === null || _a === void 0 ? void 0 : _a.sender) === 'USER';
9703
10054
  const actionsAlignmentClass = firstMessageFromUser
9704
10055
  ? chatStyles.actions + ' ' + chatStyles.left
9705
10056
  : chatStyles.actions + ' ' + chatStyles.right;
@@ -9776,11 +10127,11 @@
9776
10127
  }
9777
10128
  return true;
9778
10129
  })() && chatStyles.hasActionsAndFirstMessageIsLong), ref: chatMessagesRef, onScroll: handleScroll, children: [postprocessedMessages.map((message, i) => {
9779
- const participant = participants.find((participant) => participant.name === message.from);
10130
+ const participant = participants.find((participant) => participant.name === message.sender);
9780
10131
  const isLastMessage = i === postprocessedMessages.length - 1;
9781
10132
  const isExpanded = expandedMessageId === message.id;
9782
10133
  const currentRating = messageRatings.get(message.id || message.content /* <-[๐Ÿ’ƒ] */) || 0;
9783
- return (jsxRuntime.jsx(ChatMessageItem, { message: message, participant: participant, participants: participants, isLastMessage: isLastMessage, onMessage: onMessage, setExpandedMessageId: setExpandedMessageId, isExpanded: isExpanded, currentRating: currentRating, handleRating: handleRating, mode: mode, isCopyButtonEnabled: isCopyButtonEnabled, isFeedbackEnabled: isFeedbackEnabled, onCopy: handleCopy }, message.id));
10134
+ return (jsxRuntime.jsx(ChatMessageItem, { message: message, participant: participant, participants: participants, isLastMessage: isLastMessage, onMessage: onMessage, setExpandedMessageId: setExpandedMessageId, isExpanded: isExpanded, currentRating: currentRating, handleRating: handleRating, mode: mode, isCopyButtonEnabled: isCopyButtonEnabled, isFeedbackEnabled: isFeedbackEnabled, onCopy: handleCopy, onCreateAgent: onCreateAgent }, message.id));
9784
10135
  }), jsxRuntime.jsx("div", {
9785
10136
  // Note: Extra space at bottom for input area
9786
10137
  style: { height: 100 } })] }), onMessage && (jsxRuntime.jsxs("div", { className: classNames(chatStyles.chatInput, useChatCssClassName('chatInput'), isDragOver && chatStyles.dragOver), ...(onFileUpload
@@ -9868,13 +10219,13 @@
9868
10219
  const idx = postprocessedMessages.findIndex((m) => m.id === selectedMessage.id);
9869
10220
  if (idx > 0) {
9870
10221
  const prev = postprocessedMessages[idx - 1];
9871
- if (prev.from === 'USER') {
10222
+ if (prev.sender === 'USER') {
9872
10223
  return prev.content;
9873
10224
  }
9874
10225
  }
9875
10226
  // fallback: find last USER message before selectedMessage
9876
10227
  for (let i = messages.findIndex((m) => m.id === selectedMessage.id) - 1; i >= 0; i--) {
9877
- if (messages[i].from === 'USER') {
10228
+ if (messages[i].sender === 'USER') {
9878
10229
  return messages[i].content;
9879
10230
  }
9880
10231
  }
@@ -9901,7 +10252,9 @@
9901
10252
  try {
9902
10253
  const serializableMessages = messages.map((message) => ({
9903
10254
  ...message,
9904
- date: (message.date || new Date()).toISOString(),
10255
+ createdAt: (typeof message.createdAt === 'string'
10256
+ ? new Date(message.createdAt)
10257
+ : message.createdAt || new Date()).toISOString(),
9905
10258
  }));
9906
10259
  const storageKey = this.STORAGE_PREFIX + persistenceKey;
9907
10260
  localStorage.setItem(storageKey, JSON.stringify(serializableMessages));
@@ -9924,7 +10277,7 @@
9924
10277
  // Convert date strings back to Date objects
9925
10278
  return serializableMessages.map((message) => ({
9926
10279
  ...message,
9927
- date: new Date(message.date),
10280
+ createdAt: new Date(message.createdAt),
9928
10281
  }));
9929
10282
  }
9930
10283
  catch (error) {
@@ -9977,7 +10330,7 @@
9977
10330
  const { llmTools, persistenceKey, onChange, onReset, initialMessages, sendMessage, userParticipantName = 'USER', llmParticipantName = 'ASSISTANT', autoExecuteMessage, buttonColor, ...restProps } = props;
9978
10331
  // Internal state management
9979
10332
  // DRY: Single factory for seeding initial messages (used on mount and after reset)
9980
- const buildInitialMessages = react.useCallback(() => (initialMessages ? [...initialMessages] : []), [initialMessages]);
10333
+ const buildInitialMessages = react.useCallback(() => initialMessages ? ([...initialMessages]) : ([]), [initialMessages]);
9981
10334
  const [messages, setMessages] = react.useState(() => buildInitialMessages());
9982
10335
  const [tasksProgress, setTasksProgress] = react.useState([]);
9983
10336
  const [isVoiceCalling, setIsVoiceCalling] = react.useState(false);
@@ -10070,17 +10423,19 @@
10070
10423
  setTasksProgress([{ id: taskId, name: 'Playing response...', progress: 100 }]);
10071
10424
  const now = Date.now();
10072
10425
  const userMessage = {
10426
+ // channel: 'PROMPTBOOK_CHAT',
10073
10427
  id: `user_${now}`,
10074
- date: new Date(),
10075
- from: userParticipantName,
10428
+ createdAt: new Date(),
10429
+ sender: userParticipantName,
10076
10430
  content: (result.userMessage || '(Voice message)'),
10077
10431
  isComplete: true,
10078
10432
  isVoiceCall: true,
10079
10433
  };
10080
10434
  const agentMessage = {
10435
+ // channel: 'PROMPTBOOK_CHAT',
10081
10436
  id: `agent_${now}`,
10082
- date: new Date(),
10083
- from: llmParticipantName,
10437
+ createdAt: new Date(),
10438
+ sender: llmParticipantName,
10084
10439
  content: (result.agentMessage || result.text),
10085
10440
  isComplete: true,
10086
10441
  isVoiceCall: true,
@@ -10177,9 +10532,10 @@
10177
10532
  hasUserInteractedRef.current = true;
10178
10533
  // Add user message
10179
10534
  const userMessage = {
10535
+ // channel: 'PROMPTBOOK_CHAT',
10180
10536
  id: `user_${Date.now()}`,
10181
- date: new Date(),
10182
- from: userParticipantName,
10537
+ createdAt: new Date(),
10538
+ sender: userParticipantName,
10183
10539
  content: messageContent,
10184
10540
  isComplete: true,
10185
10541
  };
@@ -10191,9 +10547,10 @@
10191
10547
  }
10192
10548
  // Add loading message for assistant
10193
10549
  const loadingMessage = {
10550
+ // channel: 'PROMPTBOOK_CHAT',
10194
10551
  id: `assistant_${Date.now()}`,
10195
- date: new Date(),
10196
- from: llmParticipantName,
10552
+ createdAt: new Date(),
10553
+ sender: llmParticipantName,
10197
10554
  content: 'Thinking...',
10198
10555
  isComplete: false,
10199
10556
  };
@@ -10224,9 +10581,10 @@
10224
10581
  if (llmTools.callChatModelStream) {
10225
10582
  result = await llmTools.callChatModelStream(prompt, (chunk) => {
10226
10583
  const assistantMessage = {
10584
+ // channel: 'PROMPTBOOK_CHAT',
10227
10585
  id: loadingMessage.id,
10228
- date: new Date(),
10229
- from: llmParticipantName,
10586
+ createdAt: new Date(),
10587
+ sender: llmParticipantName,
10230
10588
  content: chunk.content,
10231
10589
  isComplete: false,
10232
10590
  };
@@ -10247,9 +10605,10 @@
10247
10605
  setTasksProgress([{ id: taskId, name: 'Response generated', progress: 100 }]);
10248
10606
  // Replace loading message with actual response
10249
10607
  const assistantMessage = {
10608
+ // channel: 'PROMPTBOOK_CHAT',
10250
10609
  id: loadingMessage.id,
10251
- date: new Date(),
10252
- from: llmParticipantName,
10610
+ createdAt: new Date(),
10611
+ sender: llmParticipantName,
10253
10612
  content: result.content,
10254
10613
  isComplete: true,
10255
10614
  };
@@ -10268,9 +10627,10 @@
10268
10627
  console.error('Error calling LLM:', error);
10269
10628
  // Replace loading message with error message
10270
10629
  const errorMessage = {
10630
+ // channel: 'PROMPTBOOK_CHAT',
10271
10631
  id: loadingMessage.id,
10272
- date: new Date(),
10273
- from: llmParticipantName,
10632
+ createdAt: new Date(),
10633
+ sender: llmParticipantName,
10274
10634
  content: `Sorry, I encountered an error: ${error instanceof Error ? error.message : 'Unknown error'}`,
10275
10635
  isComplete: true,
10276
10636
  };
@@ -10337,7 +10697,8 @@
10337
10697
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(LlmChat, { title: title || `Chat with ${agent.meta.fullname || agent.agentName || 'Agent'}`, persistenceKey: persistenceKey || `agent-chat-${agent.agentName}`, userParticipantName: "USER", llmParticipantName: "AGENT" // <- TODO: [๐Ÿง ] Maybe dynamic agent id
10338
10698
  , initialMessages: [
10339
10699
  {
10340
- from: 'AGENT',
10700
+ // channel: 'PROMPTBOOK_CHAT',
10701
+ sender: 'AGENT',
10341
10702
  content: agent.initialMessage ||
10342
10703
  spaceTrim__default["default"](`
10343
10704
 
@@ -10615,7 +10976,7 @@
10615
10976
  if (delays.longPauseChance &&
10616
10977
  Math.random() < delays.longPauseChance &&
10617
10978
  i > 0 &&
10618
- originalMessages[i].from !== originalMessages[i - 1].from) {
10979
+ originalMessages[i].sender !== originalMessages[i - 1].sender) {
10619
10980
  await waitasecond.forTime(getDelay(delays.longPauseDuration, 2000));
10620
10981
  didLongPause = true;
10621
10982
  if (isCancelled)
@@ -10636,9 +10997,10 @@
10636
10997
  }
10637
10998
  // Show incomplete message first (for typing effect)
10638
10999
  const incompleteMessage = {
11000
+ // channel: 'PROMPTBOOK_CHAT',
10639
11001
  id: currentMessage.id,
10640
- date: currentMessage.date,
10641
- from: currentMessage.from,
11002
+ createdAt: currentMessage.createdAt,
11003
+ sender: currentMessage.sender,
10642
11004
  content: '',
10643
11005
  isComplete: false,
10644
11006
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10656,9 +11018,10 @@
10656
11018
  currentContent += (wordIndex > 0 ? ' ' : '') + word;
10657
11019
  // Update the message with current content
10658
11020
  const updatingMessage = {
11021
+ // channel: 'PROMPTBOOK_CHAT',
10659
11022
  id: currentMessage.id,
10660
- date: currentMessage.date,
10661
- from: currentMessage.from,
11023
+ createdAt: currentMessage.createdAt,
11024
+ sender: currentMessage.sender,
10662
11025
  content: currentContent,
10663
11026
  isComplete: false,
10664
11027
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10676,9 +11039,10 @@
10676
11039
  }
10677
11040
  // Mark message as complete
10678
11041
  const completeMessage = {
11042
+ // channel: 'PROMPTBOOK_CHAT',
10679
11043
  id: currentMessage.id,
10680
- date: currentMessage.date,
10681
- from: currentMessage.from,
11044
+ createdAt: currentMessage.createdAt,
11045
+ sender: currentMessage.sender,
10682
11046
  content: currentMessage.content,
10683
11047
  isComplete: true,
10684
11048
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10930,6 +11294,12 @@
10930
11294
  callEmbeddingModel(prompt) {
10931
11295
  return this.callCommonModel(prompt);
10932
11296
  }
11297
+ /**
11298
+ * Calls the best available embedding model
11299
+ */
11300
+ callImageGenerationModel(prompt) {
11301
+ return this.callCommonModel(prompt);
11302
+ }
10933
11303
  // <- Note: [๐Ÿค–]
10934
11304
  /**
10935
11305
  * Calls the best available model
@@ -10956,6 +11326,11 @@
10956
11326
  continue llm;
10957
11327
  }
10958
11328
  return await llmExecutionTools.callEmbeddingModel(prompt);
11329
+ case 'IMAGE_GENERATION':
11330
+ if (llmExecutionTools.callImageGenerationModel === undefined) {
11331
+ continue llm;
11332
+ }
11333
+ return await llmExecutionTools.callImageGenerationModel(prompt);
10959
11334
  // <- case [๐Ÿค–]:
10960
11335
  default:
10961
11336
  throw new UnexpectedError(`Unknown model variant "${prompt.modelRequirements.modelVariant}" in ${llmExecutionTools.title}`);
@@ -12130,6 +12505,15 @@
12130
12505
  return promptResult;
12131
12506
  };
12132
12507
  }
12508
+ if (llmTools.callImageGenerationModel !== undefined) {
12509
+ proxyTools.callImageGenerationModel = async (prompt) => {
12510
+ // console.info('[๐Ÿš•] callImageGenerationModel through countTotalUsage');
12511
+ const promptResult = await llmTools.callImageGenerationModel(prompt);
12512
+ totalUsage = addUsage(totalUsage, promptResult.usage);
12513
+ spending.next(promptResult.usage);
12514
+ return promptResult;
12515
+ };
12516
+ }
12133
12517
  // <- Note: [๐Ÿค–]
12134
12518
  return proxyTools;
12135
12519
  }
@@ -12138,7 +12522,7 @@
12138
12522
  * TODO: [๐Ÿง ] Is there some meaningfull way how to test this util
12139
12523
  * TODO: [๐Ÿง ][๐ŸŒฏ] Maybe a way how to hide ability to `get totalUsage`
12140
12524
  * > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
12141
- * TODO: [๐Ÿ‘ทโ€โ™‚๏ธ] @@@ Manual about construction of llmTools
12525
+ * TODO: [๐Ÿ‘ทโ€โ™‚๏ธ] Write a comprehensive manual explaining the construction and usage of LLM tools in the Promptbook ecosystem
12142
12526
  */
12143
12527
 
12144
12528
  /**
@@ -13673,8 +14057,9 @@
13673
14057
  $ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
13674
14058
  break variant;
13675
14059
  case 'EMBEDDING':
14060
+ case 'IMAGE_GENERATION':
13676
14061
  throw new PipelineExecutionError(spaceTrim$1.spaceTrim((block) => `
13677
- Embedding model can not be used in pipeline
14062
+ ${modelRequirements.modelVariant} model can not be used in pipeline
13678
14063
 
13679
14064
  This should be catched during parsing
13680
14065
 
@@ -14990,7 +15375,12 @@
14990
15375
  };
14991
15376
  }
14992
15377
  // Apply each commitment in order using reduce-like pattern
14993
- for (const commitment of filteredCommitments) {
15378
+ for (let i = 0; i < filteredCommitments.length; i++) {
15379
+ const commitment = filteredCommitments[i];
15380
+ // CLOSED commitment should work only if its the last commitment in the book
15381
+ if (commitment.type === 'CLOSED' && i !== filteredCommitments.length - 1) {
15382
+ continue;
15383
+ }
14994
15384
  const definition = getCommitmentDefinition(commitment.type);
14995
15385
  if (definition) {
14996
15386
  try {
@@ -16005,7 +16395,7 @@
16005
16395
  let threadMessages = [];
16006
16396
  if ('thread' in prompt && Array.isArray(prompt.thread)) {
16007
16397
  threadMessages = prompt.thread.map((msg) => ({
16008
- role: msg.role === 'assistant' ? 'assistant' : 'user',
16398
+ role: msg.sender === 'assistant' ? 'assistant' : 'user',
16009
16399
  content: msg.content,
16010
16400
  }));
16011
16401
  }
@@ -16418,13 +16808,14 @@
16418
16808
  const modelName = currentModelRequirements.modelName || this.getDefaultImageGenerationModel().modelName;
16419
16809
  const modelSettings = {
16420
16810
  model: modelName,
16421
- // size: currentModelRequirements.size,
16422
- // quality: currentModelRequirements.quality,
16423
- // style: currentModelRequirements.style,
16811
+ size: currentModelRequirements.size,
16812
+ quality: currentModelRequirements.quality,
16813
+ style: currentModelRequirements.style,
16424
16814
  };
16425
16815
  const rawPromptContent = templateParameters(content, { ...parameters, modelName });
16426
16816
  const rawRequest = {
16427
16817
  ...modelSettings,
16818
+ size: modelSettings.size || '1024x1024',
16428
16819
  prompt: rawPromptContent,
16429
16820
  user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
16430
16821
  response_format: 'url', // TODO: [๐Ÿง ] Maybe allow b64_json
@@ -17443,6 +17834,11 @@
17443
17834
  * Links found in the agent source
17444
17835
  */
17445
17836
  this.links = [];
17837
+ /**
17838
+ * Capabilities of the agent
17839
+ * This is parsed from commitments like USE BROWSER, USE SEARCH ENGINE, KNOWLEDGE, etc.
17840
+ */
17841
+ this.capabilities = [];
17446
17842
  /**
17447
17843
  * Metadata like image or color
17448
17844
  */
@@ -17452,11 +17848,12 @@
17452
17848
  this.agentSource = agentSource;
17453
17849
  this.agentSource.subscribe((source) => {
17454
17850
  this.updateAgentSource(source);
17455
- const { agentName, personaDescription, initialMessage, links, meta } = parseAgentSource(source);
17851
+ const { agentName, personaDescription, initialMessage, links, meta, capabilities } = parseAgentSource(source);
17456
17852
  this._agentName = agentName;
17457
17853
  this.personaDescription = personaDescription;
17458
17854
  this.initialMessage = initialMessage;
17459
17855
  this.links = links;
17856
+ this.capabilities = capabilities;
17460
17857
  this.meta = { ...this.meta, ...meta };
17461
17858
  });
17462
17859
  }
@@ -17530,9 +17927,52 @@
17530
17927
  ${block(result.content)}
17531
17928
 
17532
17929
  `);
17930
+ // Extract knowledge
17931
+ let knowledgeBlock = '';
17932
+ try {
17933
+ const extractionPrompt = {
17934
+ title: 'Knowledge Extraction',
17935
+ modelRequirements: {
17936
+ modelVariant: 'CHAT',
17937
+ },
17938
+ content: spaceTrim__default["default"]((block) => `
17939
+ You are an AI agent that is learning from a conversation.
17940
+
17941
+ Here is the conversation so far:
17942
+
17943
+ User: ${block(prompt.content)}
17944
+ Agent: ${block(result.content)}
17945
+
17946
+ Extract any new knowledge, facts, or important information that should be remembered for future interactions.
17947
+ Format the output as a list of KNOWLEDGE blocks.
17948
+ If there is no new knowledge, return nothing.
17949
+
17950
+ Example output:
17951
+ KNOWLEDGE The user's name is Alice.
17952
+ KNOWLEDGE The project deadline is next Friday.
17953
+ `),
17954
+ pipelineUrl: 'https://github.com/webgptorg/promptbook/blob/main/prompts/knowledge-extraction.ptbk.md',
17955
+ parameters: {},
17956
+ };
17957
+ if (this.options.llmTools.callChatModel) {
17958
+ const extractionResult = await this.options.llmTools.callChatModel(extractionPrompt);
17959
+ const extractedContent = extractionResult.content;
17960
+ if (extractedContent.includes('KNOWLEDGE')) {
17961
+ knowledgeBlock = '\n\n' + spaceTrim__default["default"](extractedContent);
17962
+ }
17963
+ }
17964
+ else {
17965
+ // TODO: [๐Ÿง ] Fallback to callChatModelStream if callChatModel is not available
17966
+ }
17967
+ }
17968
+ catch (error) {
17969
+ if (this.options.isVerbose) {
17970
+ console.warn('Failed to extract knowledge', error);
17971
+ }
17972
+ }
17533
17973
  // Append to the current source
17534
17974
  const currentSource = this.agentSource.value;
17535
- const newSource = padBook(validateBook(spaceTrim__default["default"](currentSource) + '\n\n' + learningExample));
17975
+ const newSource = padBook(validateBook(spaceTrim__default["default"](currentSource) + '\n\n' + learningExample + knowledgeBlock));
17536
17976
  // Update the source (which will trigger the subscription and update the underlying tools)
17537
17977
  this.agentSource.next(newSource);
17538
17978
  return result;
@@ -17806,7 +18246,8 @@
17806
18246
  // TODO: [๐Ÿง ] Handle error state (show error message in the chat window)
17807
18247
  const image = ((_a = agent === null || agent === void 0 ? void 0 : agent.meta) === null || _a === void 0 ? void 0 : _a.image) ||
17808
18248
  (meta === null || meta === void 0 ? void 0 : meta.image) ||
17809
- 'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y';
18249
+ // Note: [๐Ÿคน] Using default avatar from the agent server
18250
+ `${agentUrl}/images/default-avatar.png`;
17810
18251
  const color = ((_b = agent === null || agent === void 0 ? void 0 : agent.meta) === null || _b === void 0 ? void 0 : _b.color) || (meta === null || meta === void 0 ? void 0 : meta.color);
17811
18252
  let connectionStatus = 'pending';
17812
18253
  if (agent) {