@promptbook/components 0.104.0-1 → 0.104.0-3

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 (31) hide show
  1. package/esm/index.es.js +488 -185
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/src/_packages/types.index.d.ts +8 -2
  4. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +6 -1
  5. package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +5 -1
  6. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  7. package/esm/typings/src/book-components/Chat/CodeBlock/CodeBlock.d.ts +13 -0
  8. package/esm/typings/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
  9. package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +7 -11
  10. package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +2 -2
  11. package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
  12. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +13 -7
  13. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +6 -0
  14. package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
  15. package/esm/typings/src/commitments/index.d.ts +2 -1
  16. package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
  17. package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
  18. package/esm/typings/src/types/Message.d.ts +49 -0
  19. package/esm/typings/src/types/typeAliases.d.ts +12 -0
  20. package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
  21. package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
  22. package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
  23. package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
  24. package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
  25. package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
  26. package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
  27. package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
  28. package/esm/typings/src/version.d.ts +1 -1
  29. package/package.json +1 -2
  30. package/umd/index.umd.js +496 -194
  31. package/umd/index.umd.js.map +1 -1
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-3';
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
  /**
@@ -3047,13 +3047,14 @@ function prompt(strings, ...values) {
3047
3047
  *
3048
3048
  * @public exported from `@promptbook/utils`
3049
3049
  */
3050
- const $isRunningInBrowser = new Function(`
3050
+ function $isRunningInBrowser() {
3051
3051
  try {
3052
- return this === window;
3053
- } catch (e) {
3052
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined';
3053
+ }
3054
+ catch (e) {
3054
3055
  return false;
3055
3056
  }
3056
- `);
3057
+ }
3057
3058
  /**
3058
3059
  * TODO: [🎺]
3059
3060
  */
@@ -3065,13 +3066,15 @@ const $isRunningInBrowser = new Function(`
3065
3066
  *
3066
3067
  * @public exported from `@promptbook/utils`
3067
3068
  */
3068
- const $isRunningInJest = new Function(`
3069
+ function $isRunningInJest() {
3070
+ var _a;
3069
3071
  try {
3070
- return process.env.JEST_WORKER_ID !== undefined;
3071
- } catch (e) {
3072
+ return typeof process !== 'undefined' && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.JEST_WORKER_ID) !== undefined;
3073
+ }
3074
+ catch (e) {
3072
3075
  return false;
3073
3076
  }
3074
- `);
3077
+ }
3075
3078
  /**
3076
3079
  * TODO: [🎺]
3077
3080
  */
@@ -3083,13 +3086,14 @@ const $isRunningInJest = new Function(`
3083
3086
  *
3084
3087
  * @public exported from `@promptbook/utils`
3085
3088
  */
3086
- const $isRunningInNode = new Function(`
3089
+ function $isRunningInNode() {
3087
3090
  try {
3088
- return this === global;
3089
- } catch (e) {
3091
+ return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
3092
+ }
3093
+ catch (e) {
3090
3094
  return false;
3091
3095
  }
3092
- `);
3096
+ }
3093
3097
  /**
3094
3098
  * TODO: [🎺]
3095
3099
  */
