@promptbook/components 0.104.0-1 โ†’ 0.104.0-10

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 (42) hide show
  1. package/esm/index.es.js +620 -235
  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 +10 -2
  6. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +6 -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 +7 -11
  15. package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +2 -2
  16. package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
  17. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +21 -11
  18. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +80 -14
  19. package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
  20. package/esm/typings/src/commitments/index.d.ts +2 -1
  21. package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
  22. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
  23. package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
  24. package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
  25. package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
  26. package/esm/typings/src/types/Message.d.ts +49 -0
  27. package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
  28. package/esm/typings/src/types/typeAliases.d.ts +23 -1
  29. package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
  30. package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
  31. package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
  32. package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
  33. package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
  34. package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
  35. package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
  36. package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
  37. package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
  38. package/esm/typings/src/version.d.ts +1 -1
  39. package/package.json +1 -2
  40. package/umd/index.umd.js +628 -244
  41. package/umd/index.umd.js.map +1 -1
  42. 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-10';
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;
@@ -7223,10 +7347,6 @@ function parseAgentSource(agentSource) {
7223
7347
  const metaType = normalizeTo_camelCase(metaTypeRaw);
7224
7348
  meta[metaType] = spaceTrim$2(commitment.content.substring(metaTypeRaw.length));
7225
7349
  }
7226
- // Generate gravatar fallback if no meta image specified
7227
- if (!meta.image) {
7228
- meta.image = generatePlaceholderAgentProfileImageUrl(parseResult.agentName || '!!');
7229
- }
7230
7350
  // Generate fullname fallback if no meta fullname specified
7231
7351
  if (!meta.fullname) {
7232
7352
  meta.fullname = parseResult.agentName || createDefaultAgentName(agentSource);
@@ -7238,6 +7358,7 @@ function parseAgentSource(agentSource) {
7238
7358
  return {
7239
7359
  agentName: normalizeAgentName(parseResult.agentName || createDefaultAgentName(agentSource)),
7240
7360
  agentHash,
7361
+ permanentId: meta.id,
7241
7362
  personaDescription,
7242
7363
  initialMessage,
7243
7364
  meta,
@@ -7277,9 +7398,9 @@ function AvatarChipFromSource(props) {
7277
7398
  return jsx(AvatarChip, { avatarBasicInformation: avatarBasicInformation, ...props });
7278
7399
  }
7279
7400
 
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);
7401
+ 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= */";
7402
+ var styles$8 = {"scrim":"Modal-module_scrim__jKO-A","Modal":"Modal-module_Modal__k49dY","closeButton":"Modal-module_closeButton__dzf6l"};
7403
+ styleInject(css_248z$9);
7283
7404
 
7284
7405
  /**
7285
7406
  *
@@ -7297,7 +7418,7 @@ function Modal({ children, onClose, className, }) {
7297
7418
  window.removeEventListener('keydown', handleKeyDown);
7298
7419
  };
7299
7420
  }, [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);
7421
+ 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
7422
  }
7302
7423
 
7303
7424
  /**
@@ -7382,9 +7503,9 @@ const DEFAULT_BOOK = padBook(validateBook(spaceTrim$2(`
7382
7503
  // <- [๐Ÿฑโ€๐Ÿš€] Buttons into genesis book
7383
7504
  // <- TODO: [๐Ÿฑโ€๐Ÿš€] generateBookBoilerplate and deprecate `DEFAULT_BOOK`
7384
7505
 
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);
7506
+ 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 */";
7507
+ 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"};
7508
+ styleInject(css_248z$8);
7388
7509
 
7389
7510
  /**
7390
7511
  * Converts Blob, File or MediaSource to url using URL.createObjectURL
@@ -7504,6 +7625,101 @@ async function $induceBookDownload(book) {
7504
7625
  * Note: [๐Ÿ”ต] Code in this file should never be published outside of `@promptbook/browser`
7505
7626
  */
7506
7627
 
7628
+ /**
7629
+ * Downloads a file with the given content and filename
7630
+ *
7631
+ * @private utility of `<Chat/>` component
7632
+ */
7633
+ function downloadFile(content, filename, mimeType) {
7634
+ const blob = new Blob([content], { type: mimeType });
7635
+ const url = URL.createObjectURL(blob);
7636
+ const link = document.createElement('a');
7637
+ link.href = url;
7638
+ link.download = filename;
7639
+ document.body.appendChild(link);
7640
+ link.click();
7641
+ document.body.removeChild(link);
7642
+ // Clean up the URL object
7643
+ setTimeout(() => URL.revokeObjectURL(url), 100);
7644
+ }
7645
+
7646
+ 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= */";
7647
+ 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"};
7648
+ styleInject(css_248z$7);
7649
+
7650
+ const LANGUAGE_EXTENSIONS = {
7651
+ python: 'py',
7652
+ javascript: 'js',
7653
+ typescript: 'ts',
7654
+ json: 'json',
7655
+ html: 'html',
7656
+ css: 'css',
7657
+ markdown: 'md',
7658
+ text: 'txt',
7659
+ xml: 'xml',
7660
+ sql: 'sql',
7661
+ sh: 'sh',
7662
+ bash: 'sh',
7663
+ zsh: 'sh',
7664
+ yaml: 'yaml',
7665
+ yml: 'yaml',
7666
+ book: 'book',
7667
+ };
7668
+ /**
7669
+ * Component to render a code block with syntax highlighting, copy, download, and create agent options.
7670
+ *
7671
+ * @private Internal utility of `<ChatMessage />` component
7672
+ */
7673
+ function CodeBlock({ code, language, className, onCreateAgent }) {
7674
+ const lines = useMemo(() => code.split('\n').length, [code]);
7675
+ // Note: 19px is approx line height for fontSize 14. +20 for padding.
7676
+ // We cap at 400px to avoid taking too much space, allowing scroll.
7677
+ const height = Math.min(Math.max(lines * 19, 19), 400);
7678
+ const [copied, setCopied] = useState(false);
7679
+ const handleDownload = () => {
7680
+ const lang = (language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) || 'text';
7681
+ const extension = LANGUAGE_EXTENSIONS[lang] || lang;
7682
+ const filename = `file.${extension}`;
7683
+ downloadFile(code, filename, 'text/plain');
7684
+ };
7685
+ const handleCopy = async () => {
7686
+ try {
7687
+ await navigator.clipboard.writeText(code);
7688
+ setCopied(true);
7689
+ setTimeout(() => setCopied(false), 2000);
7690
+ }
7691
+ catch (error) {
7692
+ console.error('Failed to copy code to clipboard:', error);
7693
+ }
7694
+ };
7695
+ 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;
7696
+ if ((language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) === 'book') {
7697
+ 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 */ })] }));
7698
+ }
7699
+ 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: {
7700
+ readOnly: true,
7701
+ minimap: { enabled: false },
7702
+ scrollBeyondLastLine: false,
7703
+ lineNumbers: 'on',
7704
+ folding: false,
7705
+ glyphMargin: false,
7706
+ fontFamily: 'Consolas, "Courier New", monospace',
7707
+ fontSize: 14,
7708
+ lineHeight: 19,
7709
+ overviewRulerLanes: 0,
7710
+ hideCursorInOverviewRuler: true,
7711
+ renderLineHighlight: 'none',
7712
+ contextmenu: false,
7713
+ scrollbar: {
7714
+ vertical: 'auto',
7715
+ horizontal: 'auto',
7716
+ useShadows: false,
7717
+ },
7718
+ domReadOnly: true,
7719
+ wordWrap: 'off',
7720
+ } })] }));
7721
+ }
7722
+
7507
7723
  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
