@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/esm/index.es.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useMemo, useEffect, useState, useRef, useCallback, forwardRef, memo } from 'react';
2
+ import { useMemo, useEffect, useState, useRef, createContext, useContext, useCallback, forwardRef, memo } from 'react';
3
3
  import spaceTrim$2, { spaceTrim as spaceTrim$1 } from 'spacetrim';
4
4
  import { SHA256 } from 'crypto-js';
5
5
  import hexEncoder from 'crypto-js/enc-hex';
@@ -8,8 +8,8 @@ import { randomBytes } from 'crypto';
8
8
  import { createPortal } from 'react-dom';
9
9
  import Editor, { useMonaco } from '@monaco-editor/react';
10
10
  import { Registration } from 'destroyable';
11
- import hljs from 'highlight.js';
12
11
  import katex from 'katex';
12
+ import { createRoot } from 'react-dom/client';
13
13
  import { Converter } from 'showdown';
14
14
  import { BehaviorSubject, Subject } from 'rxjs';
15
15
  import { forTime } from 'waitasecond';
@@ -35,7 +35,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
35
35
  * @generated
36
36
  * @see https://github.com/webgptorg/promptbook
37
37
  */
38
- const PROMPTBOOK_ENGINE_VERSION = '0.104.0-1';
38
+ const PROMPTBOOK_ENGINE_VERSION = '0.104.0-11';
39
39
  /**
40
40
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
41
41
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
@@ -84,9 +84,9 @@ function styleInject(css, ref) {
84
84
  }
85
85
  }
86
86
 
87
- 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== */";
88
- var styles$8 = {"AvatarChip":"AvatarChip-module_AvatarChip__4sA0u","Avatar":"AvatarChip-module_Avatar__mN2sc","TemplateLabel":"AvatarChip-module_TemplateLabel__-7vVI"};
89
- styleInject(css_248z$9);
87
+ 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== */";
88
+ var styles$9 = {"AvatarChip":"AvatarChip-module_AvatarChip__4sA0u","Avatar":"AvatarChip-module_Avatar__mN2sc","TemplateLabel":"AvatarChip-module_TemplateLabel__-7vVI"};
89
+ styleInject(css_248z$a);
90
90
 
91
91
  /**
92
92
  * Shows a chip with avatar's avatar and name
@@ -96,7 +96,7 @@ styleInject(css_248z$9);
96
96
  function AvatarChip(props) {
97
97
  const { avatarBasicInformation, className, onSelect, isSelected, isTemplate } = props;
98
98
  const { agentName, meta } = avatarBasicInformation;
99
- return (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: [jsx("img", { src: meta.image, alt: agentName || '', className: styles$8.Avatar }), meta.fullname || agentName, isTemplate && jsx("span", { className: styles$8.TemplateLabel, children: "Template" })] }));
99
+ return (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: [jsx("img", { src: meta.image, alt: agentName || '', className: styles$9.Avatar }), meta.fullname || agentName, isTemplate && jsx("span", { className: styles$9.TemplateLabel, children: "Template" })] }));
100
100
  }
101
101
 
102
102
  /**
@@ -153,48 +153,12 @@ function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
153
153
  * TODO: [๐ŸŒบ] Use some intermediate util splitWords
154
154
  */
155
155
 
156
- /**
157
- * Generates a gravatar URL based on agent name for fallback avatar
158
- *
159
- * @param agentName The agent name to generate avatar for
160
- * @returns Gravatar URL
161
- *
162
- * @private - [๐Ÿคน] The fact that profile image is Gravatar is just implementation detail which should be hidden for consumer
163
- */
164
- function generateGravatarUrl(agentName) {
165
- // Use a default name if none provided
166
- const safeName = agentName || 'Anonymous Agent';
167
- // Create a simple hash from the name for consistent avatar
168
- let hash = 0;
169
- for (let i = 0; i < safeName.length; i++) {
170
- const char = safeName.charCodeAt(i);
171
- hash = (hash << 5) - hash + char;
172
- hash = hash & hash; // Convert to 32bit integer
173
- }
174
- const avatarId = Math.abs(hash).toString();
175
- return `https://www.gravatar.com/avatar/${avatarId}?default=robohash&size=200&rating=x`;
176
- }
177
-
178
- /**
179
- * Generates an image for the agent to use as profile image
180
- *
181
- * @param agentName The agent name to generate avatar for
182
- * @returns The placeholder profile image URL for the agent
183
- *
184
- * @public exported from `@promptbook/core`
185
- */
186
- function generatePlaceholderAgentProfileImageUrl(agentName) {
187
- // Note: [๐Ÿคน] The fact that profile image is Gravatar is just implementation detail which should be hidden for consumer
188
- return generateGravatarUrl(agentName);
189
- }
190
- /**
191
- * TODO: [๐Ÿคน] Figure out best placeholder image generator https://i.pravatar.cc/1000?u=568
192
- */
193
-
194
156
  /**
195
157
  * Core Promptbook server configuration.
196
158
  *
197
159
  * This server is also used for auto-federation in the Agents Server.
160
+ *
161
+ * @public exported from `@promptbook/core`
198
162
  */