@@ -3101,17 +3105,17 @@ const $isRunningInNode = new Function(`
3101
3105
  *
3102
3106
  * @public exported from `@promptbook/utils`
3103
3107
  */
3104
- const $isRunningInWebWorker = new Function(`
3108
+ function $isRunningInWebWorker() {
3105
3109
  try {
3106
- if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
3107
- return true;
3108
- } else {
3109
- return false;
3110
- }
3111
- } catch (e) {
3110
+ // Note: Check for importScripts which is specific to workers
3111
+ // and not available in the main browser thread
3112
+ return (typeof self !== 'undefined' &&
3113
+ typeof self.importScripts === 'function');
3114
+ }
3115
+ catch (e) {
3112
3116
  return false;
3113
3117
  }
3114
- `);
3118
+ }
3115
3119
  /**
3116
3120
  * TODO: [🎺]
3117
3121
  */
@@ -4127,6 +4131,114 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
4127
4131
  * Note: [💞] Ignore a discrepancy between file name and entity name
4128
4132
  */
4129
4133
 
4134
+ /**
4135
+ * DICTIONARY commitment definition
4136
+ *
4137
+ * The DICTIONARY commitment defines specific terms and their meanings that the agent should use correctly
4138
+ * in its reasoning and responses. This ensures consistent terminology usage.
4139
+ *
4140
+ * Key features:
4141
+ * - Multiple DICTIONARY commitments are automatically merged into one
4142
+ * - Content is placed in a dedicated section of the system message
4143
+ * - Terms and definitions are stored in metadata.DICTIONARY for debugging
4144
+ * - Agent should use the defined terms correctly in responses
4145
+ *
4146
+ * Example usage in agent source:
4147
+ *
4148
+ * ```book
4149
+ * Legal Assistant
4150
+ *
4151
+ * PERSONA You are a knowledgeable legal assistant
4152
+ * DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
4153
+ * DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
4154
+ * DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
4155
+ * ```
4156
+ *
4157
+ * @private [🪔] Maybe export the commitments through some package
4158
+ */
4159
+ class DictionaryCommitmentDefinition extends BaseCommitmentDefinition {
4160
+ constructor() {
4161
+ super('DICTIONARY');
4162
+ }
4163
+ /**
4164
+ * Short one-line description of DICTIONARY.
4165
+ */
4166
+ get description() {
4167
+ return 'Define terms and their meanings for consistent terminology usage.';
4168
+ }
4169
+ /**
4170
+ * Icon for this commitment.
4171
+ */
4172
+ get icon() {
4173
+ return '📚';
4174
+ }
4175
+ /**
4176
+ * Markdown documentation for DICTIONARY commitment.
4177
+ */
4178
+ get documentation() {
4179
+ return spaceTrim$1(`
4180
+ # DICTIONARY
4181
+
4182
+ Defines specific terms and their meanings that the agent should use correctly in reasoning and responses.
4183
+
4184
+ ## Key aspects
4185
+
4186
+ - Multiple \`DICTIONARY\` commitments are merged together.
4187
+ - Terms are defined in the format: "Term is definition"
4188
+ - The agent should use these terms consistently in responses.
4189
+ - Definitions help ensure accurate and consistent terminology.
4190
+
4191
+ ## Examples
4192
+
4193
+ \`\`\`book
4194
+ Legal Assistant
4195
+
4196
+ PERSONA You are a knowledgeable legal assistant specializing in criminal law
4197
+ DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
4198
+ DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
4199
+ DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
4200
+ \`\`\`
4201
+
4202
+ \`\`\`book
4203
+ Medical Assistant
4204
+
4205
+ PERSONA You are a helpful medical assistant
4206
+ DICTIONARY Hypertension is persistently high blood pressure
4207
+ DICTIONARY Diabetes is a chronic condition that affects how the body processes blood sugar
4208
+ DICTIONARY Vaccine is a biological preparation that provides active immunity to a particular disease
4209
+ \`\`\`
4210
+ `);
4211
+ }
4212
+ applyToAgentModelRequirements(requirements, content) {
4213
+ var _a;
4214
+ const trimmedContent = content.trim();
4215
+ if (!trimmedContent) {
4216
+ return requirements;
4217
+ }
4218
+ // Get existing dictionary entries from metadata
4219
+ const existingDictionary = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.DICTIONARY) || '';
4220
+ // Merge the new dictionary entry with existing entries
4221
+ const mergedDictionary = existingDictionary
4222
+ ? `${existingDictionary}\n${trimmedContent}`
4223
+ : trimmedContent;
4224
+ // Store the merged dictionary in metadata for debugging and inspection
4225
+ const updatedMetadata = {
4226
+ ...requirements.metadata,
4227
+ DICTIONARY: mergedDictionary,
4228
+ };
4229
+ // Create the dictionary section for the system message
4230
+ // Format: "# DICTIONARY\nTerm: definition\nTerm: definition..."
4231
+ const dictionarySection = `# DICTIONARY\n${mergedDictionary}`;
4232
+ return {
4233
+ ...this.appendToSystemMessage(requirements, dictionarySection),
4234
+ metadata: updatedMetadata,
4235
+ };
4236
+ }
4237
+ }
4238
+ /**
4239
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4240
+ */
4241
+
4130
4242
  /**
4131
4243
  * FORMAT commitment definition
4132
4244
  *
@@ -6947,6 +7059,7 @@ const COMMITMENT_REGISTRY = [
6947
7059
  new DeleteCommitmentDefinition('CANCEL'),
6948
7060
  new DeleteCommitmentDefinition('DISCARD'),
6949
7061
  new DeleteCommitmentDefinition('REMOVE'),
7062
+ new DictionaryCommitmentDefinition(),
6950
7063
  new OpenCommitmentDefinition(),
6951
7064
  new ClosedCommitmentDefinition(),
6952
7065
  new UseBrowserCommitmentDefinition(),
@@ -7006,17 +7119,64 @@ function parseAgentSourceWithCommitments(agentSource) {
7006
7119
  };
7007
7120
  }
7008
7121
  const lines = agentSource.split('\n');
7009
- const agentName = (((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.trim()) || null);
7122
+ let agentName = null;
7123
+ let agentNameLineIndex = -1;
7124
+ // Find the agent name: first non-empty line that is not a commitment and not a horizontal line
7125
+ for (let i = 0; i < lines.length; i++) {
7126
+ const line = lines[i];
7127
+ if (line === undefined) {
7128
+ continue;
7129
+ }
7130
+ const trimmed = line.trim();
7131
+ if (!trimmed) {
7132
+ continue;
7133
+ }
7134
+ const isHorizontal = HORIZONTAL_LINE_PATTERN.test(line);
7135
+ if (isHorizontal) {
7136
+ continue;
7137
+ }
7138
+ let isCommitment = false;
7139
+ for (const definition of COMMITMENT_REGISTRY) {
7140
+ const typeRegex = definition.createTypeRegex();
7141
+ const match = typeRegex.exec(trimmed);
7142
+ if (match && ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.type)) {
7143
+ isCommitment = true;
7144
+ break;
7145
+ }
7146
+ }
7147
+ if (!isCommitment) {
7148
+ agentName = trimmed;
7149
+ agentNameLineIndex = i;
7150
+ break;
7151
+ }
7152
+ }
7010
7153
  const commitments = [];
7011
7154
  const nonCommitmentLines = [];
7012
- // Always add the first line (agent name) to non-commitment lines
7013
- if (lines[0] !== undefined) {
7014
- nonCommitmentLines.push(lines[0]);
7155
+ // Add lines before agentName that are horizontal lines (they are non-commitment)
7156
+ for (let i = 0; i < agentNameLineIndex; i++) {
7157
+ const line = lines[i];
7158
+ if (line === undefined) {
7159
+ continue;
7160
+ }
7161
+ const trimmed = line.trim();
7162
+ if (!trimmed) {
7163
+ continue;
7164
+ }
7165
+ const isHorizontal = HORIZONTAL_LINE_PATTERN.test(line);
7166
+ if (isHorizontal) {
7167
+ nonCommitmentLines.push(line);
7168
+ }
7169
+ // Note: Commitments before agentName are not added to nonCommitmentLines
7170
+ }
7171
+ // Add the agent name line to non-commitment lines
7172
+ if (agentNameLineIndex >= 0) {
7173
+ nonCommitmentLines.push(lines[agentNameLineIndex]);
7015
7174
  }
7016
7175
  // Parse commitments with multiline support
7017
7176
  let currentCommitment = null;
7018
- // Process lines starting from the second line (skip agent name)
7019
- for (let i = 1; i < lines.length; i++) {
7177
+ // Process lines starting from after the agent name line
7178
+ const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
7179
+ for (let i = startIndex; i < lines.length; i++) {
7020
7180
  const line = lines[i];
7021
7181
  if (line === undefined) {
7022
7182
  continue;
@@ -7238,6 +7398,7 @@ function parseAgentSource(agentSource) {
7238
7398
  return {
7239
7399
  agentName: normalizeAgentName(parseResult.agentName || createDefaultAgentName(agentSource)),
7240
7400
  agentHash,
7401
+ permanentId: meta.id,
7241
7402
  personaDescription,
7242
7403
  initialMessage,
7243
7404
  meta,
@@ -7277,9 +7438,9 @@ function AvatarChipFromSource(props) {
7277
7438
  return jsx(AvatarChip, { avatarBasicInformation: avatarBasicInformation, ...props });
7278
7439
  }
7279
7440
 
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);
7441
+ 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= */";
7442
+ var styles$8 = {"scrim":"Modal-module_scrim__jKO-A","Modal":"Modal-module_Modal__k49dY","closeButton":"Modal-module_closeButton__dzf6l"};
7443
+ styleInject(css_248z$9);
7283
7444
 