7724
  var styles$5 = {"MarkdownContent":"MarkdownContent-module_MarkdownContent__2JuyX","chat-code-block":"MarkdownContent-module_chat-code-block__ZffFg","citation":"MarkdownContent-module_citation__11SMw"};
7509
7725
  styleInject(css_248z$6);
@@ -7606,32 +7822,8 @@ function renderMarkdown(markdown) {
7606
7822
  }
7607
7823
  try {
7608
7824
  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
- }
7825
+ const html = chatMarkdownConverter.makeHtml(processedMarkdown);
7826
+ if (typeof window !== 'undefined') {
7635
7827
  if (html.match(/class="katex/)) {
7636
7828
  const katexCssId = 'katex-css';
7637
7829
  if (!window.document.getElementById(katexCssId)) {
@@ -7642,38 +7834,6 @@ function renderMarkdown(markdown) {
7642
7834
  window.document.head.appendChild(link);
7643
7835
  }
7644
7836
  }
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
7837
  }
7678
7838
  const sanitizedHtml = html
7679
7839
  .replace(/<\s*(script|style|iframe|object|embed)[^>]*>[\s\S]*?<\s*\/\s*\1\s*>/gi, '')
@@ -7703,9 +7863,50 @@ function renderMarkdown(markdown) {
7703
7863
  * @public exported from `@promptbook/components`
7704
7864
  */
7705
7865
  function MarkdownContent(props) {
7706
- const { content, className } = props;
7866
+ const { content, className, onCreateAgent } = props;
7707
7867
  const htmlContent = useMemo(() => renderMarkdown(content), [content]);
7708
- return (jsx("div", { className: classNames(styles$5.MarkdownContent, className), dangerouslySetInnerHTML: {
7868
+ const containerRef = useRef(null);
7869
+ const rootsRef = useRef([]);
7870
+ useEffect(() => {
7871
+ // Cleanup previous roots
7872
+ rootsRef.current.forEach((root) => root.unmount());
7873
+ rootsRef.current = [];
7874
+ if (!containerRef.current) {
7875
+ return;
7876
+ }
7877
+ const preElements = containerRef.current.querySelectorAll('pre');
7878
+ preElements.forEach((pre) => {
7879
+ // Check if it is a code block (has code element)
7880
+ const codeElement = pre.querySelector('code');
7881
+ if (!codeElement) {
7882
+ return;
7883
+ }
7884
+ // Get language and code
7885
+ const className = codeElement.className; // e.g. language-python
7886
+ const match = className.match(/language-([^\s]+)/);
7887
+ const language = match ? match[1] : undefined;
7888
+ const code = codeElement.textContent || '';
7889
+ // Clear the pre element content
7890
+ pre.innerHTML = '';
7891
+ pre.className = ''; // remove existing classes if any
7892
+ pre.style.background = 'none'; // reset styles
7893
+ pre.style.padding = '0';
7894
+ pre.style.margin = '0';
7895
+ pre.style.overflow = 'visible';
7896
+ // Create a container for the CodeBlock
7897
+ const mountPoint = document.createElement('div');
7898
+ pre.appendChild(mountPoint);
7899
+ // Render CodeBlock
7900
+ const root = createRoot(mountPoint);
7901
+ root.render(jsx(CodeBlock, { code: code, language: language, onCreateAgent: onCreateAgent }));
7902
+ rootsRef.current.push(root);
7903
+ });
7904
+ return () => {
7905
+ rootsRef.current.forEach((root) => root.unmount());
7906
+ rootsRef.current = [];
7907
+ };
7908
+ }, [htmlContent, onCreateAgent]);
7909
+ return (jsx("div", { ref: containerRef, className: classNames(styles$5.MarkdownContent, className), dangerouslySetInnerHTML: {
7709
7910
  __html: htmlContent,
7710
7911
  } }));
7711
7912
  }
@@ -7922,6 +8123,16 @@ function Dropdown({ actions }) {
7922
8123
  }, children: [icon, jsx("span", { children: name })] }, name))) }))] }));