199
163
  const CORE_SERVER = {
200
164
  title: 'Promptbook Core',
@@ -3047,13 +3011,14 @@ function prompt(strings, ...values) {
3047
3011
  *
3048
3012
  * @public exported from `@promptbook/utils`
3049
3013
  */
3050
- const $isRunningInBrowser = new Function(`
3014
+ function $isRunningInBrowser() {
3051
3015
  try {
3052
- return this === window;
3053
- } catch (e) {
3016
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined';
3017
+ }
3018
+ catch (e) {
3054
3019
  return false;
3055
3020
  }
3056
- `);
3021
+ }
3057
3022
  /**
3058
3023
  * TODO: [๐ŸŽบ]
3059
3024
  */
@@ -3065,13 +3030,15 @@ const $isRunningInBrowser = new Function(`
3065
3030
  *
3066
3031
  * @public exported from `@promptbook/utils`
3067
3032
  */
3068
- const $isRunningInJest = new Function(`
3033
+ function $isRunningInJest() {
3034
+ var _a;
3069
3035
  try {
3070
- return process.env.JEST_WORKER_ID !== undefined;
3071
- } catch (e) {
3036
+ return typeof process !== 'undefined' && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.JEST_WORKER_ID) !== undefined;
3037
+ }
3038
+ catch (e) {
3072
3039
  return false;
3073
3040
  }
3074
- `);
3041
+ }
3075
3042
  /**
3076
3043
  * TODO: [๐ŸŽบ]
3077
3044
  */
@@ -3083,13 +3050,14 @@ const $isRunningInJest = new Function(`
3083
3050
  *
3084
3051
  * @public exported from `@promptbook/utils`
3085
3052
  */
3086
- const $isRunningInNode = new Function(`
3053
+ function $isRunningInNode() {
3087
3054
  try {
3088
- return this === global;
3089
- } catch (e) {
3055
+ return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
3056
+ }
3057
+ catch (e) {
3090
3058
  return false;
3091
3059
  }
3092
- `);
3060
+ }
3093
3061
  /**
3094
3062
  * TODO: [๐ŸŽบ]
3095
3063
  */
@@ -3101,17 +3069,17 @@ const $isRunningInNode = new Function(`
3101
3069
  *
3102
3070
  * @public exported from `@promptbook/utils`
3103
3071
  */
3104
- const $isRunningInWebWorker = new Function(`
3072
+ function $isRunningInWebWorker() {
3105
3073
  try {
3106
- if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
3107
- return true;
3108
- } else {
3109
- return false;
3110
- }
3111
- } catch (e) {
3074
+ // Note: Check for importScripts which is specific to workers
3075
+ // and not available in the main browser thread
3076
+ return (typeof self !== 'undefined' &&
3077
+ typeof self.importScripts === 'function');
3078
+ }
3079
+ catch (e) {
3112
3080
  return false;
3113
3081
  }
3114
- `);
3082
+ }
3115
3083
  /**
3116
3084
  * TODO: [๐ŸŽบ]
3117
3085
  */
@@ -4127,6 +4095,114 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
4127
4095
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
4128
4096
  */
4129
4097
 
4098
+ /**
4099
+ * DICTIONARY commitment definition
4100
+ *
4101
+ * The DICTIONARY commitment defines specific terms and their meanings that the agent should use correctly
4102
+ * in its reasoning and responses. This ensures consistent terminology usage.
4103
+ *
4104
+ * Key features:
4105
+ * - Multiple DICTIONARY commitments are automatically merged into one
4106
+ * - Content is placed in a dedicated section of the system message
4107
+ * - Terms and definitions are stored in metadata.DICTIONARY for debugging
4108
+ * - Agent should use the defined terms correctly in responses
4109
+ *
4110
+ * Example usage in agent source:
4111
+ *
4112
+ * ```book
4113
+ * Legal Assistant
4114
+ *
4115
+ * PERSONA You are a knowledgeable legal assistant
4116
+ * DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
4117
+ * DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
4118
+ * DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
4119
+ * ```
4120
+ *
4121
+ * @private [๐Ÿช”] Maybe export the commitments through some package
4122
+ */
4123
+ class DictionaryCommitmentDefinition extends BaseCommitmentDefinition {
4124
+ constructor() {
4125
+ super('DICTIONARY');
4126
+ }
4127
+ /**
4128
+ * Short one-line description of DICTIONARY.
4129
+ */
4130
+ get description() {
4131
+ return 'Define terms and their meanings for consistent terminology usage.';
4132
+ }
4133
+ /**
4134
+ * Icon for this commitment.
4135
+ */
4136
+ get icon() {
4137
+ return '๐Ÿ“š';
4138
+ }
4139
+ /**
4140
+ * Markdown documentation for DICTIONARY commitment.
4141
+ */
4142
+ get documentation() {
4143
+ return spaceTrim$1(`
4144
+ # DICTIONARY
4145
+
4146
+ Defines specific terms and their meanings that the agent should use correctly in reasoning and responses.
4147
+
4148
+ ## Key aspects
4149
+
4150
+ - Multiple \`DICTIONARY\` commitments are merged together.
4151
+ - Terms are defined in the format: "Term is definition"
4152
+ - The agent should use these terms consistently in responses.
4153
+ - Definitions help ensure accurate and consistent terminology.
4154
+
4155
+ ## Examples
4156
+
4157
+ \`\`\`book
4158
+ Legal Assistant
4159
+
4160
+ PERSONA You are a knowledgeable legal assistant specializing in criminal law
4161
+ DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
4162
+ DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
4163
+ DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
4164
+ \`\`\`
4165
+
4166
+ \`\`\`book
4167
+ Medical Assistant
4168
+
4169
+ PERSONA You are a helpful medical assistant
4170
+ DICTIONARY Hypertension is persistently high blood pressure
4171
+ DICTIONARY Diabetes is a chronic condition that affects how the body processes blood sugar
4172
+ DICTIONARY Vaccine is a biological preparation that provides active immunity to a particular disease
4173
+ \`\`\`
4174
+ `);
4175
+ }
4176
+ applyToAgentModelRequirements(requirements, content) {
4177
+ var _a;
4178
+ const trimmedContent = content.trim();
4179
+ if (!trimmedContent) {
4180
+ return requirements;
4181
+ }
4182
+ // Get existing dictionary entries from metadata
4183
+ const existingDictionary = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.DICTIONARY) || '';
4184
+ // Merge the new dictionary entry with existing entries
4185
+ const mergedDictionary = existingDictionary
4186
+ ? `${existingDictionary}\n${trimmedContent}`
4187
+ : trimmedContent;
4188
+ // Store the merged dictionary in metadata for debugging and inspection
4189
+ const updatedMetadata = {
4190
+ ...requirements.metadata,
4191
+ DICTIONARY: mergedDictionary,
4192
+ };
4193
+ // Create the dictionary section for the system message
4194
+ // Format: "# DICTIONARY\nTerm: definition\nTerm: definition..."
4195
+ const dictionarySection = `# DICTIONARY\n${mergedDictionary}`;
4196
+ return {
4197
+ ...this.appendToSystemMessage(requirements, dictionarySection),
4198
+ metadata: updatedMetadata,
4199
+ };
4200
+ }
4201
+ }
4202
+ /**
4203
+ * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
4204
+ */
4205
+
4130
4206
  /**
4131
4207
  * FORMAT commitment definition
4132
4208
  *
@@ -6947,6 +7023,7 @@ const COMMITMENT_REGISTRY = [
6947
7023
  new DeleteCommitmentDefinition('CANCEL'),
6948
7024
  new DeleteCommitmentDefinition('DISCARD'),
6949
7025
  new DeleteCommitmentDefinition('REMOVE'),
7026
+ new DictionaryCommitmentDefinition(),
6950
7027
  new OpenCommitmentDefinition(),
6951
7028
  new ClosedCommitmentDefinition(),
6952
7029
  new UseBrowserCommitmentDefinition(),
@@ -7006,17 +7083,64 @@ function parseAgentSourceWithCommitments(agentSource) {
7006
7083
  };
7007
7084
  }
7008
7085
  const lines = agentSource.split('\n');
7009
- const agentName = (((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.trim()) || null);
7086
+ let agentName = null;
7087
+ let agentNameLineIndex = -1;
7088
+ // Find the agent name: first non-empty line that is not a commitment and not a horizontal line
7089
+ for (let i = 0; i < lines.length; i++) {
7090
+ const line = lines[i];
7091
+ if (line === undefined) {
7092
+ continue;
7093
+ }
7094
+ const trimmed = line.trim();
7095
+ if (!trimmed) {
7096
+ continue;
7097
+ }
7098
+ const isHorizontal = HORIZONTAL_LINE_PATTERN.test(line);
7099
+ if (isHorizontal) {
7100
+ continue;
7101
+ }
7102
+ let isCommitment = false;
7103
+ for (const definition of COMMITMENT_REGISTRY) {
7104
+ const typeRegex = definition.createTypeRegex();
7105
+ const match = typeRegex.exec(trimmed);
7106
+ if (match && ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.type)) {
7107
+ isCommitment = true;
7108
+ break;
7109
+ }
7110
+ }
7111
+ if (!isCommitment) {
7112
+ agentName = trimmed;
7113
+ agentNameLineIndex = i;
7114
+ break;
7115
+ }
7116
+ }
7010
7117
  const commitments = [];
7011
7118
  const nonCommitmentLines = [];
7012
- // Always add the first line (agent name) to non-commitment lines
7013
- if (lines[0] !== undefined) {
7014
- nonCommitmentLines.push(lines[0]);
7119
+ // Add lines before agentName that are horizontal lines (they are non-commitment)
7120
+ for (let i = 0; i < agentNameLineIndex; i++) {
7121
+ const line = lines[i];
7122
+ if (line === undefined) {
7123
+ continue;
7124
+ }
7125
+ const trimmed = line.trim();
7126
+ if (!trimmed) {
7127
+ continue;
7128
+ }
7129
+ const isHorizontal = HORIZONTAL_LINE_PATTERN.test(line);
7130
+ if (isHorizontal) {
7131
+ nonCommitmentLines.push(line);
7132
+ }
7133
+ // Note: Commitments before agentName are not added to nonCommitmentLines
7134
+ }
7135
+ // Add the agent name line to non-commitment lines
7136
+ if (agentNameLineIndex >= 0) {
7137
+ nonCommitmentLines.push(lines[agentNameLineIndex]);
7015
7138
  }
7016
7139
  // Parse commitments with multiline support
7017
7140
  let currentCommitment = null;
7018
- // Process lines starting from the second line (skip agent name)
7019
- for (let i = 1; i < lines.length; i++) {
7141
+ // Process lines starting from after the agent name line
7142
+ const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
7143
+ for (let i = startIndex; i < lines.length; i++) {
7020
7144
  const line = lines[i];
7021
7145
  if (line === undefined) {
7022
7146
  continue;
@@ -7193,7 +7317,57 @@ function parseAgentSource(agentSource) {
7193
7317
  }
7194
7318
  const meta = {};
7195
7319
  const links = [];
7320
+ const capabilities = [];
7196
7321
  for (const commitment of parseResult.commitments) {
7322
+ if (commitment.type === 'USE BROWSER') {
7323
+ capabilities.push({
7324
+ type: 'browser',
7325
+ label: 'Browser',
7326
+ iconName: 'Globe',
7327
+ });
7328
+ continue;
7329
+ }
7330
+ if (commitment.type === 'USE SEARCH ENGINE') {
7331
+ capabilities.push({
7332
+ type: 'search-engine',
7333
+ label: 'Search Internet',
7334
+ iconName: 'Search',
7335
+ });
7336
+ continue;
7337
+ }
7338
+ if (commitment.type === 'KNOWLEDGE') {
7339
+ const content = spaceTrim$2(commitment.content).split('\n')[0] || '';
7340
+ let label = content;
7341
+ let iconName = 'Book';
7342
+ if (content.startsWith('http://') || content.startsWith('https://')) {
7343
+ try {
7344
+ const url = new URL(content);
7345
+ if (url.pathname.endsWith('.pdf')) {
7346
+ label = url.pathname.split('/').pop() || 'Document.pdf';
7347
+ iconName = 'FileText';
7348
+ }
7349
+ else {
7350
+ label = url.hostname.replace(/^www\./, '');
7351
+ }
7352
+ }
7353
+ catch (e) {
7354
+ // Invalid URL, treat as text
7355
+ }
7356
+ }
7357
+ else {
7358
+ // Text content - take first few words
7359
+ const words = content.split(/\s+/);
7360
+ if (words.length > 4) {
7361
+ label = words.slice(0, 4).join(' ') + '...';
7362
+ }
7363
+ }
7364
+ capabilities.push({
7365
+ type: 'knowledge',
7366
+ label,
7367
+ iconName,
7368
+ });
7369
+ continue;
7370
+ }
7197
7371
  if (commitment.type === 'META LINK') {
7198
7372
  const linkValue = spaceTrim$2(commitment.content);
7199
7373
  links.push(linkValue);
@@ -7223,10 +7397,6 @@ function parseAgentSource(agentSource) {
7223
7397
  const metaType = normalizeTo_camelCase(metaTypeRaw);
7224
7398
  meta[metaType] = spaceTrim$2(commitment.content.substring(metaTypeRaw.length));
7225
7399
  }
7226
- // Generate gravatar fallback if no meta image specified
7227
- if (!meta.image) {
7228
- meta.image = generatePlaceholderAgentProfileImageUrl(parseResult.agentName || '!!');
7229
- }
7230
7400
  // Generate fullname fallback if no meta fullname specified
7231
7401
  if (!meta.fullname) {
7232
7402
  meta.fullname = parseResult.agentName || createDefaultAgentName(agentSource);
@@ -7238,11 +7408,13 @@ function parseAgentSource(agentSource) {
7238
7408
  return {
7239
7409
  agentName: normalizeAgentName(parseResult.agentName || createDefaultAgentName(agentSource)),
7240
7410
  agentHash,
7411
+ permanentId: meta.id,
7241
7412
  personaDescription,
7242
7413
  initialMessage,
7243
7414
  meta,
7244
7415
  links,
7245
7416
  parameters,
7417
+ capabilities,
7246
7418
  };
7247
7419
  }
7248
7420
  /**
@@ -7277,9 +7449,9 @@ function AvatarChipFromSource(props) {
7277
7449
  return jsx(AvatarChip, { avatarBasicInformation: avatarBasicInformation, ...props });
7278
7450
  }
7279
7451
 
7280
- 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= */";
7281
- var styles$7 = {"scrim":"Modal-module_scrim__jKO-A","Modal":"Modal-module_Modal__k49dY","closeButton":"Modal-module_closeButton__dzf6l"};
7282
- styleInject(css_248z$8);
7452
+ 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= */";
7453
+ var styles$8 = {"scrim":"Modal-module_scrim__jKO-A","Modal":"Modal-module_Modal__k49dY","closeButton":"Modal-module_closeButton__dzf6l"};
7454
+ styleInject(css_248z$9);
7283
7455
 