7284
7445
  /**
7285
7446
  *
@@ -7297,7 +7458,7 @@ function Modal({ children, onClose, className, }) {
7297
7458
  window.removeEventListener('keydown', handleKeyDown);
7298
7459
  };
7299
7460
  }, [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);
7461
+ 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
7462
  }
7302
7463
 
7303
7464
  /**
@@ -7382,9 +7543,9 @@ const DEFAULT_BOOK = padBook(validateBook(spaceTrim$2(`
7382
7543
  // <- [🐱‍🚀] Buttons into genesis book
7383
7544
  // <- TODO: [🐱‍🚀] generateBookBoilerplate and deprecate `DEFAULT_BOOK`
7384
7545
 
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);
7546
+ 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 */";
7547
+ 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"};
7548
+ styleInject(css_248z$8);
7388
7549
 
7389
7550
  /**
7390
7551
  * Converts Blob, File or MediaSource to url using URL.createObjectURL
@@ -7504,6 +7665,101 @@ async function $induceBookDownload(book) {
7504
7665
  * Note: [🔵] Code in this file should never be published outside of `@promptbook/browser`
7505
7666
  */
7506
7667
 
7668
+ /**
7669
+ * Downloads a file with the given content and filename
7670
+ *
7671
+ * @private utility of `<Chat/>` component
7672
+ */
7673
+ function downloadFile(content, filename, mimeType) {
7674
+ const blob = new Blob([content], { type: mimeType });
7675
+ const url = URL.createObjectURL(blob);
7676
+ const link = document.createElement('a');
7677
+ link.href = url;
7678
+ link.download = filename;
7679
+ document.body.appendChild(link);
7680
+ link.click();
7681
+ document.body.removeChild(link);
7682
+ // Clean up the URL object
7683
+ setTimeout(() => URL.revokeObjectURL(url), 100);
7684
+ }
7685
+
7686
+ 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= */";
7687
+ 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"};
7688
+ styleInject(css_248z$7);
7689
+
7690
+ const LANGUAGE_EXTENSIONS = {
7691
+ python: 'py',
7692
+ javascript: 'js',
7693
+ typescript: 'ts',
7694
+ json: 'json',
7695
+ html: 'html',
7696
+ css: 'css',
7697
+ markdown: 'md',
7698
+ text: 'txt',
7699
+ xml: 'xml',
7700
+ sql: 'sql',
7701
+ sh: 'sh',
7702
+ bash: 'sh',
7703
+ zsh: 'sh',
7704
+ yaml: 'yaml',
7705
+ yml: 'yaml',
7706
+ book: 'book',
7707
+ };
7708
+ /**
7709
+ * Component to render a code block with syntax highlighting, copy, download, and create agent options.
7710
+ *
7711
+ * @private Internal utility of `<ChatMessage />` component
7712
+ */
7713
+ function CodeBlock({ code, language, className, onCreateAgent }) {
7714
+ const lines = useMemo(() => code.split('\n').length, [code]);
7715
+ // Note: 19px is approx line height for fontSize 14. +20 for padding.
7716
+ // We cap at 400px to avoid taking too much space, allowing scroll.
7717
+ const height = Math.min(Math.max(lines * 19, 19), 400);
7718
+ const [copied, setCopied] = useState(false);
7719
+ const handleDownload = () => {
7720
+ const lang = (language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) || 'text';
7721
+ const extension = LANGUAGE_EXTENSIONS[lang] || lang;
7722
+ const filename = `file.${extension}`;
7723
+ downloadFile(code, filename, 'text/plain');
7724
+ };
7725
+ const handleCopy = async () => {
7726
+ try {
7727
+ await navigator.clipboard.writeText(code);
7728
+ setCopied(true);
7729
+ setTimeout(() => setCopied(false), 2000);
7730
+ }
7731
+ catch (error) {
7732
+ console.error('Failed to copy code to clipboard:', error);
7733
+ }
7734
+ };
7735
+ 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;
7736
+ if ((language === null || language === void 0 ? void 0 : language.trim().toLowerCase()) === 'book') {
7737
+ 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 */ })] }));
7738
+ }
7739
+ 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: {
7740
+ readOnly: true,
7741
+ minimap: { enabled: false },
7742
+ scrollBeyondLastLine: false,
7743
+ lineNumbers: 'on',
7744
+ folding: false,
7745
+ glyphMargin: false,
7746
+ fontFamily: 'Consolas, "Courier New", monospace',
7747
+ fontSize: 14,
7748
+ lineHeight: 19,
7749
+ overviewRulerLanes: 0,
7750
+ hideCursorInOverviewRuler: true,
7751
+ renderLineHighlight: 'none',
7752
+ contextmenu: false,
7753
+ scrollbar: {
7754
+ vertical: 'auto',
7755
+ horizontal: 'auto',
7756
+ useShadows: false,
7757
+ },
7758
+ domReadOnly: true,
7759
+ wordWrap: 'off',
7760
+ } })] }));
7761
+ }
7762
+
7507
7763
  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