7923
8124
  }
7924
8125
 
8126
+ const MenuHoistingContext = createContext(null);
8127
+ /**
8128
+ * Hook to use the menu hoisting system
8129
+ *
8130
+ * @private mechanism inside Promptbook
8131
+ */
8132
+ function useMenuHoisting() {
8133
+ return useContext(MenuHoistingContext);
8134
+ }
8135
+
7925
8136
  /**
7926
8137
  *
7927
8138
  * @private Internal component used by `BookEditor`
@@ -7929,50 +8140,83 @@ function Dropdown({ actions }) {
7929
8140
  function BookEditorActionbar(props) {
7930
8141
  const { value, isDownloadButtonShown, isUploadButtonShown, isCameraButtonShown, isAboutButtonShown, isFullscreenButtonShown, onFullscreenClick, onUploadDocument, onTakePhoto, isFullscreen, } = props;
7931
8142
  const [isAboutModalOpen, setIsAboutModalOpen] = useState(false);
7932
- const handleDownload = () => {
7933
- const book = validateBook(value || DEFAULT_BOOK);
8143
+ const menuHoisting = useMenuHoisting();
8144
+ // Note: [1] We use ref to avoid re-creating the handleDownload function (and thus the actions array) on every value change
8145
+ const valueRef = useRef(value);
8146
+ useEffect(() => {
8147
+ valueRef.current = value;
8148
+ }, [value]);
8149
+ const handleDownload = useCallback(() => {
8150
+ const book = validateBook(valueRef.current || DEFAULT_BOOK);
7934
8151
  /* 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
- }
8152
+ }, []);
8153
+ const actions = useMemo(() => {
8154
+ const _actions = [];
8155
+ if (isUploadButtonShown && onUploadDocument) {
8156
+ _actions.push({
8157
+ icon: jsx(AttachmentIcon, {}),
8158
+ name: 'Upload document',
8159
+ onClick: onUploadDocument,
8160
+ });
8161
+ }
8162
+ if (isCameraButtonShown && onTakePhoto) {
8163
+ _actions.push({
8164
+ icon: jsx(CameraIcon, {}),
8165
+ name: 'Take photo',
8166
+ onClick: onTakePhoto,
8167
+ });
8168
+ }
8169
+ if (isDownloadButtonShown) {
8170
+ _actions.push({
8171
+ icon: jsx(DownloadIcon, {}),
8172
+ name: 'Download',
8173
+ onClick: handleDownload,
8174
+ });
8175
+ }
8176
+ if (isAboutButtonShown) {
8177
+ _actions.push({
8178
+ icon: jsx(AboutIcon, {}),
8179
+ name: 'About',
8180
+ onClick: () => setIsAboutModalOpen(true),
8181
+ });
8182
+ }
8183
+ if (isFullscreenButtonShown && onFullscreenClick) {
8184
+ _actions.push({
8185
+ icon: jsx(FullscreenIcon, {}),
8186
+ name: 'Fullscreen',
8187
+ onClick: onFullscreenClick,
8188
+ });
8189
+ }
8190
+ return _actions;
8191
+ }, [
8192
+ isUploadButtonShown,
8193
+ onUploadDocument,
8194
+ isCameraButtonShown,
8195
+ onTakePhoto,
8196
+ isDownloadButtonShown,
8197
+ handleDownload,
8198
+ isAboutButtonShown,
8199
+ isFullscreenButtonShown,
8200
+ onFullscreenClick,
8201
+ ]);
8202
+ useEffect(() => {
8203
+ if (!menuHoisting || isFullscreen) {
8204
+ return;
8205
+ }
8206
+ menuHoisting.setMenu(actions);
8207
+ return () => {
8208
+ menuHoisting.setMenu([]);
8209
+ };
8210
+ }, [menuHoisting, actions, isFullscreen]);
7972
8211
  if (isFullscreen) {
7973
- return (jsx("div", { className: styles$6.bookEditorActionbar, children: jsx("button", { className: styles$6.button, onClick: onFullscreenClick, children: jsx(ExitFullscreenIcon, {}) }) }));
8212
+ return (jsx("div", { className: styles$7.bookEditorActionbar, children: jsx("button", { className: styles$7.button, onClick: onFullscreenClick, children: jsx(ExitFullscreenIcon, {}) }) }));
7974
8213
  }
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: () => {
8214
+ if (menuHoisting && !isFullscreen) {
8215
+ return (jsx(Fragment, { children: isAboutModalOpen && (jsx(Modal, { onClose: () => {
8216
+ setIsAboutModalOpen(false);
8217
+ }, children: jsx(AboutPromptbookInformation, {}) })) }));
8218
+ }
8219
+ 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
8220
  setIsAboutModalOpen(false);
7977
8221
  }, children: jsx(AboutPromptbookInformation, {}) }))] }));
7978
8222
  }
@@ -8084,6 +8328,7 @@ function BookEditorMonaco(props) {
8084
8328
  const parameterRegex = /@([a-zA-Z0-9_รก-ลพร-ลฝฤ-ล™ฤŒ-ล˜ลก-ลพล -ลฝะฐ-ัะ-ะฏั‘ะ]+)/;
8085
8329
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8086
8330
  const bookRules = [
8331
+ [/^---[-]*$/, ''],
8087
8332
  [parameterRegex, 'parameter'],
8088
8333
  [/\{[^}]+\}/, 'parameter'],
8089
8334
  [commitmentRegex, 'commitment'],
@@ -8092,7 +8337,12 @@ function BookEditorMonaco(props) {
8092
8337
  const tokenProvider = monaco.languages.setMonarchTokensProvider(BOOK_LANGUAGE_ID, {
8093
8338
  ignoreCase: true,
8094
8339
  tokenizer: {
8095
- root: [[/^.*$/, 'title', '@body']],
8340
+ root: [
8341
+ [/^\s*$/, 'empty'],
8342
+ [/^-*$/, 'line'],
8343
+ [/^.*$/, 'title', '@body'],
8344
+ [commitmentRegex, 'commitment'],
8345
+ ],
8096
8346
  body: bookRules,
8097
8347
  },
8098
8348
  });
@@ -8310,7 +8560,7 @@ function BookEditorMonaco(props) {
8310
8560
  event.preventDefault();
8311
8561
  setIsDragOver(false);
8312
8562
  }, []);
8313
- return (jsxs("div", { className: classNames(styles$6.bookEditorContainer, instanceClass), onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [(isUploadButtonShown ||
8563
+ return (jsxs("div", { className: classNames(styles$7.bookEditorContainer, instanceClass), onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [(isUploadButtonShown ||
8314
8564
  isCameraButtonShown ||
8315
8565
  isDownloadButtonShown ||
8316
8566
  isAboutButtonShown ||
@@ -8323,7 +8573,7 @@ function BookEditorMonaco(props) {
8323
8573
  onFullscreenClick,
8324
8574
  onUploadDocument: handleUploadDocument,
8325
8575
  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: {
8576
+ 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
8577
  position: 'relative',
8328
8578
  flex: 1,
8329
8579
  height: '100%',
@@ -8388,7 +8638,7 @@ function BookEditorMonaco(props) {
8388
8638
  arrowSize: 0,
8389
8639
  useShadows: false,
8390
8640
  },
8391
- }, loading: jsx("div", { className: styles$6.loading, children: "\uD83D\uDCD6" }) })] })] }));
8641
+ }, loading: jsx("div", { className: styles$7.loading, children: "\uD83D\uDCD6" }) })] })] }));
8392
8642
  }
8393
8643
 
8394
8644
  /**
@@ -8410,7 +8660,7 @@ function BookEditor(props) {
8410
8660
  const handleFullscreenToggle = () => {
8411
8661
  setIsFullscreen(!isFullscreen);
8412
8662
  };
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
8663
+ 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
8664
  ? style
8415
8665
  : {
8416
8666
  ...(style || {}),
@@ -8536,6 +8786,52 @@ function furthest(...colors) {
8536
8786
  */