7284
7456
  /**
7285
7457
  *
@@ -7297,7 +7469,7 @@ function Modal({ children, onClose, className, }) {
7297
7469
  window.removeEventListener('keydown', handleKeyDown);
7298
7470
  };
7299
7471
  }, [onClose]);
7300
- return createPortal(jsx("div", { className: styles$7.scrim, onClick: onClose, children: jsxs("div", { className: classNames(styles$7.Modal, className), onClick: (e) => e.stopPropagation(), children: [jsx("button", { className: styles$7.closeButton, onClick: onClose, children: "\u00D7" }), children] }) }), document.body);
7472
+ return createPortal(jsx("div", { className: styles$8.scrim, onClick: onClose, children: jsxs("div", { className: classNames(styles$8.Modal, className), onClick: (e) => e.stopPropagation(), children: [jsx("button", { className: styles$8.closeButton, onClick: onClose, children: "\u00D7" }), children] }) }), document.body);
7301
7473
  }
7302
7474
 
7303
7475
  /**
@@ -7382,9 +7554,9 @@ const DEFAULT_BOOK = padBook(validateBook(spaceTrim$2(`
7382
7554
  // <- [๐Ÿฑโ€๐Ÿš€] Buttons into genesis book
7383
7555
  // <- TODO: [๐Ÿฑโ€๐Ÿš€] generateBookBoilerplate and deprecate `DEFAULT_BOOK`
7384
7556
 
7385
- 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 */";
7386
- 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"};
7387
- styleInject(css_248z$7);
7557
+ 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 */";
7558
+ 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"};
7559
+ styleInject(css_248z$8);
7388
7560
 
7389
7561
  /**
7390
7562
  * Converts Blob, File or MediaSource to url using URL.createObjectURL
@@ -7504,12 +7676,107 @@ async function $induceBookDownload(book) {
7504
7676
  * Note: [๐Ÿ”ต] Code in this file should never be published outside of `@promptbook/browser`
7505
7677
  */
7506
7678
 
7679
+ /**
7680
+ * Downloads a file with the given content and filename
7681
+ *
7682
+ * @private utility of `<Chat/>` component
7683
+ */
7684
+ function downloadFile(content, filename, mimeType) {
7685
+ const blob = new Blob([content], { type: mimeType });
7686
+ const url = URL.createObjectURL(blob);
7687
+ const link = document.createElement('a');
7688
+ link.href = url;
7689
+ link.download = filename;
7690
+ document.body.appendChild(link);
7691
+ link.click();
7692
+ document.body.removeChild(link);
7693
+ // Clean up the URL object
7694
+ setTimeout(() => URL.revokeObjectURL(url), 100);
7695
+ }
7696
+
7697
+ 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= */";
7698
+ 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"};
7699
+ styleInject(css_248z$7);
7700
+
7701
+ const LANGUAGE_EXTENSIONS = {
7702
+ python: 'py',
7703
+ javascript: 'js',
7704
+ typescript: 'ts',
7705
+ json: 'json',
7706
+ html: 'html',
7707
+ css: 'css',
7708
+ markdown: 'md',
7709
+ text: 'txt',
7710
+ xml: 'xml',
7711
+ sql: 'sql',
7712
+ sh: 'sh',
7713
+ bash: 'sh',
7714
+ zsh: 'sh',
7715
+ yaml: 'yaml',
7716
+ yml: 'yaml',
7717
+ book: 'book',
7718
+ };
7719
+ /**
7720
+ * Component to render a code block with syntax highlighting, copy, download, and create agent options.
7721
+ *
7722
+ * @private Internal utility of `<ChatMessage />` component
7723
+ */
7724
+ function CodeBlock({ code, language, className, onCreateAgent }) {
7725
+ const lines = useMemo(() => code.split('\n').length, [code]);
7726
+ // Note: 19px is approx line height for fontSize 14. +20 for padding.
7727
+ // We cap at 400px to avoid taking too much space, allowing scroll.
7728
+ const height = Math.min(Math.max(lines * 19, 19), 400);
7729
+ const [copied, setCopied] = useState(false);
7730
+ const handleDownload = () => {
7731
+ const lang = (language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) || 'text';
7732
+ const extension = LANGUAGE_EXTENSIONS[lang] || lang;
7733
+ const filename = `file.${extension}`;
7734
+ downloadFile(code, filename, 'text/plain');
7735
+ };
7736
+ const handleCopy = async () => {
7737
+ try {
7738
+ await navigator.clipboard.writeText(code);
7739
+ setCopied(true);
7740
+ setTimeout(() => setCopied(false), 2000);
7741
+ }
7742
+ catch (error) {
7743
+ console.error('Failed to copy code to clipboard:', error);
7744
+ }
7745
+ };
7746
+ const header = language ? (jsxs("div", { className: styles$6.CodeBlockHeader, children: [jsx("span", { children: language }), jsxs("div", { className: styles$6.CodeBlockButtons, children: [jsx("button", { onClick: handleCopy, className: styles$6.CopyButton, title: "Copy to clipboard", children: copied ? 'Copied!' : 'Copy' }), 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 && (jsx("button", { onClick: () => onCreateAgent(code), className: styles$6.CreateAgentButton, title: "Create agent from this book", children: "Create Agent" }))] })] })) : null;
7747
+ if ((language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) === 'book') {
7748
+ return (jsxs("div", { className: classNames(styles$6.CodeBlock, className), children: [header, jsx(BookEditor, { value: code, isReadonly: true, height: lines * 25 /* <- [๐Ÿง ] A bit more than 19px to accommodate BookEditor lines */ })] }));
7749
+ }
7750
+ return (jsxs("div", { className: classNames(styles$6.CodeBlock, className), children: [header, jsx(Editor, { height: `${height}px`, language: language || 'plaintext', value: code, theme: "vs-dark", options: {
7751
+ readOnly: true,
7752
+ minimap: { enabled: false },
7753
+ scrollBeyondLastLine: false,
7754
+ lineNumbers: 'on',
7755
+ folding: false,
7756
+ glyphMargin: false,
7757
+ fontFamily: 'Consolas, "Courier New", monospace',
7758
+ fontSize: 14,
7759
+ lineHeight: 19,
7760
+ overviewRulerLanes: 0,
7761
+ hideCursorInOverviewRuler: true,
7762
+ renderLineHighlight: 'none',
7763
+ contextmenu: false,
7764
+ scrollbar: {
7765
+ vertical: 'auto',
7766
+ horizontal: 'auto',
7767
+ useShadows: false,
7768
+ },
7769
+ domReadOnly: true,
7770
+ wordWrap: 'off',
7771
+ } })] }));
7772
+ }
7773
+
7507
7774
  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= */";
7508
7775
  var styles$5 = {"MarkdownContent":"MarkdownContent-module_MarkdownContent__2JuyX","chat-code-block":"MarkdownContent-module_chat-code-block__ZffFg","citation":"MarkdownContent-module_citation__11SMw"};
7509
7776
  styleInject(css_248z$6);
7510
7777
 
7511
7778
  /**
7512
- * @@@
7779
+ * Creates a showdown converter configured for chat markdown rendering
7513
7780
  *
7514
7781
  * @private utility of `MarkdownContent` component
7515
7782
  */
@@ -7557,13 +7824,13 @@ function createChatMarkdownConverter() {
7557
7824
  });
7558
7825
  }
7559
7826
  /**
7560
- * @@@
7827
+ * Pre-configured showdown converter for chat markdown
7561
7828
  *
7562
7829
  * @private utility of `MarkdownContent` component
7563
7830
  */
7564
7831
  const chatMarkdownConverter = createChatMarkdownConverter();
7565
7832
  /**
7566
- * @@@
7833
+ * Renders math expressions in markdown using KaTeX
7567
7834
  *
7568
7835
  * @private utility of `MarkdownContent` component
7569
7836
  */
@@ -7606,32 +7873,8 @@ function renderMarkdown(markdown) {
7606
7873
  }