7764
  var styles$5 = {"MarkdownContent":"MarkdownContent-module_MarkdownContent__2JuyX","chat-code-block":"MarkdownContent-module_chat-code-block__ZffFg","citation":"MarkdownContent-module_citation__11SMw"};
7509
7765
  styleInject(css_248z$6);
@@ -7606,32 +7862,8 @@ function renderMarkdown(markdown) {
7606
7862
  }
7607
7863
  try {
7608
7864
  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
- }
7865
+ const html = chatMarkdownConverter.makeHtml(processedMarkdown);
7866
+ if (typeof window !== 'undefined') {
7635
7867
  if (html.match(/class="katex/)) {
7636
7868
  const katexCssId = 'katex-css';
7637
7869
  if (!window.document.getElementById(katexCssId)) {
@@ -7642,38 +7874,6 @@ function renderMarkdown(markdown) {
7642
7874
  window.document.head.appendChild(link);
7643
7875
  }
7644
7876
  }
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
7877
  }
7678
7878
  const sanitizedHtml = html
7679
7879
  .replace(/<\s*(script|style|iframe|object|embed)[^>]*>[\s\S]*?<\s*\/\s*\1\s*>/gi, '')
@@ -7703,9 +7903,50 @@ function renderMarkdown(markdown) {
7703
7903
  * @public exported from `@promptbook/components`
7704
7904
  */
7705
7905
  function MarkdownContent(props) {
7706
- const { content, className } = props;
7906
+ const { content, className, onCreateAgent } = props;
7707
7907
  const htmlContent = useMemo(() => renderMarkdown(content), [content]);
7708
- return (jsx("div", { className: classNames(styles$5.MarkdownContent, className), dangerouslySetInnerHTML: {
7908
+ const containerRef = useRef(null);
7909
+ const rootsRef = useRef([]);
7910
+ useEffect(() => {
7911
+ // Cleanup previous roots
7912
+ rootsRef.current.forEach((root) => root.unmount());
7913
+ rootsRef.current = [];
7914
+ if (!containerRef.current) {
7915
+ return;
7916
+ }
7917
+ const preElements = containerRef.current.querySelectorAll('pre');
7918
+ preElements.forEach((pre) => {
7919
+ // Check if it is a code block (has code element)
7920
+ const codeElement = pre.querySelector('code');
7921
+ if (!codeElement) {
7922
+ return;
7923
+ }
7924
+ // Get language and code
7925
+ const className = codeElement.className; // e.g. language-python
7926
+ const match = className.match(/language-([^\s]+)/);
7927
+ const language = match ? match[1] : undefined;
7928
+ const code = codeElement.textContent || '';
7929
+ // Clear the pre element content
7930
+ pre.innerHTML = '';
7931
+ pre.className = ''; // remove existing classes if any
7932
+ pre.style.background = 'none'; // reset styles
7933
+ pre.style.padding = '0';
7934
+ pre.style.margin = '0';
7935
+ pre.style.overflow = 'visible';
7936
+ // Create a container for the CodeBlock
7937
+ const mountPoint = document.createElement('div');
7938
+ pre.appendChild(mountPoint);
7939
+ // Render CodeBlock
7940
+ const root = createRoot(mountPoint);
7941
+ root.render(jsx(CodeBlock, { code: code, language: language, onCreateAgent: onCreateAgent }));
7942
+ rootsRef.current.push(root);
7943
+ });
7944
+ return () => {
7945
+ rootsRef.current.forEach((root) => root.unmount());
7946
+ rootsRef.current = [];
7947
+ };
7948
+ }, [htmlContent, onCreateAgent]);
7949
+ return (jsx("div", { ref: containerRef, className: classNames(styles$5.MarkdownContent, className), dangerouslySetInnerHTML: {
7709
7950
  __html: htmlContent,
7710
7951
  } }));
7711
7952
  }
@@ -7922,6 +8163,16 @@ function Dropdown({ actions }) {
7922
8163
  }, children: [icon, jsx("span", { children: name })] }, name))) }))] }));
7923
8164
  }
7924
8165
 