8537
8787
  const textColor = furthest(Color.get('white'), Color.from('black'));
8538
8788
 
8789
+ /**
8790
+ * Makes data url from color
8791
+ *
8792
+ * @public exported from `@promptbook/color`
8793
+ */
8794
+ function colorToDataUrl(color) {
8795
+ if (typeof color === 'string') {
8796
+ color = Color.fromHex(color);
8797
+ }
8798
+ return rgbDataURL(color.red, color.green, color.blue);
8799
+ }
8800
+ /**
8801
+ * Pixel GIF code adapted from https://stackoverflow.com/a/33919020/266535
8802
+ *
8803
+ * @private util of `colorToDataUrl`
8804
+ */
8805
+ const keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
8806
+ /**
8807
+ * Generates a base64-encoded triplet string
8808
+ *
8809
+ * @param e1 - The first element in the triplet.
8810
+ * @param e2 - The second element in the triplet.
8811
+ * @param e3 - The third element in the triplet.
8812
+ * @returns The base64-encoded triplet string.
8813
+ *
8814
+ * @private util of `colorToDataUrl`
8815
+ */
8816
+ const triplet = (e1, e2, e3) => keyStr.charAt(e1 >> 2) +
8817
+ keyStr.charAt(((e1 & 3) << 4) | (e2 >> 4)) +
8818
+ keyStr.charAt(((e2 & 15) << 2) | (e3 >> 6)) +
8819
+ keyStr.charAt(e3 & 63);
8820
+ /**
8821
+ * Converts RGB values to a data URL string
8822
+ *
8823
+ * @param r - The red channel value.
8824
+ * @param g - The green channel value.
8825
+ * @param b - The blue channel value.
8826
+ * @returns The RGB data URL string.
8827
+ *
8828
+ * @private util of `colorToDataUrl`
8829
+ */
8830
+ const rgbDataURL = (r, g, b) => `data:image/gif;base64,R0lGODlhAQABAPAA${triplet(0, r, g) + triplet(b, 255, 255)}/yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==`;
8831
+ /**
8832
+ * TODO: Make as functions NOT const
8833
+ */
8834
+
8539
8835
  /**
8540
8836
  * Restricts an Updatable to a (2) BehaviorSubject variant
8541
8837
  *
@@ -9018,15 +9314,15 @@ const htmlSaveFormatDefinition = {
9018
9314
  ASSISTANT: '#ffb300',
9019
9315
  SYSTEM: '#888',
9020
9316
  };
9021
- const bgColor = participantColors[String(message.from)] || '#2b7cff';
9317
+ const bgColor = participantColors[String(message.sender)] || '#2b7cff';
9022
9318
  const textColor = getTextColor(bgColor);
9023
9319
  return spaceTrim$2(`
9024
9320
  <div class="chat-message">
9025
9321
  <div class="avatar" style="background:${bgColor};color:${getTextColor(bgColor)};">
9026
- ${String(message.from)[0] || '?'}
9322
+ ${String(message.sender)[0] || '?'}
9027
9323
  </div>
9028
9324
  <div class="bubble" style="background:${bgColor};color:${textColor};">
9029
- <span class="from-label">${String(message.from)}:</span>
9325
+ <span class="from-label">${String(message.sender)}:</span>
9030
9326
  ${message.content}
9031
9327
  </div>
9032
9328
  </div>
@@ -9072,7 +9368,7 @@ const mdSaveFormatDefinition = {
9072
9368
  getContent: ({ messages }) => spaceTrim$1(`
9073
9369
  ${messages
9074
9370
  .map((message) => spaceTrim$1(`
9075
- **${message.from}:**
9371
+ **${message.sender}:**
9076
9372
 
9077
9373
  > ${message.content.replace(/\n/g, '\n> ')}
9078
9374
  `))
@@ -9262,8 +9558,8 @@ const AVATAR_SIZE = 40;
9262
9558
  *
9263
9559
  * @private internal subcomponent of `<Chat>` component
9264
9560
  */
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) || '';
9561
+ const ChatMessageItem = memo(({ message, participant, participants, isLastMessage, onMessage, setExpandedMessageId, isExpanded, currentRating, handleRating, mode, isCopyButtonEnabled, isFeedbackEnabled, onCopy, onCreateAgent, }) => {
9562
+ const avatarSrc = (participant === null || participant === void 0 ? void 0 : participant.avatarSrc) || null;
9267
9563
  const [isAvatarTooltipVisible, setIsAvatarTooltipVisible] = useState(false);
9268
9564
  const [avatarTooltipPosition, setAvatarTooltipPosition] = useState(null);
9269
9565
  const hoverTimeoutRef = useRef(null);
@@ -9354,9 +9650,14 @@ const ChatMessageItem = memo(({ message, participant, participants, isLastMessag
9354
9650
  console.info('participant avatarSrc', avatarSrc);
9355
9651
  console.info('participant color', { color, colorOfText });
9356
9652
  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: {
9653
+ }, 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
9654
  '--avatar-bg-color': color.toHex(),
9655
+ objectFit: 'cover',
9656
+ objectPosition: '50% 20%',
9359
9657
  width: AVATAR_SIZE,
9658
+ height: AVATAR_SIZE,
9659
+ aspectRatio: '1 / 1',
9660
+ backgroundImage: `url(${colorToDataUrl(color)})`,
9360
9661
  } }), 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
9662
  '--message-bg-color': color.toHex(),
9362
9663
  '--message-text-color': colorOfText.toHex(),
@@ -9405,7 +9706,7 @@ const ChatMessageItem = memo(({ message, participant, participants, isLastMessag
9405
9706
  ? ' ' + chatStyles.copiedTooltipLeft
9406
9707
  : tooltipAlign === 'right'
9407
9708
  ? ' ' + 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) => {
9709
+ : ''), 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
9710
  event.stopPropagation();
9410
9711
  if (onMessage) {
9411
9712
  onMessage(button.message);
@@ -9488,7 +9789,7 @@ function Chat(props) {
9488
9789
  // isExperimental = false,
9489
9790
  // TODO: [๐Ÿ˜…]> isSaveButtonEnabled = false,
9490
9791
  // exportHeaderMarkdown,
9491
- participants = [], extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, } = props;
9792
+ participants = [], extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, onCreateAgent, } = props;
9492
9793
  const buttonColor = useMemo(() => Color.from(buttonColorRaw || '#0066cc'), [buttonColorRaw]);
9493
9794
  // Use the auto-scroll hook
9494
9795
  const { isAutoScrolling, chatMessagesRef, handleScroll, handleMessagesChange, scrollToBottom, isMobile: isMobileFromHook, } = useChatAutoScroll();
@@ -9703,7 +10004,7 @@ function Chat(props) {
9703
10004
  }
9704
10005
  }, [ratingModalOpen, isMobile]);
9705
10006
  // 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';
10007
+ const firstMessageFromUser = ((_a = messages[0]) === null || _a === void 0 ? void 0 : _a.sender) === 'USER';
9707
10008
  const actionsAlignmentClass = firstMessageFromUser
9708
10009
  ? chatStyles.actions + ' ' + chatStyles.left
9709
10010
  : chatStyles.actions + ' ' + chatStyles.right;
@@ -9780,11 +10081,11 @@ function Chat(props) {
9780
10081
  }
9781
10082
  return true;
9782
10083
  })() && chatStyles.hasActionsAndFirstMessageIsLong), ref: chatMessagesRef, onScroll: handleScroll, children: [postprocessedMessages.map((message, i) => {
9783
- const participant = participants.find((participant) => participant.name === message.from);
10084
+ const participant = participants.find((participant) => participant.name === message.sender);
9784
10085
  const isLastMessage = i === postprocessedMessages.length - 1;
9785
10086
  const isExpanded = expandedMessageId === message.id;
9786
10087
  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));
10088
+ 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
10089
  }), jsx("div", {
9789
10090
  // Note: Extra space at bottom for input area
9790
10091
  style: { height: 100 } })] }), onMessage && (jsxs("div", { className: classNames(chatStyles.chatInput, useChatCssClassName('chatInput'), isDragOver && chatStyles.dragOver), ...(onFileUpload
@@ -9872,13 +10173,13 @@ function Chat(props) {
9872
10173
  const idx = postprocessedMessages.findIndex((m) => m.id === selectedMessage.id);
9873
10174
  if (idx > 0) {
9874
10175
  const prev = postprocessedMessages[idx - 1];
9875
- if (prev.from === 'USER') {
10176
+ if (prev.sender === 'USER') {
9876
10177
  return prev.content;
9877
10178
  }
9878
10179
  }
9879
10180
  // fallback: find last USER message before selectedMessage
9880
10181
  for (let i = messages.findIndex((m) => m.id === selectedMessage.id) - 1; i >= 0; i--) {
9881
- if (messages[i].from === 'USER') {
10182
+ if (messages[i].sender === 'USER') {
9882
10183
  return messages[i].content;
9883
10184
  }
9884
10185
  }
@@ -9905,7 +10206,9 @@ class ChatPersistence {
9905
10206
  try {
9906
10207
  const serializableMessages = messages.map((message) => ({
9907
10208
  ...message,
9908
- date: (message.date || new Date()).toISOString(),
10209
+ createdAt: (typeof message.createdAt === 'string'
10210
+ ? new Date(message.createdAt)
10211
+ : message.createdAt || new Date()).toISOString(),
9909
10212
  }));
9910
10213
  const storageKey = this.STORAGE_PREFIX + persistenceKey;
9911
10214
  localStorage.setItem(storageKey, JSON.stringify(serializableMessages));
@@ -9928,7 +10231,7 @@ class ChatPersistence {
9928
10231
  // Convert date strings back to Date objects
9929
10232
  return serializableMessages.map((message) => ({
9930
10233
  ...message,
9931
- date: new Date(message.date),
10234
+ createdAt: new Date(message.createdAt),
9932
10235
  }));
9933
10236
  }
9934
10237
  catch (error) {
@@ -9981,7 +10284,7 @@ function LlmChat(props) {
9981
10284
  const { llmTools, persistenceKey, onChange, onReset, initialMessages, sendMessage, userParticipantName = 'USER', llmParticipantName = 'ASSISTANT', autoExecuteMessage, buttonColor, ...restProps } = props;
9982
10285
  // Internal state management
9983
10286
  // DRY: Single factory for seeding initial messages (used on mount and after reset)
9984
- const buildInitialMessages = useCallback(() => (initialMessages ? [...initialMessages] : []), [initialMessages]);
10287
+ const buildInitialMessages = useCallback(() => initialMessages ? ([...initialMessages]) : ([]), [initialMessages]);
9985
10288
  const [messages, setMessages] = useState(() => buildInitialMessages());
9986
10289
  const [tasksProgress, setTasksProgress] = useState([]);
9987
10290
  const [isVoiceCalling, setIsVoiceCalling] = useState(false);
@@ -10074,17 +10377,19 @@ function LlmChat(props) {
10074
10377
  setTasksProgress([{ id: taskId, name: 'Playing response...', progress: 100 }]);
10075
10378
  const now = Date.now();
10076
10379
  const userMessage = {
10380
+ // channel: 'PROMPTBOOK_CHAT',
10077
10381
  id: `user_${now}`,
10078
- date: new Date(),
10079
- from: userParticipantName,
10382
+ createdAt: new Date(),
10383
+ sender: userParticipantName,
10080
10384
  content: (result.userMessage || '(Voice message)'),
10081
10385
  isComplete: true,
10082
10386
  isVoiceCall: true,
10083
10387
  };
10084
10388
  const agentMessage = {
10389
+ // channel: 'PROMPTBOOK_CHAT',
10085
10390
  id: `agent_${now}`,
10086
- date: new Date(),
10087
- from: llmParticipantName,
10391
+ createdAt: new Date(),
10392
+ sender: llmParticipantName,
10088
10393
  content: (result.agentMessage || result.text),
10089
10394
  isComplete: true,
10090
10395
  isVoiceCall: true,
@@ -10181,9 +10486,10 @@ function LlmChat(props) {
10181
10486
  hasUserInteractedRef.current = true;
10182
10487
  // Add user message
10183
10488
  const userMessage = {
10489
+ // channel: 'PROMPTBOOK_CHAT',
10184
10490
  id: `user_${Date.now()}`,
10185
- date: new Date(),
10186
- from: userParticipantName,
10491
+ createdAt: new Date(),
10492
+ sender: userParticipantName,
10187
10493
  content: messageContent,
10188
10494
  isComplete: true,
10189
10495
  };
@@ -10195,9 +10501,10 @@ function LlmChat(props) {
10195
10501
  }
10196
10502
  // Add loading message for assistant
10197
10503
  const loadingMessage = {
10504
+ // channel: 'PROMPTBOOK_CHAT',
10198
10505
  id: `assistant_${Date.now()}`,
10199
- date: new Date(),
10200
- from: llmParticipantName,
10506
+ createdAt: new Date(),
10507
+ sender: llmParticipantName,
10201
10508
  content: 'Thinking...',
10202
10509
  isComplete: false,
10203
10510
  };
@@ -10228,9 +10535,10 @@ function LlmChat(props) {
10228
10535
  if (llmTools.callChatModelStream) {
10229
10536
  result = await llmTools.callChatModelStream(prompt, (chunk) => {
10230
10537
  const assistantMessage = {
10538
+ // channel: 'PROMPTBOOK_CHAT',
10231
10539
  id: loadingMessage.id,
10232
- date: new Date(),
10233
- from: llmParticipantName,
10540
+ createdAt: new Date(),
10541
+ sender: llmParticipantName,
10234
10542
  content: chunk.content,
10235
10543
  isComplete: false,
10236
10544
  };
@@ -10251,9 +10559,10 @@ function LlmChat(props) {
10251
10559
  setTasksProgress([{ id: taskId, name: 'Response generated', progress: 100 }]);
10252
10560
  // Replace loading message with actual response
10253
10561
  const assistantMessage = {
10562
+ // channel: 'PROMPTBOOK_CHAT',
10254
10563
  id: loadingMessage.id,
10255
- date: new Date(),
10256
- from: llmParticipantName,
10564
+ createdAt: new Date(),
10565
+ sender: llmParticipantName,
10257
10566
  content: result.content,
10258
10567
  isComplete: true,
10259
10568
  };
@@ -10272,9 +10581,10 @@ function LlmChat(props) {
10272
10581
  console.error('Error calling LLM:', error);
10273
10582
  // Replace loading message with error message
10274
10583
  const errorMessage = {
10584
+ // channel: 'PROMPTBOOK_CHAT',
10275
10585
  id: loadingMessage.id,
10276
- date: new Date(),
10277
- from: llmParticipantName,
10586
+ createdAt: new Date(),
10587
+ sender: llmParticipantName,
10278
10588
  content: `Sorry, I encountered an error: ${error instanceof Error ? error.message : 'Unknown error'}`,
10279
10589
  isComplete: true,
10280
10590
  };
@@ -10341,7 +10651,8 @@ function AgentChat(props) {
10341
10651
  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
10652
  , initialMessages: [
10343
10653
  {
10344
- from: 'AGENT',
10654
+ // channel: 'PROMPTBOOK_CHAT',
10655
+ sender: 'AGENT',
10345
10656
  content: agent.initialMessage ||
10346
10657
  spaceTrim$2(`
10347
10658
 
@@ -10619,7 +10930,7 @@ function MockedChat(props) {
10619
10930
  if (delays.longPauseChance &&
10620
10931
  Math.random() < delays.longPauseChance &&
10621
10932
  i > 0 &&
10622
- originalMessages[i].from !== originalMessages[i - 1].from) {
10933
+ originalMessages[i].sender !== originalMessages[i - 1].sender) {
10623
10934
  await forTime(getDelay(delays.longPauseDuration, 2000));
10624
10935
  didLongPause = true;
10625
10936
  if (isCancelled)
@@ -10640,9 +10951,10 @@ function MockedChat(props) {
10640
10951
  }
10641
10952
  // Show incomplete message first (for typing effect)
10642
10953
  const incompleteMessage = {
10954
+ // channel: 'PROMPTBOOK_CHAT',
10643
10955
  id: currentMessage.id,
10644
- date: currentMessage.date,
10645
- from: currentMessage.from,
10956
+ createdAt: currentMessage.createdAt,
10957
+ sender: currentMessage.sender,
10646
10958
  content: '',
10647
10959
  isComplete: false,
10648
10960
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10660,9 +10972,10 @@ function MockedChat(props) {
10660
10972
  currentContent += (wordIndex > 0 ? ' ' : '') + word;
10661
10973
  // Update the message with current content
10662
10974
  const updatingMessage = {
10975
+ // channel: 'PROMPTBOOK_CHAT',
10663
10976
  id: currentMessage.id,
10664
- date: currentMessage.date,
10665
- from: currentMessage.from,
10977
+ createdAt: currentMessage.createdAt,
10978
+ sender: currentMessage.sender,
10666
10979
  content: currentContent,
10667
10980
  isComplete: false,
10668
10981
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10680,9 +10993,10 @@ function MockedChat(props) {
10680
10993
  }
10681
10994
  // Mark message as complete
10682
10995
  const completeMessage = {
10996
+ // channel: 'PROMPTBOOK_CHAT',
10683
10997
  id: currentMessage.id,
10684
- date: currentMessage.date,
10685
- from: currentMessage.from,
10998
+ createdAt: currentMessage.createdAt,
10999
+ sender: currentMessage.sender,
10686
11000
  content: currentMessage.content,
10687
11001
  isComplete: true,
10688
11002
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10934,6 +11248,12 @@ class MultipleLlmExecutionTools {
10934
11248
  callEmbeddingModel(prompt) {
10935
11249
  return this.callCommonModel(prompt);
10936
11250
  }
11251
+ /**
11252
+ * Calls the best available embedding model
11253
+ */
11254
+ callImageGenerationModel(prompt) {
11255
+ return this.callCommonModel(prompt);
11256
+ }
10937
11257
  // <- Note: [๐Ÿค–]
10938
11258
  /**
10939
11259
  * Calls the best available model
@@ -10960,6 +11280,11 @@ class MultipleLlmExecutionTools {
10960
11280
  continue llm;
10961
11281
  }
10962
11282
  return await llmExecutionTools.callEmbeddingModel(prompt);
11283
+ case 'IMAGE_GENERATION':
11284
+ if (llmExecutionTools.callImageGenerationModel === undefined) {
11285
+ continue llm;
11286
+ }
11287
+ return await llmExecutionTools.callImageGenerationModel(prompt);
10963
11288
  // <- case [๐Ÿค–]:
10964
11289
  default:
10965
11290
  throw new UnexpectedError(`Unknown model variant "${prompt.modelRequirements.modelVariant}" in ${llmExecutionTools.title}`);
@@ -12134,6 +12459,15 @@ function countUsage(llmTools) {
12134
12459
  return promptResult;
12135
12460
  };
12136
12461
  }
12462
+ if (llmTools.callImageGenerationModel !== undefined) {
12463
+ proxyTools.callImageGenerationModel = async (prompt) => {
12464
+ // console.info('[๐Ÿš•] callImageGenerationModel through countTotalUsage');
12465
+ const promptResult = await llmTools.callImageGenerationModel(prompt);
12466
+ totalUsage = addUsage(totalUsage, promptResult.usage);
12467
+ spending.next(promptResult.usage);
12468
+ return promptResult;
12469
+ };
12470
+ }
12137
12471
  // <- Note: [๐Ÿค–]
12138
12472
  return proxyTools;
12139
12473
  }
@@ -13677,8 +14011,9 @@ async function executeAttempts(options) {
13677
14011
  $ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
13678
14012
  break variant;
13679
14013
  case 'EMBEDDING':
14014
+ case 'IMAGE_GENERATION':
13680
14015
  throw new PipelineExecutionError(spaceTrim$1((block) => `
13681
- Embedding model can not be used in pipeline
14016
+ ${modelRequirements.modelVariant} model can not be used in pipeline
13682
14017
 
13683
14018
  This should be catched during parsing
13684
14019
 
@@ -14994,7 +15329,12 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
14994
15329
  };
14995
15330
  }
14996
15331
  // Apply each commitment in order using reduce-like pattern
14997
- for (const commitment of filteredCommitments) {
15332
+ for (let i = 0; i < filteredCommitments.length; i++) {
15333
+ const commitment = filteredCommitments[i];
15334
+ // CLOSED commitment should work only if its the last commitment in the book
15335
+ if (commitment.type === 'CLOSED' && i !== filteredCommitments.length - 1) {
15336
+ continue;
15337
+ }
14998
15338
  const definition = getCommitmentDefinition(commitment.type);
14999
15339
  if (definition) {
15000
15340
  try {
@@ -16009,7 +16349,7 @@ class OpenAiCompatibleExecutionTools {
16009
16349
  let threadMessages = [];
16010
16350
  if ('thread' in prompt && Array.isArray(prompt.thread)) {
16011
16351
  threadMessages = prompt.thread.map((msg) => ({
16012
- role: msg.role === 'assistant' ? 'assistant' : 'user',
16352
+ role: msg.sender === 'assistant' ? 'assistant' : 'user',
16013
16353
  content: msg.content,
16014
16354
  }));
16015
16355
  }
@@ -16422,13 +16762,14 @@ class OpenAiCompatibleExecutionTools {
16422
16762
  const modelName = currentModelRequirements.modelName || this.getDefaultImageGenerationModel().modelName;
16423
16763
  const modelSettings = {
16424
16764
  model: modelName,
16425
- // size: currentModelRequirements.size,
16426
- // quality: currentModelRequirements.quality,
16427
- // style: currentModelRequirements.style,
16765
+ size: currentModelRequirements.size,
16766
+ quality: currentModelRequirements.quality,
16767
+ style: currentModelRequirements.style,
16428
16768
  };
16429
16769
  const rawPromptContent = templateParameters(content, { ...parameters, modelName });
16430
16770
  const rawRequest = {
16431
16771
  ...modelSettings,
16772
+ size: modelSettings.size || '1024x1024',
16432
16773
  prompt: rawPromptContent,
16433
16774
  user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
16434
16775
  response_format: 'url', // TODO: [๐Ÿง ] Maybe allow b64_json
@@ -17534,9 +17875,52 @@ class Agent extends AgentLlmExecutionTools {
17534
17875
  ${block(result.content)}
17535
17876
 
17536
17877
  `);
17878
+ // Extract knowledge
17879
+ let knowledgeBlock = '';
17880
+ try {
17881
+ const extractionPrompt = {
17882
+ title: 'Knowledge Extraction',
17883
+ modelRequirements: {
17884
+ modelVariant: 'CHAT',
17885
+ },
17886
+ content: spaceTrim$2((block) => `
17887
+ You are an AI agent that is learning from a conversation.
17888
+
17889
+ Here is the conversation so far:
17890
+
17891
+ User: ${block(prompt.content)}
17892
+ Agent: ${block(result.content)}
17893
+
17894
+ Extract any new knowledge, facts, or important information that should be remembered for future interactions.
17895
+ Format the output as a list of KNOWLEDGE blocks.
17896
+ If there is no new knowledge, return nothing.
17897
+
17898
+ Example output:
17899
+ KNOWLEDGE The user's name is Alice.
17900
+ KNOWLEDGE The project deadline is next Friday.
17901
+ `),
17902
+ pipelineUrl: 'https://github.com/webgptorg/promptbook/blob/main/prompts/knowledge-extraction.ptbk.md',
17903
+ parameters: {},
17904
+ };
17905
+ if (this.options.llmTools.callChatModel) {
17906
+ const extractionResult = await this.options.llmTools.callChatModel(extractionPrompt);
17907
+ const extractedContent = extractionResult.content;
17908
+ if (extractedContent.includes('KNOWLEDGE')) {
17909
+ knowledgeBlock = '\n\n' + spaceTrim$2(extractedContent);
17910
+ }
17911
+ }
17912
+ else {
17913
+ // TODO: [๐Ÿง ] Fallback to callChatModelStream if callChatModel is not available
17914
+ }
17915
+ }
17916
+ catch (error) {
17917
+ if (this.options.isVerbose) {
17918
+ console.warn('Failed to extract knowledge', error);
17919
+ }
17920
+ }
17537
17921
  // Append to the current source
17538
17922
  const currentSource = this.agentSource.value;
17539
- const newSource = padBook(validateBook(spaceTrim$2(currentSource) + '\n\n' + learningExample));
17923
+ const newSource = padBook(validateBook(spaceTrim$2(currentSource) + '\n\n' + learningExample + knowledgeBlock));
17540
17924
  // Update the source (which will trigger the subscription and update the underlying tools)
17541
17925
  this.agentSource.next(newSource);
17542
17926
  return result;
@@ -17810,7 +18194,8 @@ function PromptbookAgentSeamlessIntegration(props) {
17810
18194
  // TODO: [๐Ÿง ] Handle error state (show error message in the chat window)
17811
18195
  const image = ((_a = agent === null || agent === void 0 ? void 0 : agent.meta) === null || _a === void 0 ? void 0 : _a.image) ||
17812
18196
  (meta === null || meta === void 0 ? void 0 : meta.image) ||
17813
- 'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y';
18197
+ // Note: [๐Ÿคน] Using default avatar from the agent server
18198
+ `${agentUrl}/images/default-avatar.png`;
17814
18199
  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
18200
  let connectionStatus = 'pending';
17816
18201
  if (agent) {