7607
7874
  try {
7608
7875
  const processedMarkdown = renderMathInMarkdown(markdown);
7609
- let html = chatMarkdownConverter.makeHtml(processedMarkdown);
7610
- if (typeof window === 'undefined') {
7611
- html = html.replace(/<pre><code( class="language-([^"]+)")?>([\s\S]*?)<\/code><\/pre>/g, (match, _langClass, lang, code) => {
7612
- const decoded = code
7613
- .replace(/&/g, '&')
7614
- .replace(/</g, '<')
7615
- .replace(/>/g, '>')
7616
- .replace(/"/g, '"')
7617
- .replace(/&#39;/g, "'");
7618
- const highlighted = lang
7619
- ? hljs.highlight(decoded, { language: lang }).value
7620
- : hljs.highlightAuto(decoded).value;
7621
- return `<pre class="chat-code-block"><code class="hljs${lang ? ' language-' + lang : ''}">${highlighted}</code></pre>`;
7622
- });
7623
- }
7624
- else {
7625
- if (html.match(/<pre><code/)) {
7626
- const cssId = 'hljs-github-dark-css';
7627
- if (!window.document.getElementById(cssId)) {
7628
- const link = window.document.createElement('link');
7629
- link.id = cssId;
7630
- link.rel = 'stylesheet';
7631
- link.href = 'https://book-components.ptbk.io/cdn/highlightjs/github-dark.css';
7632
- window.document.head.appendChild(link);
7633
- }
7634
- }
7876
+ const html = chatMarkdownConverter.makeHtml(processedMarkdown);
7877
+ if (typeof window !== 'undefined') {
7635
7878
  if (html.match(/class="katex/)) {
7636
7879
  const katexCssId = 'katex-css';
7637
7880
  if (!window.document.getElementById(katexCssId)) {
@@ -7642,38 +7885,6 @@ function renderMarkdown(markdown) {
7642
7885
  window.document.head.appendChild(link);
7643
7886
  }
7644
7887
  }
7645
- const parser = new window.DOMParser();
7646
- const doc = parser.parseFromString(html, 'text/html');
7647
- doc.querySelectorAll('pre > code').forEach((codeEl) => {
7648
- var _a;
7649
- const preEl = codeEl.parentElement;
7650
- if (!preEl)
7651
- return;
7652
- const lang = (_a = Array.from(codeEl.classList)
7653
- .find((cls) => cls.startsWith('language-'))) === null || _a === void 0 ? void 0 : _a.replace('language-', '');
7654
- const code = codeEl.innerHTML;
7655
- let highlighted = '';
7656
- try {
7657
- const decoded = code
7658
- .replace(/&/g, '&')
7659
- .replace(/</g, '<')
7660
- .replace(/>/g, '>')
7661
- .replace(/"/g, '"')
7662
- .replace(/&#39;/g, "'");
7663
- highlighted = lang
7664
- ? hljs.highlight(decoded, { language: lang }).value
7665
- : hljs.highlightAuto(decoded).value;
7666
- }
7667
- catch (_b) {
7668
- highlighted = code;
7669
- }
7670
- codeEl.innerHTML = highlighted;
7671
- codeEl.classList.add('hljs');
7672
- if (lang)
7673
- codeEl.classList.add(`language-${lang}`);
7674
- preEl.classList.add('chat-code-block');
7675
- });
7676
- html = doc.body.innerHTML;
7677
7888
  }
7678
7889
  const sanitizedHtml = html
7679
7890
  .replace(/<\s*(script|style|iframe|object|embed)[^>]*>[\s\S]*?<\s*\/\s*\1\s*>/gi, '')
@@ -7703,9 +7914,50 @@ function renderMarkdown(markdown) {
7703
7914
  * @public exported from `@promptbook/components`
7704
7915
  */
7705
7916
  function MarkdownContent(props) {
7706
- const { content, className } = props;
7917
+ const { content, className, onCreateAgent } = props;
7707
7918
  const htmlContent = useMemo(() => renderMarkdown(content), [content]);
7708
- return (jsx("div", { className: classNames(styles$5.MarkdownContent, className), dangerouslySetInnerHTML: {
7919
+ const containerRef = useRef(null);
7920
+ const rootsRef = useRef([]);
7921
+ useEffect(() => {
7922
+ // Cleanup previous roots
7923
+ rootsRef.current.forEach((root) => root.unmount());
7924
+ rootsRef.current = [];
7925
+ if (!containerRef.current) {
7926
+ return;
7927
+ }
7928
+ const preElements = containerRef.current.querySelectorAll('pre');
7929
+ preElements.forEach((pre) => {
7930
+ // Check if it is a code block (has code element)
7931
+ const codeElement = pre.querySelector('code');
7932
+ if (!codeElement) {
7933
+ return;
7934
+ }
7935
+ // Get language and code
7936
+ const className = codeElement.className; // e.g. language-python
7937
+ const match = className.match(/language-([^\s]+)/);
7938
+ const language = match ? match[1] : undefined;
7939
+ const code = codeElement.textContent || '';
7940
+ // Clear the pre element content
7941
+ pre.innerHTML = '';
7942
+ pre.className = ''; // remove existing classes if any
7943
+ pre.style.background = 'none'; // reset styles
7944
+ pre.style.padding = '0';
7945
+ pre.style.margin = '0';
7946
+ pre.style.overflow = 'visible';
7947
+ // Create a container for the CodeBlock
7948
+ const mountPoint = document.createElement('div');
7949
+ pre.appendChild(mountPoint);
7950
+ // Render CodeBlock
7951
+ const root = createRoot(mountPoint);
7952
+ root.render(jsx(CodeBlock, { code: code, language: language, onCreateAgent: onCreateAgent }));
7953
+ rootsRef.current.push(root);
7954
+ });
7955
+ return () => {
7956
+ rootsRef.current.forEach((root) => root.unmount());
7957
+ rootsRef.current = [];
7958
+ };
7959
+ }, [htmlContent, onCreateAgent]);
7960
+ return (jsx("div", { ref: containerRef, className: classNames(styles$5.MarkdownContent, className), dangerouslySetInnerHTML: {
7709
7961
  __html: htmlContent,
7710
7962
  } }));
7711
7963
  }
@@ -7775,7 +8027,7 @@ function AboutPromptbookInformation(props) {
7775
8027
  }
7776
8028
 
7777
8029
  /**
7778
- * @@@
8030
+ * Renders an about icon
7779
8031
  *
7780
8032
  * @private internal subcomponent used by various components
7781
8033
  */
@@ -7785,7 +8037,7 @@ function AboutIcon(props) {
7785
8037
  }
7786
8038
 
7787
8039
  /**
7788
- * @@@
8040
+ * Renders an attachment icon
7789
8041
  *
7790
8042
  * @public exported from `@promptbook/components`
7791
8043
  */
@@ -7794,7 +8046,7 @@ function AttachmentIcon({ size = 24, color = 'currentColor' }) {
7794
8046
  }
7795
8047
 
7796
8048
  /**
7797
- * @@@
8049
+ * Renders a camera icon
7798
8050
  *
7799
8051
  * @public exported from `@promptbook/components`
7800
8052
  */
@@ -7803,7 +8055,7 @@ function CameraIcon({ size = 24, color = 'currentColor' }) {
7803
8055
  }
7804
8056
 
7805
8057
  /**
7806
- * @@@
8058
+ * Renders a download icon
7807
8059
  *
7808
8060
  * @private internal subcomponent used by various components
7809
8061
  */
@@ -7897,7 +8149,7 @@ var styles$4 = {"MenuHamburger":"HamburgerMenu-module_MenuHamburger__Jd-wk","Men
7897
8149
  styleInject(css_248z$5);
7898
8150
 
7899
8151
  /**
7900
- * @@@
8152
+ * An animated hamburger menu button component.
7901
8153
  *
7902
8154
  * @private Internal component
7903
8155
  */
@@ -7910,7 +8162,7 @@ var styles$3 = {"dropdown":"Dropdown-module_dropdown__ZShv1","button":"Dropdown-
7910
8162
  styleInject(css_248z$4);
7911
8163
 
7912
8164
  /**
7913
- * @@@
8165
+ * A dropdown menu component that displays a list of actions triggered by a hamburger menu button.
7914
8166
  *
7915
8167
  * @private internal subcomponent used by various components
7916
8168
  */
@@ -7922,6 +8174,16 @@ function Dropdown({ actions }) {
7922
8174
  }, children: [icon, jsx("span", { children: name })] }, name))) }))] }));
7923
8175
  }
7924
8176
 
8177
+ const MenuHoistingContext = createContext(null);
8178
+ /**
8179
+ * Hook to use the menu hoisting system
8180
+ *
8181
+ * @private mechanism inside Promptbook
8182
+ */
8183
+ function useMenuHoisting() {
8184
+ return useContext(MenuHoistingContext);
8185
+ }
8186
+
7925
8187
  /**
7926
8188
  *
7927
8189
  * @private Internal component used by `BookEditor`
@@ -7929,50 +8191,83 @@ function Dropdown({ actions }) {
7929
8191
  function BookEditorActionbar(props) {
7930
8192
  const { value, isDownloadButtonShown, isUploadButtonShown, isCameraButtonShown, isAboutButtonShown, isFullscreenButtonShown, onFullscreenClick, onUploadDocument, onTakePhoto, isFullscreen, } = props;
7931
8193
  const [isAboutModalOpen, setIsAboutModalOpen] = useState(false);
7932
- const handleDownload = () => {
7933
- const book = validateBook(value || DEFAULT_BOOK);
8194
+ const menuHoisting = useMenuHoisting();
8195
+ // Note: [1] We use ref to avoid re-creating the handleDownload function (and thus the actions array) on every value change
8196
+ const valueRef = useRef(value);
8197
+ useEffect(() => {
8198
+ valueRef.current = value;
8199
+ }, [value]);
8200
+ const handleDownload = useCallback(() => {
8201
+ const book = validateBook(valueRef.current || DEFAULT_BOOK);
7934
8202
  /* not await */ $induceBookDownload(book);
7935
- };
7936
- const actions = [];
7937
- if (isUploadButtonShown && onUploadDocument) {
7938
- actions.push({
7939
- icon: jsx(AttachmentIcon, {}),
7940
- name: 'Upload document',
7941
- onClick: onUploadDocument,
7942
- });
7943
- }
7944
- if (isCameraButtonShown && onTakePhoto) {
7945
- actions.push({
7946
- icon: jsx(CameraIcon, {}),
7947
- name: 'Take photo',
7948
- onClick: onTakePhoto,
7949
- });
7950
- }
7951
- if (isDownloadButtonShown) {
7952
- actions.push({
7953
- icon: jsx(DownloadIcon, {}),
7954
- name: 'Download',
7955
- onClick: handleDownload,
7956
- });
7957
- }
7958
- if (isAboutButtonShown) {
7959
- actions.push({
7960
- icon: jsx(AboutIcon, {}),
7961
- name: 'About',
7962
- onClick: () => setIsAboutModalOpen(true),
7963
- });
7964
- }
7965
- if (isFullscreenButtonShown && onFullscreenClick) {
7966
- actions.push({
7967
- icon: jsx(FullscreenIcon, {}),
7968
- name: 'Fullscreen',
7969
- onClick: onFullscreenClick,
7970
- });
7971
- }
8203
+ }, []);
8204
+ const actions = useMemo(() => {
8205
+ const _actions = [];
8206
+ if (isUploadButtonShown && onUploadDocument) {
8207
+ _actions.push({
8208
+ icon: jsx(AttachmentIcon, {}),
8209
+ name: 'Upload document',
8210
+ onClick: onUploadDocument,
8211
+ });
8212
+ }
8213
+ if (isCameraButtonShown && onTakePhoto) {
8214
+ _actions.push({
8215
+ icon: jsx(CameraIcon, {}),
8216
+ name: 'Take photo',
8217
+ onClick: onTakePhoto,
8218
+ });
8219
+ }
8220
+ if (isDownloadButtonShown) {
8221
+ _actions.push({
8222
+ icon: jsx(DownloadIcon, {}),
8223
+ name: 'Download',
8224
+ onClick: handleDownload,
8225
+ });
8226
+ }
8227
+ if (isAboutButtonShown) {
8228
+ _actions.push({
8229
+ icon: jsx(AboutIcon, {}),
8230
+ name: 'About',
8231
+ onClick: () => setIsAboutModalOpen(true),
8232
+ });
8233
+ }
8234
+ if (isFullscreenButtonShown && onFullscreenClick) {
8235
+ _actions.push({
8236
+ icon: jsx(FullscreenIcon, {}),
8237
+ name: 'Fullscreen',
8238
+ onClick: onFullscreenClick,
8239
+ });
8240
+ }
8241
+ return _actions;
8242
+ }, [
8243
+ isUploadButtonShown,
8244
+ onUploadDocument,
8245
+ isCameraButtonShown,
8246
+ onTakePhoto,
8247
+ isDownloadButtonShown,
8248
+ handleDownload,
8249
+ isAboutButtonShown,
8250
+ isFullscreenButtonShown,
8251
+ onFullscreenClick,
8252
+ ]);
8253
+ useEffect(() => {
8254
+ if (!menuHoisting || isFullscreen) {
8255
+ return;
8256
+ }
8257
+ menuHoisting.setMenu(actions);
8258
+ return () => {
8259
+ menuHoisting.setMenu([]);
8260
+ };
8261
+ }, [menuHoisting, actions, isFullscreen]);
7972
8262
  if (isFullscreen) {
7973
- return (jsx("div", { className: styles$6.bookEditorActionbar, children: jsx("button", { className: styles$6.button, onClick: onFullscreenClick, children: jsx(ExitFullscreenIcon, {}) }) }));
8263
+ return (jsx("div", { className: styles$7.bookEditorActionbar, children: jsx("button", { className: styles$7.button, onClick: onFullscreenClick, children: jsx(ExitFullscreenIcon, {}) }) }));
8264
+ }
8265
+ if (menuHoisting && !isFullscreen) {
8266
+ return (jsx(Fragment, { children: isAboutModalOpen && (jsx(Modal, { onClose: () => {
8267
+ setIsAboutModalOpen(false);
8268
+ }, children: jsx(AboutPromptbookInformation, {}) })) }));
7974
8269
  }