8166
+ const MenuHoistingContext = createContext(null);
8167
+ /**
8168
+ * Hook to use the menu hoisting system
8169
+ *
8170
+ * @private mechanism inside Promptbook
8171
+ */
8172
+ function useMenuHoisting() {
8173
+ return useContext(MenuHoistingContext);
8174
+ }
8175
+
7925
8176
  /**
7926
8177
  *
7927
8178
  * @private Internal component used by `BookEditor`
@@ -7929,50 +8180,83 @@ function Dropdown({ actions }) {
7929
8180
  function BookEditorActionbar(props) {
7930
8181
  const { value, isDownloadButtonShown, isUploadButtonShown, isCameraButtonShown, isAboutButtonShown, isFullscreenButtonShown, onFullscreenClick, onUploadDocument, onTakePhoto, isFullscreen, } = props;
7931
8182
  const [isAboutModalOpen, setIsAboutModalOpen] = useState(false);
7932
- const handleDownload = () => {
7933
- const book = validateBook(value || DEFAULT_BOOK);
8183
+ const menuHoisting = useMenuHoisting();
8184
+ // Note: [1] We use ref to avoid re-creating the handleDownload function (and thus the actions array) on every value change
8185
+ const valueRef = useRef(value);
8186
+ useEffect(() => {
8187
+ valueRef.current = value;
8188
+ }, [value]);
8189
+ const handleDownload = useCallback(() => {
8190
+ const book = validateBook(valueRef.current || DEFAULT_BOOK);
7934
8191
  /* 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
- }
8192
+ }, []);
8193
+ const actions = useMemo(() => {
8194
+ const _actions = [];
8195
+ if (isUploadButtonShown && onUploadDocument) {
8196
+ _actions.push({
8197
+ icon: jsx(AttachmentIcon, {}),
8198
+ name: 'Upload document',
8199
+ onClick: onUploadDocument,
8200
+ });
8201
+ }
8202
+ if (isCameraButtonShown && onTakePhoto) {
8203
+ _actions.push({
8204
+ icon: jsx(CameraIcon, {}),
8205
+ name: 'Take photo',
8206
+ onClick: onTakePhoto,
8207
+ });
8208
+ }
8209
+ if (isDownloadButtonShown) {
8210
+ _actions.push({
8211
+ icon: jsx(DownloadIcon, {}),
8212
+ name: 'Download',
8213
+ onClick: handleDownload,
8214
+ });
8215
+ }
8216
+ if (isAboutButtonShown) {
8217
+ _actions.push({
8218
+ icon: jsx(AboutIcon, {}),
8219
+ name: 'About',
8220
+ onClick: () => setIsAboutModalOpen(true),
8221
+ });
8222
+ }
8223
+ if (isFullscreenButtonShown && onFullscreenClick) {
8224
+ _actions.push({
8225
+ icon: jsx(FullscreenIcon, {}),
8226
+ name: 'Fullscreen',
8227
+ onClick: onFullscreenClick,
8228
+ });
8229
+ }
8230
+ return _actions;
8231
+ }, [
8232
+ isUploadButtonShown,
8233
+ onUploadDocument,
8234
+ isCameraButtonShown,
8235
+ onTakePhoto,
8236
+ isDownloadButtonShown,
8237
+ handleDownload,
8238
+ isAboutButtonShown,
8239
+ isFullscreenButtonShown,
8240
+ onFullscreenClick,
8241
+ ]);
8242
+ useEffect(() => {
8243
+ if (!menuHoisting || isFullscreen) {
8244
+ return;
8245
+ }
8246
+ menuHoisting.setMenu(actions);
8247
+ return () => {
8248
+ menuHoisting.setMenu([]);
8249
+ };
8250
+ }, [menuHoisting, actions, isFullscreen]);
7972
8251
  if (isFullscreen) {
7973
- return (jsx("div", { className: styles$6.bookEditorActionbar, children: jsx("button", { className: styles$6.button, onClick: onFullscreenClick, children: jsx(ExitFullscreenIcon, {}) }) }));
8252
+ return (jsx("div", { className: styles$7.bookEditorActionbar, children: jsx("button", { className: styles$7.button, onClick: onFullscreenClick, children: jsx(ExitFullscreenIcon, {}) }) }));
7974
8253
  }
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: () => {
8254
+ if (menuHoisting && !isFullscreen) {
8255
+ return (jsx(Fragment, { children: isAboutModalOpen && (jsx(Modal, { onClose: () => {
8256
+ setIsAboutModalOpen(false);
8257
+ }, children: jsx(AboutPromptbookInformation, {}) })) }));
8258
+ }
8259
+ 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
8260
  setIsAboutModalOpen(false);
7977
8261
  }, children: jsx(AboutPromptbookInformation, {}) }))] }));
7978
8262
  }
@@ -8084,6 +8368,7 @@ function BookEditorMonaco(props) {
8084
8368
  const parameterRegex = /@([a-zA-Z0-9_á-žÁ-Žč-řČ-Řš-žŠ-Žа-яА-ЯёЁ]+)/;
8085
8369
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8086
8370
  const bookRules = [
8371
+ [/^---[-]*$/, ''],
8087
8372
  [parameterRegex, 'parameter'],
8088
8373
  [/\{[^}]+\}/, 'parameter'],
8089
8374
  [commitmentRegex, 'commitment'],
@@ -8092,7 +8377,12 @@ function BookEditorMonaco(props) {
8092
8377
  const tokenProvider = monaco.languages.setMonarchTokensProvider(BOOK_LANGUAGE_ID, {
8093
8378
  ignoreCase: true,
8094
8379
  tokenizer: {
8095
- root: [[/^.*$/, 'title', '@body']],
8380
+ root: [
8381
+ [/^\s*$/, 'empty'],
8382
+ [/^-*$/, 'line'],
8383
+ [/^.*$/, 'title', '@body'],
8384
+ [commitmentRegex, 'commitment'],
8385
+ ],
8096
8386
  body: bookRules,
8097
8387
  },
8098
8388
  });
@@ -8310,7 +8600,7 @@ function BookEditorMonaco(props) {
8310
8600
  event.preventDefault();
8311
8601
  setIsDragOver(false);
8312
8602
  }, []);
8313
- return (jsxs("div", { className: classNames(styles$6.bookEditorContainer, instanceClass), onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [(isUploadButtonShown ||
8603
+ return (jsxs("div", { className: classNames(styles$7.bookEditorContainer, instanceClass), onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [(isUploadButtonShown ||
8314
8604
  isCameraButtonShown ||
8315
8605
  isDownloadButtonShown ||
8316
8606
  isAboutButtonShown ||
@@ -8323,7 +8613,7 @@ function BookEditorMonaco(props) {
8323
8613
  onFullscreenClick,
8324
8614
  onUploadDocument: handleUploadDocument,
8325
8615
  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: {
8616
+ 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
8617
  position: 'relative',
8328
8618
  flex: 1,
8329
8619
  height: '100%',
@@ -8388,7 +8678,7 @@ function BookEditorMonaco(props) {
8388
8678
  arrowSize: 0,
8389
8679
  useShadows: false,
8390
8680
  },
8391
- }, loading: jsx("div", { className: styles$6.loading, children: "\uD83D\uDCD6" }) })] })] }));
8681
+ }, loading: jsx("div", { className: styles$7.loading, children: "\uD83D\uDCD6" }) })] })] }));
8392
8682
  }
8393
8683
 
8394
8684
  /**
@@ -8410,7 +8700,7 @@ function BookEditor(props) {
8410
8700
  const handleFullscreenToggle = () => {
8411
8701
  setIsFullscreen(!isFullscreen);
8412
8702
  };
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
8703
+ 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
8704
  ? style
8415
8705
  : {
8416
8706
  ...(style || {}),
@@ -9018,15 +9308,15 @@ const htmlSaveFormatDefinition = {
9018
9308
  ASSISTANT: '#ffb300',
9019
9309
  SYSTEM: '#888',
9020
9310
  };
9021
- const bgColor = participantColors[String(message.from)] || '#2b7cff';
9311
+ const bgColor = participantColors[String(message.sender)] || '#2b7cff';
9022
9312
  const textColor = getTextColor(bgColor);
9023
9313
  return spaceTrim$2(`
9024
9314
  <div class="chat-message">
9025
9315
  <div class="avatar" style="background:${bgColor};color:${getTextColor(bgColor)};">
9026
- ${String(message.from)[0] || '?'}
9316
+ ${String(message.sender)[0] || '?'}
9027
9317
  </div>
9028
9318
  <div class="bubble" style="background:${bgColor};color:${textColor};">
9029
- <span class="from-label">${String(message.from)}:</span>
9319
+ <span class="from-label">${String(message.sender)}:</span>
9030
9320
  ${message.content}
9031
9321
  </div>
9032
9322
  </div>
@@ -9072,7 +9362,7 @@ const mdSaveFormatDefinition = {
9072
9362
  getContent: ({ messages }) => spaceTrim$1(`
9073
9363
  ${messages
9074
9364
  .map((message) => spaceTrim$1(`
9075
- **${message.from}:**
9365
+ **${message.sender}:**
9076
9366
 
9077
9367
  > ${message.content.replace(/\n/g, '\n> ')}
9078
9368
  `))
@@ -9262,7 +9552,7 @@ const AVATAR_SIZE = 40;
9262
9552
  *
9263
9553
  * @private internal subcomponent of `<Chat>` component
9264
9554
  */
9265
- const ChatMessageItem = memo(({ message, participant, participants, isLastMessage, onMessage, setExpandedMessageId, isExpanded, currentRating, handleRating, mode, isCopyButtonEnabled, isFeedbackEnabled, onCopy, }) => {
9555
+ const ChatMessageItem = memo(({ message, participant, participants, isLastMessage, onMessage, setExpandedMessageId, isExpanded, currentRating, handleRating, mode, isCopyButtonEnabled, isFeedbackEnabled, onCopy, onCreateAgent, }) => {
9266
9556
  const avatarSrc = (participant === null || participant === void 0 ? void 0 : participant.avatarSrc) || '';
9267
9557
  const [isAvatarTooltipVisible, setIsAvatarTooltipVisible] = useState(false);
9268
9558
  const [avatarTooltipPosition, setAvatarTooltipPosition] = useState(null);
@@ -9354,7 +9644,7 @@ const ChatMessageItem = memo(({ message, participant, participants, isLastMessag
9354
9644
  console.info('participant avatarSrc', avatarSrc);
9355
9645
  console.info('participant color', { color, colorOfText });
9356
9646
  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: {
9647
+ }, 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
9648
  '--avatar-bg-color': color.toHex(),
9359
9649
  width: AVATAR_SIZE,
9360
9650
  } }), 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: {
@@ -9405,7 +9695,7 @@ const ChatMessageItem = memo(({ message, participant, participants, isLastMessag
9405
9695
  ? ' ' + chatStyles.copiedTooltipLeft
9406
9696
  : tooltipAlign === 'right'
9407
9697
  ? ' ' + 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) => {
9698
+ : ''), 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
9699
  event.stopPropagation();
9410
9700
  if (onMessage) {
9411
9701
  onMessage(button.message);
@@ -9488,7 +9778,7 @@ function Chat(props) {
9488
9778
  // isExperimental = false,
9489
9779
  // TODO: [😅]> isSaveButtonEnabled = false,
9490
9780
  // exportHeaderMarkdown,
9491
- participants = [], extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, } = props;
9781
+ participants = [], extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, onCreateAgent, } = props;
9492
9782
  const buttonColor = useMemo(() => Color.from(buttonColorRaw || '#0066cc'), [buttonColorRaw]);
9493
9783
  // Use the auto-scroll hook
9494
9784
  const { isAutoScrolling, chatMessagesRef, handleScroll, handleMessagesChange, scrollToBottom, isMobile: isMobileFromHook, } = useChatAutoScroll();
@@ -9703,7 +9993,7 @@ function Chat(props) {
9703
9993
  }
9704
9994
  }, [ratingModalOpen, isMobile]);
9705
9995
  // 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';
9996
+ const firstMessageFromUser = ((_a = messages[0]) === null || _a === void 0 ? void 0 : _a.sender) === 'USER';
9707
9997
  const actionsAlignmentClass = firstMessageFromUser
9708
9998
  ? chatStyles.actions + ' ' + chatStyles.left
9709
9999
  : chatStyles.actions + ' ' + chatStyles.right;
@@ -9780,11 +10070,11 @@ function Chat(props) {
9780
10070
  }
9781
10071
  return true;
9782
10072
  })() && chatStyles.hasActionsAndFirstMessageIsLong), ref: chatMessagesRef, onScroll: handleScroll, children: [postprocessedMessages.map((message, i) => {
9783
- const participant = participants.find((participant) => participant.name === message.from);
10073
+ const participant = participants.find((participant) => participant.name === message.sender);
9784
10074
  const isLastMessage = i === postprocessedMessages.length - 1;
9785
10075
  const isExpanded = expandedMessageId === message.id;
9786
10076
  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));
10077
+ 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
10078
  }), jsx("div", {
9789
10079
  // Note: Extra space at bottom for input area
9790
10080
  style: { height: 100 } })] }), onMessage && (jsxs("div", { className: classNames(chatStyles.chatInput, useChatCssClassName('chatInput'), isDragOver && chatStyles.dragOver), ...(onFileUpload
@@ -9872,13 +10162,13 @@ function Chat(props) {
9872
10162
  const idx = postprocessedMessages.findIndex((m) => m.id === selectedMessage.id);
9873
10163
  if (idx > 0) {
9874
10164
  const prev = postprocessedMessages[idx - 1];
9875
- if (prev.from === 'USER') {
10165
+ if (prev.sender === 'USER') {
9876
10166
  return prev.content;
9877
10167
  }
9878
10168
  }
9879
10169
  // fallback: find last USER message before selectedMessage
9880
10170
  for (let i = messages.findIndex((m) => m.id === selectedMessage.id) - 1; i >= 0; i--) {
9881
- if (messages[i].from === 'USER') {
10171
+ if (messages[i].sender === 'USER') {
9882
10172
  return messages[i].content;
9883
10173
  }
9884
10174
  }
@@ -9905,7 +10195,9 @@ class ChatPersistence {
9905
10195
  try {
9906
10196
  const serializableMessages = messages.map((message) => ({
9907
10197
  ...message,
9908
- date: (message.date || new Date()).toISOString(),
10198
+ createdAt: (typeof message.createdAt === 'string'
10199
+ ? new Date(message.createdAt)
10200
+ : message.createdAt || new Date()).toISOString(),
9909
10201
  }));
9910
10202
  const storageKey = this.STORAGE_PREFIX + persistenceKey;
9911
10203
  localStorage.setItem(storageKey, JSON.stringify(serializableMessages));
@@ -9928,7 +10220,7 @@ class ChatPersistence {
9928
10220
  // Convert date strings back to Date objects
9929
10221
  return serializableMessages.map((message) => ({
9930
10222
  ...message,
9931
- date: new Date(message.date),
10223
+ createdAt: new Date(message.createdAt),
9932
10224
  }));
9933
10225
  }
9934
10226
  catch (error) {
@@ -9981,7 +10273,7 @@ function LlmChat(props) {
9981
10273
  const { llmTools, persistenceKey, onChange, onReset, initialMessages, sendMessage, userParticipantName = 'USER', llmParticipantName = 'ASSISTANT', autoExecuteMessage, buttonColor, ...restProps } = props;
9982
10274
  // Internal state management
9983
10275
  // DRY: Single factory for seeding initial messages (used on mount and after reset)
9984
- const buildInitialMessages = useCallback(() => (initialMessages ? [...initialMessages] : []), [initialMessages]);
10276
+ const buildInitialMessages = useCallback(() => initialMessages ? ([...initialMessages]) : ([]), [initialMessages]);
9985
10277
  const [messages, setMessages] = useState(() => buildInitialMessages());
9986
10278
  const [tasksProgress, setTasksProgress] = useState([]);
9987
10279
  const [isVoiceCalling, setIsVoiceCalling] = useState(false);
@@ -10074,17 +10366,19 @@ function LlmChat(props) {
10074
10366
  setTasksProgress([{ id: taskId, name: 'Playing response...', progress: 100 }]);
10075
10367
  const now = Date.now();
10076
10368
  const userMessage = {
10369
+ // channel: 'PROMPTBOOK_CHAT',
10077
10370
  id: `user_${now}`,
10078
- date: new Date(),
10079
- from: userParticipantName,
10371
+ createdAt: new Date(),
10372
+ sender: userParticipantName,
10080
10373
  content: (result.userMessage || '(Voice message)'),
10081
10374
  isComplete: true,
10082
10375
  isVoiceCall: true,
10083
10376
  };
10084
10377
  const agentMessage = {
10378
+ // channel: 'PROMPTBOOK_CHAT',
10085
10379
  id: `agent_${now}`,
10086
- date: new Date(),
10087
- from: llmParticipantName,
10380
+ createdAt: new Date(),
10381
+ sender: llmParticipantName,
10088
10382
  content: (result.agentMessage || result.text),
10089
10383
  isComplete: true,
10090
10384
  isVoiceCall: true,
@@ -10181,9 +10475,10 @@ function LlmChat(props) {
10181
10475
  hasUserInteractedRef.current = true;
10182
10476
  // Add user message
10183
10477
  const userMessage = {
10478
+ // channel: 'PROMPTBOOK_CHAT',
10184
10479
  id: `user_${Date.now()}`,
10185
- date: new Date(),
10186
- from: userParticipantName,
10480
+ createdAt: new Date(),
10481
+ sender: userParticipantName,
10187
10482
  content: messageContent,
10188
10483
  isComplete: true,
10189
10484
  };
@@ -10195,9 +10490,10 @@ function LlmChat(props) {
10195
10490
  }
10196
10491
  // Add loading message for assistant
10197
10492
  const loadingMessage = {
10493
+ // channel: 'PROMPTBOOK_CHAT',
10198
10494
  id: `assistant_${Date.now()}`,
10199
- date: new Date(),
10200
- from: llmParticipantName,
10495
+ createdAt: new Date(),
10496
+ sender: llmParticipantName,
10201
10497
  content: 'Thinking...',
10202
10498
  isComplete: false,
10203
10499
  };
@@ -10228,9 +10524,10 @@ function LlmChat(props) {
10228
10524
  if (llmTools.callChatModelStream) {
10229
10525
  result = await llmTools.callChatModelStream(prompt, (chunk) => {
10230
10526
  const assistantMessage = {
10527
+ // channel: 'PROMPTBOOK_CHAT',
10231
10528
  id: loadingMessage.id,
10232
- date: new Date(),
10233
- from: llmParticipantName,
10529
+ createdAt: new Date(),
10530
+ sender: llmParticipantName,
10234
10531
  content: chunk.content,
10235
10532
  isComplete: false,
10236
10533
  };
@@ -10251,9 +10548,10 @@ function LlmChat(props) {
10251
10548
  setTasksProgress([{ id: taskId, name: 'Response generated', progress: 100 }]);
10252
10549
  // Replace loading message with actual response
10253
10550
  const assistantMessage = {
10551
+ // channel: 'PROMPTBOOK_CHAT',
10254
10552
  id: loadingMessage.id,
10255
- date: new Date(),
10256
- from: llmParticipantName,
10553
+ createdAt: new Date(),
10554
+ sender: llmParticipantName,
10257
10555
  content: result.content,
10258
10556
  isComplete: true,
10259
10557
  };
@@ -10272,9 +10570,10 @@ function LlmChat(props) {
10272
10570
  console.error('Error calling LLM:', error);
10273
10571
  // Replace loading message with error message
10274
10572
  const errorMessage = {
10573
+ // channel: 'PROMPTBOOK_CHAT',
10275
10574
  id: loadingMessage.id,
10276
- date: new Date(),
10277
- from: llmParticipantName,
10575
+ createdAt: new Date(),
10576
+ sender: llmParticipantName,
10278
10577
  content: `Sorry, I encountered an error: ${error instanceof Error ? error.message : 'Unknown error'}`,
10279
10578
  isComplete: true,
10280
10579
  };
@@ -10341,7 +10640,8 @@ function AgentChat(props) {
10341
10640
  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
10641
  , initialMessages: [
10343
10642
  {
10344
- from: 'AGENT',
10643
+ // channel: 'PROMPTBOOK_CHAT',
10644
+ sender: 'AGENT',
10345
10645
  content: agent.initialMessage ||
10346
10646
  spaceTrim$2(`
10347
10647
 
@@ -10619,7 +10919,7 @@ function MockedChat(props) {
10619
10919
  if (delays.longPauseChance &&
10620
10920
  Math.random() < delays.longPauseChance &&
10621
10921
  i > 0 &&
10622
- originalMessages[i].from !== originalMessages[i - 1].from) {
10922
+ originalMessages[i].sender !== originalMessages[i - 1].sender) {
10623
10923
  await forTime(getDelay(delays.longPauseDuration, 2000));
10624
10924
  didLongPause = true;
10625
10925
  if (isCancelled)
@@ -10640,9 +10940,10 @@ function MockedChat(props) {
10640
10940
  }
10641
10941
  // Show incomplete message first (for typing effect)
10642
10942
  const incompleteMessage = {
10943
+ // channel: 'PROMPTBOOK_CHAT',
10643
10944
  id: currentMessage.id,
10644
- date: currentMessage.date,
10645
- from: currentMessage.from,
10945
+ createdAt: currentMessage.createdAt,
10946
+ sender: currentMessage.sender,
10646
10947
  content: '',
10647
10948
  isComplete: false,
10648
10949
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10660,9 +10961,10 @@ function MockedChat(props) {
10660
10961
  currentContent += (wordIndex > 0 ? ' ' : '') + word;
10661
10962
  // Update the message with current content
10662
10963
  const updatingMessage = {
10964
+ // channel: 'PROMPTBOOK_CHAT',
10663
10965
  id: currentMessage.id,
10664
- date: currentMessage.date,
10665
- from: currentMessage.from,
10966
+ createdAt: currentMessage.createdAt,
10967
+ sender: currentMessage.sender,
10666
10968
  content: currentContent,
10667
10969
  isComplete: false,
10668
10970
  expectedAnswer: currentMessage.expectedAnswer,
@@ -10680,9 +10982,10 @@ function MockedChat(props) {
10680
10982
  }
10681
10983
  // Mark message as complete
10682
10984
  const completeMessage = {
10985
+ // channel: 'PROMPTBOOK_CHAT',
10683
10986
  id: currentMessage.id,
10684
- date: currentMessage.date,
10685
- from: currentMessage.from,
10987
+ createdAt: currentMessage.createdAt,
10988
+ sender: currentMessage.sender,
10686
10989
  content: currentMessage.content,
10687
10990
  isComplete: true,
10688
10991
  expectedAnswer: currentMessage.expectedAnswer,
@@ -16009,7 +16312,7 @@ class OpenAiCompatibleExecutionTools {
16009
16312
  let threadMessages = [];
16010
16313
  if ('thread' in prompt && Array.isArray(prompt.thread)) {
16011
16314
  threadMessages = prompt.thread.map((msg) => ({
16012
- role: msg.role === 'assistant' ? 'assistant' : 'user',
16315
+ role: msg.sender === 'assistant' ? 'assistant' : 'user',
16013
16316
  content: msg.content,
16014
16317
  }));
16015
16318
  }