7975
- return (jsxs("div", { className: styles$6.bookEditorActionbar, children: [actions.length >= 2 ? (jsx(Dropdown, { actions: actions })) : (actions.map(({ icon, name, onClick }) => (jsx("button", { className: styles$6.button, onClick: onClick, children: icon }, name)))), isAboutModalOpen && (jsx(Modal, { onClose: () => {
8270
+ return (jsxs("div", { className: styles$7.bookEditorActionbar, children: [actions.length >= 2 ? (jsx(Dropdown, { actions: actions })) : (actions.map(({ icon, name, onClick }) => (jsx("button", { className: styles$7.button, onClick: onClick, children: icon }, name)))), isAboutModalOpen && (jsx(Modal, { onClose: () => {
7976
8271
  setIsAboutModalOpen(false);
7977
8272
  }, children: jsx(AboutPromptbookInformation, {}) }))] }));
7978
8273
  }
@@ -8084,6 +8379,7 @@ function BookEditorMonaco(props) {
8084
8379
  const parameterRegex = /@([a-zA-Z0-9_รก-ลพร-ลฝฤ-ล™ฤŒ-ล˜ลก-ลพล -ลฝะฐ-ัะ-ะฏั‘ะ]+)/;
8085
8380
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8086
8381
  const bookRules = [
8382
+ [/^---[-]*$/, ''],
8087
8383
  [parameterRegex, 'parameter'],
8088
8384
  [/\{[^}]+\}/, 'parameter'],
8089
8385
  [commitmentRegex, 'commitment'],
@@ -8092,7 +8388,12 @@ function BookEditorMonaco(props) {
8092
8388
  const tokenProvider = monaco.languages.setMonarchTokensProvider(BOOK_LANGUAGE_ID, {
8093
8389
  ignoreCase: true,
8094
8390
  tokenizer: {
8095
- root: [[/^.*$/, 'title', '@body']],
8391
+ root: [
8392
+ [/^\s*$/, 'empty'],
8393
+ [/^-*$/, 'line'],
8394
+ [/^.*$/, 'title', '@body'],
8395
+ [commitmentRegex, 'commitment'],
8396
+ ],
8096
8397
  body: bookRules,
8097
8398
  },
8098
8399
  });
@@ -8310,7 +8611,7 @@ function BookEditorMonaco(props) {
8310
8611
  event.preventDefault();
8311
8612
  setIsDragOver(false);
8312
8613
  }, []);
8313
- return (jsxs("div", { className: classNames(styles$6.bookEditorContainer, instanceClass), onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [(isUploadButtonShown ||
8614
+ return (jsxs("div", { className: classNames(styles$7.bookEditorContainer, instanceClass), onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [(isUploadButtonShown ||
8314
8615
  isCameraButtonShown ||
8315
8616
  isDownloadButtonShown ||
8316
8617
  isAboutButtonShown ||
@@ -8323,7 +8624,7 @@ function BookEditorMonaco(props) {
8323
8624
  onFullscreenClick,
8324
8625
  onUploadDocument: handleUploadDocument,
8325
8626
  onTakePhoto: handleTakePhoto,
8326
- isFullscreen })), jsx("input", { type: "file", ref: fileUploadInputRef, style: { display: 'none' }, onChange: handleFileInputChange, multiple: true }), jsx("input", { type: "file", ref: cameraInputRef, style: { display: 'none' }, accept: "image/*", capture: "environment", onChange: handleFileInputChange }), isDragOver && jsx("div", { className: styles$6.dropOverlay, children: "Drop files to upload" }), jsxs("div", { style: {
8627
+ isFullscreen })), jsx("input", { type: "file", ref: fileUploadInputRef, style: { display: 'none' }, onChange: handleFileInputChange, multiple: true }), jsx("input", { type: "file", ref: cameraInputRef, style: { display: 'none' }, accept: "image/*", capture: "environment", onChange: handleFileInputChange }), isDragOver && jsx("div", { className: styles$7.dropOverlay, children: "Drop files to upload" }), jsxs("div", { style: {
8327
8628
  position: 'relative',
8328
8629
  flex: 1,
8329
8630
  height: '100%',
@@ -8388,7 +8689,7 @@ function BookEditorMonaco(props) {
8388
8689
  arrowSize: 0,
8389
8690
  useShadows: false,
8390
8691
  },
8391
- }, loading: jsx("div", { className: styles$6.loading, children: "\uD83D\uDCD6" }) })] })] }));
8692
+ }, loading: jsx("div", { className: styles$7.loading, children: "\uD83D\uDCD6" }) })] })] }));
8392
8693
  }
8393
8694
 
8394
8695
  /**
@@ -8410,7 +8711,7 @@ function BookEditor(props) {
8410
8711
  const handleFullscreenToggle = () => {
8411
8712
  setIsFullscreen(!isFullscreen);
8412
8713
  };
8413
- const editorContent = (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
8714
+ const editorContent = (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
8414
8715
  ? style
8415
8716
  : {
8416
8717
  ...(style || {}),
@@ -8536,6 +8837,52 @@ function furthest(...colors) {
8536
8837
  */
8537
8838
  const textColor = furthest(Color.get('white'), Color.from('black'));
8538
8839
 
8840
+ /**
8841
+ * Makes data url from color
8842
+ *
8843
+ * @public exported from `@promptbook/color`
8844
+ */
8845
+ function colorToDataUrl(color) {
8846
+ if (typeof color === 'string') {
8847
+ color = Color.fromHex(color);
8848
+ }
8849
+ return rgbDataURL(color.red, color.green, color.blue);
8850
+ }
8851
+ /**
8852
+ * Pixel GIF code adapted from https://stackoverflow.com/a/33919020/266535
8853
+ *
8854
+ * @private util of `colorToDataUrl`
8855
+ */
8856
+ const keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
8857
+ /**
8858
+ * Generates a base64-encoded triplet string
8859
+ *
8860
+ * @param e1 - The first element in the triplet.
8861
+ * @param e2 - The second element in the triplet.
8862
+ * @param e3 - The third element in the triplet.
8863
+ * @returns The base64-encoded triplet string.
8864
+ *
8865
+ * @private util of `colorToDataUrl`
8866
+ */
8867
+ const triplet = (e1, e2, e3) => keyStr.charAt(e1 >> 2) +
8868
+ keyStr.charAt(((e1 & 3) << 4) | (e2 >> 4)) +
8869
+ keyStr.charAt(((e2 & 15) << 2) | (e3 >> 6)) +
8870
+ keyStr.charAt(e3 & 63);
8871
+ /**
8872
+ * Converts RGB values to a data URL string
8873
+ *
8874
+ * @param r - The red channel value.
8875
+ * @param g - The green channel value.
8876
+ * @param b - The blue channel value.
8877
+ * @returns The RGB data URL string.
8878
+ *
8879
+ * @private util of `colorToDataUrl`
8880
+ */
8881
+ const rgbDataURL = (r, g, b) => `data:image/gif;base64,R0lGODlhAQABAPAA${triplet(0, r, g) + triplet(b, 255, 255)}/yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==`;
8882
+ /**
8883
+ * TODO: Make as functions NOT const
8884
+ */
8885
+
8539
8886
  /**
8540
8887
  * Restricts an Updatable to a (2) BehaviorSubject variant
8541
8888
  *
@@ -8738,7 +9085,7 @@ const MicIcon = ({ size }) => (jsxs("svg", { width: size, height: size, viewBox:
8738
9085
  const ResetIcon = () => (jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: 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" }) }));
8739
9086
 
8740
9087
  /**
8741
- * @@@
9088
+ * Renders a save icon
8742
9089
  *
8743
9090
  * @public exported from `@promptbook/components`
8744
9091
  */
@@ -9018,15 +9365,15 @@ const htmlSaveFormatDefinition = {
9018
9365
  ASSISTANT: '#ffb300',
9019
9366
  SYSTEM: '#888',
9020
9367
  };
9021
- const bgColor = participantColors[String(message.from)] || '#2b7cff';
9368
+ const bgColor = participantColors[String(message.sender)] || '#2b7cff';
9022
9369
  const textColor = getTextColor(bgColor);
9023
9370
  return spaceTrim$2(`
9024
9371
  <div class="chat-message">
9025
9372
  <div class="avatar" style="background:${bgColor};color:${getTextColor(bgColor)};">
9026
- ${String(message.from)[0] || '?'}
9373
+ ${String(message.sender)[0] || '?'}
9027
9374
  </div>
9028
9375
  <div class="bubble" style="background:${bgColor};color:${textColor};">
9029
- <span class="from-label">${String(message.from)}:</span>
9376
+ <span class="from-label">${String(message.sender)}:</span>
9030
9377
  ${message.content}
9031
9378
  </div>
9032
9379
  </div>
@@ -9072,7 +9419,7 @@ const mdSaveFormatDefinition = {
9072
9419
  getContent: ({ messages }) => spaceTrim$1(`
9073
9420
  ${messages
9074
9421
  .map((message) => spaceTrim$1(`
9075
- **${message.from}:**
9422
+ **${message.sender}:**
9076
9423
 
9077
9424
  > ${message.content.replace(/\n/g, '\n> ')}
9078
9425
  `))
@@ -9262,8 +9609,8 @@ const AVATAR_SIZE = 40;
9262
9609
  *
9263
9610
  * @private internal subcomponent of `<Chat>` component
9264
9611
  */
9265
- const ChatMessageItem = memo(({ message, participant, participants, isLastMessage, onMessage, setExpandedMessageId, isExpanded, currentRating, handleRating, mode, isCopyButtonEnabled, isFeedbackEnabled, onCopy, }) => {
9266
- const avatarSrc = (participant === null || participant === void 0 ? void 0 : participant.avatarSrc) || '';
9612
+ const ChatMessageItem = memo(({ message, participant, participants, isLastMessage, onMessage, setExpandedMessageId, isExpanded, currentRating, handleRating, mode, isCopyButtonEnabled, isFeedbackEnabled, onCopy, onCreateAgent, }) => {
9613
+ const avatarSrc = (participant === null || participant === void 0 ? void 0 : participant.avatarSrc) || null;
9267
9614
  const [isAvatarTooltipVisible, setIsAvatarTooltipVisible] = useState(false);
9268
9615
  const [avatarTooltipPosition, setAvatarTooltipPosition] = useState(null);
9269
9616
  const hoverTimeoutRef = useRef(null);
@@ -9354,9 +9701,14 @@ const ChatMessageItem = memo(({ message, participant, participants, isLastMessag
9354
9701
  console.info('participant avatarSrc', avatarSrc);
9355
9702
  console.info('participant color', { color, colorOfText });
9356
9703
  console.groupEnd();
9357
- }, children: [avatarSrc && (jsxs("div", { ref: avatarRef, className: chatStyles.avatar, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: showTooltip, children: [jsx("img", { width: AVATAR_SIZE, src: avatarSrc, alt: `Avatar of ${message.from.toString().toLocaleLowerCase()}`, style: {
9704
+ }, children: [avatarSrc && (jsxs("div", { ref: avatarRef, className: chatStyles.avatar, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: showTooltip, children: [jsx("img", { width: AVATAR_SIZE, src: avatarSrc, alt: `Avatar of ${message.sender.toString().toLocaleLowerCase()}`, style: {
9358
9705
  '--avatar-bg-color': color.toHex(),
9706
+ objectFit: 'cover',
9707
+ objectPosition: '50% 20%',
9359
9708
  width: AVATAR_SIZE,
9709
+ height: AVATAR_SIZE,
9710
+ aspectRatio: '1 / 1',
9711
+ backgroundImage: `url(${colorToDataUrl(color)})`,
9360
9712
  } }), isAvatarTooltipVisible && (participant === null || participant === void 0 ? void 0 : participant.agentSource) && avatarTooltipPosition && (jsx(AvatarProfileTooltip, { ref: tooltipRef, agentSource: participant.agentSource, position: avatarTooltipPosition }))] })), jsxs("div", { className: chatStyles.messageText, style: {
9361
9713
  '--message-bg-color': color.toHex(),
9362
9714
  '--message-text-color': colorOfText.toHex(),
@@ -9405,7 +9757,7 @@ const ChatMessageItem = memo(({ message, participant, participants, isLastMessag
9405
9757
  ? ' ' + chatStyles.copiedTooltipLeft
9406
9758
  : tooltipAlign === 'right'
9407
9759
  ? ' ' + chatStyles.copiedTooltipRight
9408
- : ''), children: "Copied!" }))] }) })), message.isVoiceCall && (jsx("div", { className: chatStyles.voiceCallIndicator, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: 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 ? (jsx(Fragment, {})) : (jsx("div", { ref: contentWithoutButtonsRef, children: jsx(MarkdownContent, { content: contentWithoutButtons }) })), !message.isComplete && jsx("span", { className: chatStyles.NonCompleteMessageFiller, children: '_'.repeat(70) }), shouldShowButtons && (jsx("div", { className: chatStyles.messageButtons, children: buttons.map((button, buttonIndex) => (jsx("button", { className: chatStyles.messageButton, onClick: (event) => {
9760
+ : ''), children: "Copied!" }))] }) })), message.isVoiceCall && (jsx("div", { className: chatStyles.voiceCallIndicator, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: 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 ? (jsx(Fragment, {})) : (jsx("div", { ref: contentWithoutButtonsRef, children: jsx(MarkdownContent, { content: contentWithoutButtons, onCreateAgent: onCreateAgent }) })), !message.isComplete && jsx("span", { className: chatStyles.NonCompleteMessageFiller, children: '_'.repeat(70) }), shouldShowButtons && (jsx("div", { className: chatStyles.messageButtons, children: buttons.map((button, buttonIndex) => (jsx("button", { className: chatStyles.messageButton, onClick: (event) => {
9409
9761
  event.stopPropagation();
9410
9762
  if (onMessage) {
9411
9763
  onMessage(button.message);
@@ -9488,7 +9840,7 @@ function Chat(props) {
9488
9840
  // isExperimental = false,
9489
9841
  // TODO: [๐Ÿ˜…]> isSaveButtonEnabled = false,
9490
9842
  // exportHeaderMarkdown,
9491
- participants = [], extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, } = props;
9843
+ participants = [], extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, onCreateAgent, } = props;
9492
9844
  const buttonColor = useMemo(() => Color.from(buttonColorRaw || '#0066cc'), [buttonColorRaw]);
9493
9845
  // Use the auto-scroll hook
9494
9846
  const { isAutoScrolling, chatMessagesRef, handleScroll, handleMessagesChange, scrollToBottom, isMobile: isMobileFromHook, } = useChatAutoScroll();
@@ -9703,7 +10055,7 @@ function Chat(props) {
9703
10055
  }
9704
10056
  }, [ratingModalOpen, isMobile]);
9705
10057
  // Determine alignment for actions (Reset button) based on the first message
9706
- const firstMessageFromUser = ((_a = messages[0]) === null || _a === void 0 ? void 0 : _a.from) === 'USER';
10058
+ const firstMessageFromUser = ((_a = messages[0]) === null || _a === void 0 ? void 0 : _a.sender) === 'USER';
9707
10059
  const actionsAlignmentClass = firstMessageFromUser
9708
10060
  ? chatStyles.actions + ' ' + chatStyles.left
9709
10061
  : chatStyles.actions + ' ' + chatStyles.right;
@@ -9780,11 +10132,11 @@ function Chat(props) {
9780
10132
  }
9781
10133
  return true;
9782
10134
  })() && chatStyles.hasActionsAndFirstMessageIsLong), ref: chatMessagesRef, onScroll: handleScroll, children: [postprocessedMessages.map((message, i) => {
9783
- const participant = participants.find((participant) => participant.name === message.from);
10135
+ const participant = participants.find((participant) => participant.name === message.sender);
9784
10136
  const isLastMessage = i === postprocessedMessages.length - 1;
9785
10137
  const isExpanded = expandedMessageId === message.id;
9786
10138
  const currentRating = messageRatings.get(message.id || message.content /* <-[๐Ÿ’ƒ] */) || 0;
9787
- return (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));
10139
+ return (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));
9788
10140
  }), jsx("div", {
9789
10141
  // Note: Extra space at bottom for input area
9790
10142
  style: { height: 100 } })] }), onMessage && (jsxs("div", { className: classNames(chatStyles.chatInput, useChatCssClassName('chatInput'), isDragOver && chatStyles.dragOver), ...(onFileUpload
@@ -9872,13 +10224,13 @@ function Chat(props) {
9872
10224
  const idx = postprocessedMessages.findIndex((m) => m.id === selectedMessage.id);
9873
10225
  if (idx > 0) {
9874
10226
  const prev = postprocessedMessages[idx - 1];
9875
- if (prev.from === 'USER') {
10227
+ if (prev.sender === 'USER') {
9876
10228
  return prev.content;
9877
10229
  }
9878
10230
  }
9879
10231
  // fallback: find last USER message before selectedMessage
9880
10232
  for (let i = messages.findIndex((m) => m.id === selectedMessage.id) - 1; i >= 0; i--) {
9881
- if (messages[i].from === 'USER') {
10233
+ if (messages[i].sender === 'USER') {
9882
10234
  return messages[i].content;
9883
10235
  }
9884
10236
  }
@@ -9905,7 +10257,9 @@ class ChatPersistence {
9905
10257
  try {
9906
10258
  const serializableMessages = messages.map((message) => ({
9907
10259
  ...message,
9908
- date: (message.date || new Date()).toISOString(),
10260
+ createdAt: (typeof message.createdAt === 'string'
10261
+ ? new Date(message.createdAt)
10262
+ : message.createdAt || new Date()).toISOString(),
9909
10263
  }));
9910
10264
  const storageKey = this.STORAGE_PREFIX + persistenceKey;
9911
10265
  localStorage.setItem(storageKey, JSON.stringify(serializableMessages));
@@ -9928,7 +10282,7 @@ class ChatPersistence {
9928
10282
  // Convert date strings back to Date objects
9929
10283
  return serializableMessages.map((message) => ({
9930
10284
  ...message,
9931
- date: new Date(message.date),
10285
+ createdAt: new Date(message.createdAt),
9932
10286
  }));
9933
10287
  }
9934
10288
  catch (error) {
@@ -9981,7 +10335,7 @@ function LlmChat(props) {
9981
10335
  const { llmTools, persistenceKey, onChange, onReset, initialMessages, sendMessage, userParticipantName = 'USER', llmParticipantName = 'ASSISTANT', autoExecuteMessage, buttonColor, ...restProps } = props;
9982
10336
  // Internal state management
9983
10337
  // DRY: Single factory for seeding initial messages (used on mount and after reset)
9984
- const buildInitialMessages = useCallback(() => (initialMessages ? [...initialMessages] : []), [initialMessages]);
10338
+ const buildInitialMessages = useCallback(() => initialMessages ? ([...initialMessages]) : ([]), [initialMessages]);
9985
10339
  const [messages, setMessages] = useState(() => buildInitialMessages());
9986
10340
  const [tasksProgress, setTasksProgress] = useState([]);
9987
10341
  const [isVoiceCalling, setIsVoiceCalling] = useState(false);
@@ -10074,17 +10428,19 @@ function LlmChat(props) {
10074
10428
  setTasksProgress([{ id: taskId, name: 'Playing response...', progress: 100 }]);
10075
10429
  const now = Date.now();
10076
10430
  const userMessage = {
10431
+ // channel: 'PROMPTBOOK_CHAT',
10077
10432
  id: `user_${now}`,
10078
- date: new Date(),
10079
- from: userParticipantName,
10433
+ createdAt: new Date(),
10434
+ sender: userParticipantName,
10080
10435
  content: (result.userMessage || '(Voice message)'),
10081
10436
  isComplete: true,
10082
10437
  isVoiceCall: true,
10083
10438
  };
10084
10439
  const agentMessage = {
10440
+ // channel: 'PROMPTBOOK_CHAT',
10085
10441
  id: `agent_${now}`,
10086
- date: new Date(),
10087
- from: llmParticipantName,
10442
+ createdAt: new Date(),
10443
+ sender: llmParticipantName,
10088
10444
  content: (result.agentMessage || result.text),
10089
10445
  isComplete: true,
10090
10446
  isVoiceCall: true,
@@ -10181,9 +10537,10 @@ function LlmChat(props) {
10181
10537
  hasUserInteractedRef.current = true;
10182
10538
  // Add user message
10183
10539
  const userMessage = {
10540
+ // channel: 'PROMPTBOOK_CHAT',
10184
10541
  id: `user_${Date.now()}`,
10185
- date: new Date(),
10186
- from: userParticipantName,
10542
+ createdAt: new Date(),
10543
+ sender: userParticipantName,
10187
10544
  content: messageContent,
10188
10545
  isComplete: true,
10189
10546
  };
@@ -10195,9 +10552,10 @@ function LlmChat(props) {
10195
10552
  }
10196
10553
  // Add loading message for assistant
10197
10554
  const loadingMessage = {
10555
+ // channel: 'PROMPTBOOK_CHAT',
10198
10556
  id: `assistant_${Date.now()}`,
10199
- date: new Date(),
10200
- from: llmParticipantName,
10557
+ createdAt: new Date(),
10558
+ sender: llmParticipantName,
10201
10559
  content: 'Thinking...',
10202
10560
  isComplete: false,
10203
10561
  };
@@ -10228,9 +10586,10 @@ function LlmChat(props) {
10228
10586
  if (llmTools.callChatModelStream) {
10229
10587
  result = await llmTools.callChatModelStream(prompt, (chunk) => {
10230
10588
  const assistantMessage = {
10589
+ // channel: 'PROMPTBOOK_CHAT',
10231
10590
  id: loadingMessage.id,
10232
- date: new Date(),
10233
- from: llmParticipantName,
10591
+ createdAt: new Date(),
10592
+ sender: llmParticipantName,
10234
10593
  content: chunk.content,
10235
10594
  isComplete: false,
10236
10595
  };
@@ -10251,9 +10610,10 @@ function LlmChat(props) {
10251
10610
  setTasksProgress([{ id: taskId, name: 'Response generated', progress: 100 }]);
10252
10611
  // Replace loading message with actual response
10253
10612
  const assistantMessage = {
10613
+ // channel: 'PROMPTBOOK_CHAT',
10254
10614
  id: loadingMessage.id,
10255
- date: new Date(),
10256
- from: llmParticipantName,
10615
+ createdAt: new Date(),
10616
+ sender: llmParticipantName,
10257
10617
  content: result.content,
10258
10618
  isComplete: true,
10259
10619
  };
@@ -10272,9 +10632,10 @@ function LlmChat(props) {
10272
10632
  console.error('Error calling LLM:', error);
10273
10633
  // Replace loading message with error message
10274
10634
  const errorMessage = {
10635
+ // channel: 'PROMPTBOOK_CHAT',
10275
10636
  id: loadingMessage.id,
10276
- date: new Date(),
10277
- from: llmParticipantName,
10637
+ createdAt: new Date(),
10638
+ sender: llmParticipantName,
10278
10639
  content: `Sorry, I encountered an error: ${error instanceof Error ? error.message : 'Unknown error'}`,
10279
10640
  isComplete: true,
10280
10641
  };
@@ -10341,7 +10702,8 @@ function AgentChat(props) {
10341
10702
  return (jsx(Fragment, { children: 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
10342
10703
  , initialMessages: [
10343
10704
  {
10344
- from: 'AGENT',
10705
+ // channel: 'PROMPTBOOK_CHAT',
10706
+ sender: 'AGENT',
10345
10707
  content: agent.initialMessage ||
10346
10708
  spaceTrim$2(`
10347
10709
 
@@ -10619,7 +10981,7 @@ function MockedChat(props) {
10619
10981
  if (delays.longPauseChance &&
10620
10982
  Math.random() < delays.longPauseChance &&
10621
10983
  i > 0 &&
10622
- originalMessages[i].from !== originalMessages[i - 1].from) {
10984
+ originalMessages[i].sender !== originalMessages[i - 1].sender) {
10623
10985
  await forTime(getDelay(delays.longPauseDuration, 2000));
10624
10986
  didLongPause = true;
10625
10987
  if (isCancelled)
@@ -10640,9 +11002,10 @@ function MockedChat(props) {
10640
11002
  }
10641
11003
  // Show incomplete message first (for typing effect)
10642
11004
  const incompleteMessage = {
11005
+ // channel: 'PROMPTBOOK_CHAT',
10643
11006
  id: currentMessage.id,
10644
- date: currentMessage.date,
10645
- from: currentMessage.from,
11007
+ createdAt: currentMessage.createdAt,
11008
+ sender: currentMessage.sender,
10646
11009
  content: '',
10647
11010
  isComplete: false,
10648
11011
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10660,9 +11023,10 @@ function MockedChat(props) {
10660
11023
  currentContent += (wordIndex > 0 ? ' ' : '') + word;
10661
11024
  // Update the message with current content
10662
11025
  const updatingMessage = {
11026
+ // channel: 'PROMPTBOOK_CHAT',
10663
11027
  id: currentMessage.id,
10664
- date: currentMessage.date,
10665
- from: currentMessage.from,
11028
+ createdAt: currentMessage.createdAt,
11029
+ sender: currentMessage.sender,
10666
11030
  content: currentContent,
10667
11031
  isComplete: false,
10668
11032
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10680,9 +11044,10 @@ function MockedChat(props) {
10680
11044
  }
10681
11045
  // Mark message as complete
10682
11046
  const completeMessage = {
11047
+ // channel: 'PROMPTBOOK_CHAT',
10683
11048
  id: currentMessage.id,
10684
- date: currentMessage.date,
10685
- from: currentMessage.from,
11049
+ createdAt: currentMessage.createdAt,
11050
+ sender: currentMessage.sender,
10686
11051
  content: currentMessage.content,
10687
11052
  isComplete: true,
10688
11053
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10934,6 +11299,12 @@ class MultipleLlmExecutionTools {
10934
11299
  callEmbeddingModel(prompt) {
10935
11300
  return this.callCommonModel(prompt);
10936
11301
  }
11302
+ /**
11303
+ * Calls the best available embedding model
11304
+ */
11305
+ callImageGenerationModel(prompt) {
11306
+ return this.callCommonModel(prompt);
11307
+ }
10937
11308
  // <- Note: [๐Ÿค–]
10938
11309
  /**
10939
11310
  * Calls the best available model
@@ -10960,6 +11331,11 @@ class MultipleLlmExecutionTools {
10960
11331
  continue llm;
10961
11332
  }
10962
11333
  return await llmExecutionTools.callEmbeddingModel(prompt);
11334
+ case 'IMAGE_GENERATION':
11335
+ if (llmExecutionTools.callImageGenerationModel === undefined) {
11336
+ continue llm;
11337
+ }
11338
+ return await llmExecutionTools.callImageGenerationModel(prompt);
10963
11339
  // <- case [๐Ÿค–]:
10964
11340
  default:
10965
11341
  throw new UnexpectedError(`Unknown model variant "${prompt.modelRequirements.modelVariant}" in ${llmExecutionTools.title}`);
@@ -12134,6 +12510,15 @@ function countUsage(llmTools) {
12134
12510
  return promptResult;
12135
12511
  };
12136
12512
  }
12513
+ if (llmTools.callImageGenerationModel !== undefined) {
12514
+ proxyTools.callImageGenerationModel = async (prompt) => {
12515
+ // console.info('[๐Ÿš•] callImageGenerationModel through countTotalUsage');
12516
+ const promptResult = await llmTools.callImageGenerationModel(prompt);
12517
+ totalUsage = addUsage(totalUsage, promptResult.usage);
12518
+ spending.next(promptResult.usage);
12519
+ return promptResult;
12520
+ };
12521
+ }
12137
12522
  // <- Note: [๐Ÿค–]
12138
12523
  return proxyTools;
12139
12524
  }
@@ -12142,7 +12527,7 @@ function countUsage(llmTools) {
12142
12527
  * TODO: [๐Ÿง ] Is there some meaningfull way how to test this util
12143
12528
  * TODO: [๐Ÿง ][๐ŸŒฏ] Maybe a way how to hide ability to `get totalUsage`
12144
12529
  * > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
12145
- * TODO: [๐Ÿ‘ทโ€โ™‚๏ธ] @@@ Manual about construction of llmTools
12530
+ * TODO: [๐Ÿ‘ทโ€โ™‚๏ธ] Write a comprehensive manual explaining the construction and usage of LLM tools in the Promptbook ecosystem
12146
12531
  */
12147
12532
 
12148
12533
  /**
@@ -13677,8 +14062,9 @@ async function executeAttempts(options) {
13677
14062
  $ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
13678
14063
  break variant;
13679
14064
  case 'EMBEDDING':
14065
+ case 'IMAGE_GENERATION':
13680
14066
  throw new PipelineExecutionError(spaceTrim$1((block) => `
13681
- Embedding model can not be used in pipeline
14067
+ ${modelRequirements.modelVariant} model can not be used in pipeline
13682
14068
 
13683
14069
  This should be catched during parsing
13684
14070
 
@@ -14994,7 +15380,12 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
14994
15380
  };
14995
15381
  }
14996
15382
  // Apply each commitment in order using reduce-like pattern
14997
- for (const commitment of filteredCommitments) {
15383
+ for (let i = 0; i < filteredCommitments.length; i++) {
15384
+ const commitment = filteredCommitments[i];
15385
+ // CLOSED commitment should work only if its the last commitment in the book
15386
+ if (commitment.type === 'CLOSED' && i !== filteredCommitments.length - 1) {
15387
+ continue;
15388
+ }
14998
15389
  const definition = getCommitmentDefinition(commitment.type);
14999
15390
  if (definition) {
15000
15391
  try {
@@ -16009,7 +16400,7 @@ class OpenAiCompatibleExecutionTools {
16009
16400
  let threadMessages = [];
16010
16401
  if ('thread' in prompt && Array.isArray(prompt.thread)) {
16011
16402
  threadMessages = prompt.thread.map((msg) => ({
16012
- role: msg.role === 'assistant' ? 'assistant' : 'user',
16403
+ role: msg.sender === 'assistant' ? 'assistant' : 'user',
16013
16404
  content: msg.content,
16014
16405
  }));
16015
16406
  }
@@ -16422,13 +16813,14 @@ class OpenAiCompatibleExecutionTools {
16422
16813
  const modelName = currentModelRequirements.modelName || this.getDefaultImageGenerationModel().modelName;
16423
16814
  const modelSettings = {
16424
16815
  model: modelName,
16425
- // size: currentModelRequirements.size,
16426
- // quality: currentModelRequirements.quality,
16427
- // style: currentModelRequirements.style,
16816
+ size: currentModelRequirements.size,
16817
+ quality: currentModelRequirements.quality,
16818
+ style: currentModelRequirements.style,
16428
16819
  };
16429
16820
  const rawPromptContent = templateParameters(content, { ...parameters, modelName });
16430
16821
  const rawRequest = {
16431
16822
  ...modelSettings,
16823
+ size: modelSettings.size || '1024x1024',
16432
16824
  prompt: rawPromptContent,
16433
16825
  user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
16434
16826
  response_format: 'url', // TODO: [๐Ÿง ] Maybe allow b64_json
@@ -17447,6 +17839,11 @@ class Agent extends AgentLlmExecutionTools {
17447
17839
  * Links found in the agent source
17448
17840
  */
17449
17841
  this.links = [];
17842
+ /**
17843
+ * Capabilities of the agent
17844
+ * This is parsed from commitments like USE BROWSER, USE SEARCH ENGINE, KNOWLEDGE, etc.
17845
+ */
17846
+ this.capabilities = [];
17450
17847
  /**
17451
17848
  * Metadata like image or color
17452
17849
  */
@@ -17456,11 +17853,12 @@ class Agent extends AgentLlmExecutionTools {
17456
17853
  this.agentSource = agentSource;
17457
17854
  this.agentSource.subscribe((source) => {
17458
17855
  this.updateAgentSource(source);
17459
- const { agentName, personaDescription, initialMessage, links, meta } = parseAgentSource(source);
17856
+ const { agentName, personaDescription, initialMessage, links, meta, capabilities } = parseAgentSource(source);
17460
17857
  this._agentName = agentName;
17461
17858
  this.personaDescription = personaDescription;
17462
17859
  this.initialMessage = initialMessage;
17463
17860
  this.links = links;
17861
+ this.capabilities = capabilities;
17464
17862
  this.meta = { ...this.meta, ...meta };
17465
17863
  });
17466
17864
  }
@@ -17534,9 +17932,52 @@ class Agent extends AgentLlmExecutionTools {
17534
17932
  ${block(result.content)}
17535
17933
 
17536
17934
  `);
17935
+ // Extract knowledge
17936
+ let knowledgeBlock = '';
17937
+ try {
17938
+ const extractionPrompt = {
17939
+ title: 'Knowledge Extraction',
17940
+ modelRequirements: {
17941
+ modelVariant: 'CHAT',
17942
+ },
17943
+ content: spaceTrim$2((block) => `
17944
+ You are an AI agent that is learning from a conversation.
17945
+
17946
+ Here is the conversation so far:
17947
+
17948
+ User: ${block(prompt.content)}
17949
+ Agent: ${block(result.content)}
17950
+
17951
+ Extract any new knowledge, facts, or important information that should be remembered for future interactions.
17952
+ Format the output as a list of KNOWLEDGE blocks.
17953
+ If there is no new knowledge, return nothing.
17954
+
17955
+ Example output:
17956
+ KNOWLEDGE The user's name is Alice.
17957
+ KNOWLEDGE The project deadline is next Friday.
17958
+ `),
17959
+ pipelineUrl: 'https://github.com/webgptorg/promptbook/blob/main/prompts/knowledge-extraction.ptbk.md',
17960
+ parameters: {},
17961
+ };
17962
+ if (this.options.llmTools.callChatModel) {
17963
+ const extractionResult = await this.options.llmTools.callChatModel(extractionPrompt);
17964
+ const extractedContent = extractionResult.content;
17965
+ if (extractedContent.includes('KNOWLEDGE')) {
17966
+ knowledgeBlock = '\n\n' + spaceTrim$2(extractedContent);
17967
+ }
17968
+ }
17969
+ else {
17970
+ // TODO: [๐Ÿง ] Fallback to callChatModelStream if callChatModel is not available
17971
+ }
17972
+ }
17973
+ catch (error) {
17974
+ if (this.options.isVerbose) {
17975
+ console.warn('Failed to extract knowledge', error);
17976
+ }
17977
+ }
17537
17978
  // Append to the current source
17538
17979
  const currentSource = this.agentSource.value;
17539
- const newSource = padBook(validateBook(spaceTrim$2(currentSource) + '\n\n' + learningExample));
17980
+ const newSource = padBook(validateBook(spaceTrim$2(currentSource) + '\n\n' + learningExample + knowledgeBlock));
17540
17981
  // Update the source (which will trigger the subscription and update the underlying tools)
17541
17982
  this.agentSource.next(newSource);
17542
17983
  return result;
@@ -17810,7 +18251,8 @@ function PromptbookAgentSeamlessIntegration(props) {
17810
18251
  // TODO: [๐Ÿง ] Handle error state (show error message in the chat window)
17811
18252
  const image = ((_a = agent === null || agent === void 0 ? void 0 : agent.meta) === null || _a === void 0 ? void 0 : _a.image) ||
17812
18253
  (meta === null || meta === void 0 ? void 0 : meta.image) ||
17813
- 'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y';
18254
+ // Note: [๐Ÿคน] Using default avatar from the agent server
18255
+ `${agentUrl}/images/default-avatar.png`;
17814
18256
  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);
17815
18257
  let connectionStatus = 'pending';
17816
18258
  if (agent) {