@promptbook/components 0.112.0-58 → 0.112.0-60
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.
- package/esm/index.es.js +774 -598
- package/esm/index.es.js.map +1 -1
- package/esm/src/book-components/BookEditor/useBookEditorMonacoInteractions.d.ts +40 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoLifecycle.d.ts +34 -0
- package/esm/src/commitments/_base/BaseCommitmentDefinition.d.ts +26 -0
- package/esm/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +2 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +774 -598
- package/umd/index.umd.js.map +1 -1
- package/umd/src/book-components/BookEditor/useBookEditorMonacoInteractions.d.ts +40 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoLifecycle.d.ts +34 -0
- package/umd/src/commitments/_base/BaseCommitmentDefinition.d.ts +26 -0
- package/umd/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +2 -0
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -40,7 +40,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
40
40
|
* @generated
|
|
41
41
|
* @see https://github.com/webgptorg/promptbook
|
|
42
42
|
*/
|
|
43
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
43
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-60';
|
|
44
44
|
/**
|
|
45
45
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
46
46
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -9530,6 +9530,49 @@ class BaseCommitmentDefinition {
|
|
|
9530
9530
|
return this.appendToSystemMessage(requirements, commentSection);
|
|
9531
9531
|
}
|
|
9532
9532
|
}
|
|
9533
|
+
/**
|
|
9534
|
+
* Helper method to append a bullet point to an existing `## SectionTitle` section in the system
|
|
9535
|
+
* message, or to create a new section when it does not yet exist.
|
|
9536
|
+
*
|
|
9537
|
+
* Handles the case where the same commitment type appears multiple times in the book source and
|
|
9538
|
+
* all entries should be grouped under one shared heading rather than emitting a duplicate block.
|
|
9539
|
+
*
|
|
9540
|
+
* @param requirements - Current model requirements.
|
|
9541
|
+
* @param sectionTitle - Section title without the `##` prefix.
|
|
9542
|
+
* @param bulletContent - Bullet content without the leading `- ` prefix.
|
|
9543
|
+
* @returns Requirements with the bullet appended to the section.
|
|
9544
|
+
*/
|
|
9545
|
+
appendBulletPointToSection(requirements, sectionTitle, bulletContent) {
|
|
9546
|
+
const sectionHeader = `## ${sectionTitle}`;
|
|
9547
|
+
const bullet = `- ${bulletContent}`;
|
|
9548
|
+
if (requirements.systemMessage.includes(sectionHeader)) {
|
|
9549
|
+
// Append bullet to end of existing section, before the next h2 heading or end of message
|
|
9550
|
+
const newSystemMessage = requirements.systemMessage.replace(new RegExp(`(## ${sectionTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n\\n)([\\s\\S]*?)(?=\\n\\n##|$)`), `$1$2\n${bullet}`);
|
|
9551
|
+
return { ...requirements, systemMessage: newSystemMessage };
|
|
9552
|
+
}
|
|
9553
|
+
return this.appendToSystemMessage(requirements, `${sectionHeader}\n\n${bullet}`, '\n\n');
|
|
9554
|
+
}
|
|
9555
|
+
/**
|
|
9556
|
+
* Helper method to replace an existing `## SectionTitle` section in the system message, or to
|
|
9557
|
+
* append a new one when the section does not yet exist.
|
|
9558
|
+
*
|
|
9559
|
+
* Use this when a commitment type can appear multiple times and each subsequent occurrence should
|
|
9560
|
+
* update the single shared section rather than appending a duplicate block.
|
|
9561
|
+
*
|
|
9562
|
+
* @param requirements - Current model requirements.
|
|
9563
|
+
* @param sectionTitle - Section title without the `##` prefix.
|
|
9564
|
+
* @param sectionContent - Full section content including the `## Title` header line.
|
|
9565
|
+
* @returns Requirements with the section replaced or appended.
|
|
9566
|
+
*/
|
|
9567
|
+
replaceOrCreateSection(requirements, sectionTitle, sectionContent) {
|
|
9568
|
+
const sectionHeader = `## ${sectionTitle}`;
|
|
9569
|
+
if (requirements.systemMessage.includes(sectionHeader)) {
|
|
9570
|
+
// Replace all text from the heading until the next h2 heading or end of message
|
|
9571
|
+
const newSystemMessage = requirements.systemMessage.replace(new RegExp(`## ${sectionTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?(?=\\n\\n##|$)`), sectionContent);
|
|
9572
|
+
return { ...requirements, systemMessage: newSystemMessage };
|
|
9573
|
+
}
|
|
9574
|
+
return this.appendToSystemMessage(requirements, sectionContent, '\n\n');
|
|
9575
|
+
}
|
|
9533
9576
|
/**
|
|
9534
9577
|
* Gets tool function implementations provided by this commitment
|
|
9535
9578
|
*
|
|
@@ -10009,20 +10052,16 @@ class DictionaryCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
10009
10052
|
if (!trimmedContent) {
|
|
10010
10053
|
return requirements;
|
|
10011
10054
|
}
|
|
10012
|
-
//
|
|
10055
|
+
// Store the entry in metadata for debugging and inspection
|
|
10013
10056
|
const existingDictionary = ((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.DICTIONARY) || '';
|
|
10014
|
-
// Merge the new dictionary entry with existing entries
|
|
10015
10057
|
const mergedDictionary = existingDictionary ? `${existingDictionary}\n${trimmedContent}` : trimmedContent;
|
|
10016
|
-
// Store the merged dictionary in metadata for debugging and inspection
|
|
10017
10058
|
const updatedMetadata = {
|
|
10018
10059
|
...requirements._metadata,
|
|
10019
10060
|
DICTIONARY: mergedDictionary,
|
|
10020
10061
|
};
|
|
10021
|
-
//
|
|
10022
|
-
// Format: "# DICTIONARY\nTerm: definition\nTerm: definition..."
|
|
10023
|
-
const dictionarySection = `# DICTIONARY\n${mergedDictionary}`;
|
|
10062
|
+
// Append each dictionary entry as a bullet point under ## Dictionary
|
|
10024
10063
|
return {
|
|
10025
|
-
...this.
|
|
10064
|
+
...this.appendBulletPointToSection(requirements, 'Dictionary', trimmedContent),
|
|
10026
10065
|
_metadata: updatedMetadata,
|
|
10027
10066
|
};
|
|
10028
10067
|
}
|
|
@@ -10536,10 +10575,10 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
10536
10575
|
if (!trimmedContent) {
|
|
10537
10576
|
return requirements;
|
|
10538
10577
|
}
|
|
10539
|
-
// Add goal to the system message
|
|
10540
|
-
const goalSection =
|
|
10578
|
+
// Add goal as a proper h2 section to the system message
|
|
10579
|
+
const goalSection = `## Goal\n\n${trimmedContent}`;
|
|
10541
10580
|
const requirementsWithGoal = this.appendToSystemMessage(requirements, goalSection, '\n\n');
|
|
10542
|
-
return this.appendToPromptSuffix(requirementsWithGoal,
|
|
10581
|
+
return this.appendToPromptSuffix(requirementsWithGoal, trimmedContent);
|
|
10543
10582
|
}
|
|
10544
10583
|
}
|
|
10545
10584
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -11059,11 +11098,8 @@ class LanguageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
11059
11098
|
if (!trimmedContent) {
|
|
11060
11099
|
return requirements;
|
|
11061
11100
|
}
|
|
11062
|
-
// Add language
|
|
11063
|
-
const languageSection =
|
|
11064
|
-
${block(trimmedContent)}
|
|
11065
|
-
<- You are speaking these languages in your responses to the user.
|
|
11066
|
-
`));
|
|
11101
|
+
// Add language as a bullet under a ## Language section
|
|
11102
|
+
const languageSection = `## Language\n\n- Your language is ${trimmedContent}`;
|
|
11067
11103
|
return this.appendToSystemMessage(requirements, languageSection, '\n\n');
|
|
11068
11104
|
}
|
|
11069
11105
|
}
|
|
@@ -11107,15 +11143,16 @@ const MemoryToolNames = {
|
|
|
11107
11143
|
*/
|
|
11108
11144
|
function createMemorySystemMessage(extraInstructions) {
|
|
11109
11145
|
return spaceTrim$1((block) => `
|
|
11110
|
-
Memory
|
|
11111
|
-
|
|
11112
|
-
-
|
|
11113
|
-
-
|
|
11114
|
-
-
|
|
11115
|
-
-
|
|
11116
|
-
-
|
|
11117
|
-
-
|
|
11118
|
-
-
|
|
11146
|
+
## Memory
|
|
11147
|
+
|
|
11148
|
+
- Prefer storing agent-scoped memories; only make them global when the fact should apply across all your agents.
|
|
11149
|
+
- You can use persistent user memory tools.
|
|
11150
|
+
- Use \`${MemoryToolNames.retrieve}\` to load relevant memory before answering.
|
|
11151
|
+
- Use \`${MemoryToolNames.store}\` to save stable user-specific facts that improve future help.
|
|
11152
|
+
- Use \`${MemoryToolNames.update}\` to refresh an existing memory when the content changes.
|
|
11153
|
+
- Use \`${MemoryToolNames.delete}\` to delete memories that are no longer accurate (deletions are soft and hidden from future queries).
|
|
11154
|
+
- Store concise memory items and avoid duplicates.
|
|
11155
|
+
- Never claim memory was saved or loaded unless the tool confirms it.
|
|
11119
11156
|
${block(extraInstructions)}
|
|
11120
11157
|
`);
|
|
11121
11158
|
}
|
|
@@ -12037,10 +12074,8 @@ class MessageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
12037
12074
|
if (!trimmedContent) {
|
|
12038
12075
|
return requirements;
|
|
12039
12076
|
}
|
|
12040
|
-
// Create message section for system message
|
|
12041
|
-
const messageSection = `Previous Message: ${trimmedContent}`;
|
|
12042
12077
|
// Messages represent conversation history and should be included for context
|
|
12043
|
-
return this.
|
|
12078
|
+
return this.appendBulletPointToSection(requirements, 'Previous messages', trimmedContent);
|
|
12044
12079
|
}
|
|
12045
12080
|
}
|
|
12046
12081
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -13677,10 +13712,9 @@ class RuleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
13677
13712
|
if (!trimmedContent) {
|
|
13678
13713
|
return requirements;
|
|
13679
13714
|
}
|
|
13680
|
-
//
|
|
13681
|
-
const
|
|
13682
|
-
|
|
13683
|
-
return this.appendToPromptSuffix(requirementsWithRule, ruleSection);
|
|
13715
|
+
// Group all rules under a single ## Rules section as bullet points
|
|
13716
|
+
const requirementsWithRule = this.appendBulletPointToSection(requirements, 'Rules', trimmedContent);
|
|
13717
|
+
return this.appendToPromptSuffix(requirementsWithRule, `- ${trimmedContent}`);
|
|
13684
13718
|
}
|
|
13685
13719
|
}
|
|
13686
13720
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -13916,10 +13950,8 @@ class ScenarioCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
13916
13950
|
if (!trimmedContent) {
|
|
13917
13951
|
return requirements;
|
|
13918
13952
|
}
|
|
13919
|
-
// Create scenario section for system message
|
|
13920
|
-
const scenarioSection = `Scenario: ${trimmedContent}`;
|
|
13921
13953
|
// Scenarios provide important contextual information that affects behavior
|
|
13922
|
-
return this.
|
|
13954
|
+
return this.appendBulletPointToSection(requirements, 'Scenarios', trimmedContent);
|
|
13923
13955
|
}
|
|
13924
13956
|
}
|
|
13925
13957
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -14302,8 +14334,8 @@ const teamToolTitles = {};
|
|
|
14302
14334
|
* @private
|
|
14303
14335
|
*/
|
|
14304
14336
|
const TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES = [
|
|
14305
|
-
'-
|
|
14306
|
-
'-
|
|
14337
|
+
'- If a teammate is relevant to the request, consult that teammate using the matching tool.',
|
|
14338
|
+
'- Do not ask the user for information that a listed teammate can provide directly.',
|
|
14307
14339
|
];
|
|
14308
14340
|
/**
|
|
14309
14341
|
* Constant for remote agents by Url.
|
|
@@ -14431,7 +14463,7 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14431
14463
|
toolName: entry.toolName,
|
|
14432
14464
|
});
|
|
14433
14465
|
}
|
|
14434
|
-
const teamSystemMessage = this.createSystemMessageSection('Teammates
|
|
14466
|
+
const teamSystemMessage = this.createSystemMessageSection('Teammates', buildTeamSystemMessageBody(teamEntries));
|
|
14435
14467
|
return this.appendToSystemMessage({
|
|
14436
14468
|
...requirements,
|
|
14437
14469
|
tools: updatedTools,
|
|
@@ -14921,36 +14953,38 @@ function createAggregatedUseCommitmentSystemMessage(type, additionalInstructions
|
|
|
14921
14953
|
switch (type) {
|
|
14922
14954
|
case 'USE TIME':
|
|
14923
14955
|
return spaceTrim$1((block) => `
|
|
14924
|
-
Time and date context
|
|
14925
|
-
|
|
14926
|
-
-
|
|
14956
|
+
## Time and date context
|
|
14957
|
+
|
|
14958
|
+
- It is ${moment().format('MMMM YYYY')} now.
|
|
14959
|
+
- If you need more precise current time information, use the tool \`get_current_time\`.
|
|
14927
14960
|
${block(formatOptionalInstructionBlock('Time instructions', combinedAdditionalInstructions))}
|
|
14928
14961
|
`);
|
|
14929
14962
|
case 'USE BROWSER':
|
|
14930
14963
|
return spaceTrim$1((block) => `
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
-
|
|
14934
|
-
|
|
14964
|
+
## Browser
|
|
14965
|
+
|
|
14966
|
+
- Use \`fetch_url_content\` to retrieve content from specific URLs (webpages or documents) using scrapers.
|
|
14967
|
+
- Use \`run_browser\` for real interactive browser automation (navigation, clicks, typing, waiting, scrolling).
|
|
14968
|
+
- When you need to know information from a specific website or document, use the tools provided.
|
|
14935
14969
|
${block(formatOptionalInstructionBlock('Browser instructions', combinedAdditionalInstructions))}
|
|
14936
14970
|
`);
|
|
14937
14971
|
case 'USE SEARCH ENGINE':
|
|
14938
14972
|
return spaceTrim$1((block) => `
|
|
14939
|
-
|
|
14940
|
-
|
|
14941
|
-
-
|
|
14942
|
-
-
|
|
14943
|
-
-
|
|
14944
|
-
-
|
|
14973
|
+
## Web Search
|
|
14974
|
+
|
|
14975
|
+
- Use \`web_search\` to find up-to-date information or facts.
|
|
14976
|
+
- When you need to know some information from the internet, use the search tool provided.
|
|
14977
|
+
- Do not make up information when you can search for it.
|
|
14978
|
+
- Do not tell the user you cannot search for information, YOU CAN.
|
|
14945
14979
|
${block(formatOptionalInstructionBlock('Search instructions', combinedAdditionalInstructions))}
|
|
14946
14980
|
`);
|
|
14947
14981
|
case 'USE DEEPSEARCH':
|
|
14948
14982
|
return spaceTrim$1((block) => `
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
-
|
|
14952
|
-
-
|
|
14953
|
-
-
|
|
14983
|
+
## Deep Research
|
|
14984
|
+
|
|
14985
|
+
- Use \`deep_search\` for broader research tasks that need multi-step investigation, comparison, or synthesis across multiple sources.
|
|
14986
|
+
- Prefer it over quick search when the user asks for a well-grounded brief, report, or deeper investigation.
|
|
14987
|
+
- Do not pretend you cannot research current information when this tool is available.
|
|
14954
14988
|
${block(formatOptionalInstructionBlock('DeepSearch instructions', combinedAdditionalInstructions))}
|
|
14955
14989
|
`);
|
|
14956
14990
|
}
|
|
@@ -15280,96 +15314,6 @@ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
15280
15314
|
}
|
|
15281
15315
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
15282
15316
|
|
|
15283
|
-
/**
|
|
15284
|
-
* Base Google Calendar API URL.
|
|
15285
|
-
*
|
|
15286
|
-
* @private constant of callGoogleCalendarApi
|
|
15287
|
-
*/
|
|
15288
|
-
const GOOGLE_CALENDAR_API_BASE_URL = 'https://www.googleapis.com/calendar/v3';
|
|
15289
|
-
/**
|
|
15290
|
-
* Runs one Google Calendar API request and parses JSON response payload.
|
|
15291
|
-
*
|
|
15292
|
-
* @private function of UseCalendarCommitmentDefinition
|
|
15293
|
-
*/
|
|
15294
|
-
async function callGoogleCalendarApi(accessToken, options) {
|
|
15295
|
-
const url = new URL(options.path, GOOGLE_CALENDAR_API_BASE_URL);
|
|
15296
|
-
if (options.query) {
|
|
15297
|
-
for (const [key, value] of Object.entries(options.query)) {
|
|
15298
|
-
if (value && value.trim()) {
|
|
15299
|
-
url.searchParams.set(key, value);
|
|
15300
|
-
}
|
|
15301
|
-
}
|
|
15302
|
-
}
|
|
15303
|
-
const response = await fetch(url.toString(), {
|
|
15304
|
-
method: options.method,
|
|
15305
|
-
headers: {
|
|
15306
|
-
Authorization: `Bearer ${accessToken}`,
|
|
15307
|
-
Accept: 'application/json',
|
|
15308
|
-
'Content-Type': 'application/json',
|
|
15309
|
-
},
|
|
15310
|
-
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
15311
|
-
});
|
|
15312
|
-
const textPayload = await response.text();
|
|
15313
|
-
const parsedPayload = tryParseJson$2(textPayload);
|
|
15314
|
-
if (options.allowNotFound && response.status === 404) {
|
|
15315
|
-
return null;
|
|
15316
|
-
}
|
|
15317
|
-
if (!response.ok) {
|
|
15318
|
-
throw new Error(spaceTrim$1(`
|
|
15319
|
-
Google Calendar API request failed (${response.status} ${response.statusText}):
|
|
15320
|
-
${extractGoogleCalendarApiErrorMessage(parsedPayload, textPayload)}
|
|
15321
|
-
`));
|
|
15322
|
-
}
|
|
15323
|
-
return parsedPayload;
|
|
15324
|
-
}
|
|
15325
|
-
/**
|
|
15326
|
-
* Parses raw text into JSON when possible.
|
|
15327
|
-
*
|
|
15328
|
-
* @private function of callGoogleCalendarApi
|
|
15329
|
-
*/
|
|
15330
|
-
function tryParseJson$2(rawText) {
|
|
15331
|
-
if (!rawText.trim()) {
|
|
15332
|
-
return {};
|
|
15333
|
-
}
|
|
15334
|
-
try {
|
|
15335
|
-
return JSON.parse(rawText);
|
|
15336
|
-
}
|
|
15337
|
-
catch (_a) {
|
|
15338
|
-
return rawText;
|
|
15339
|
-
}
|
|
15340
|
-
}
|
|
15341
|
-
/**
|
|
15342
|
-
* Extracts a user-friendly Google Calendar API error message.
|
|
15343
|
-
*
|
|
15344
|
-
* @private function of callGoogleCalendarApi
|
|
15345
|
-
*/
|
|
15346
|
-
function extractGoogleCalendarApiErrorMessage(parsedPayload, fallbackText) {
|
|
15347
|
-
if (parsedPayload && typeof parsedPayload === 'object') {
|
|
15348
|
-
const payload = parsedPayload;
|
|
15349
|
-
const errorPayload = payload.error;
|
|
15350
|
-
if (errorPayload && typeof errorPayload === 'object') {
|
|
15351
|
-
const normalizedErrorPayload = errorPayload;
|
|
15352
|
-
const message = typeof normalizedErrorPayload.message === 'string' ? normalizedErrorPayload.message : '';
|
|
15353
|
-
const errors = Array.isArray(normalizedErrorPayload.errors) ? normalizedErrorPayload.errors : [];
|
|
15354
|
-
const flattenedErrors = errors
|
|
15355
|
-
.map((errorEntry) => {
|
|
15356
|
-
if (!errorEntry || typeof errorEntry !== 'object') {
|
|
15357
|
-
return '';
|
|
15358
|
-
}
|
|
15359
|
-
const normalizedErrorEntry = errorEntry;
|
|
15360
|
-
const detailMessage = typeof normalizedErrorEntry.message === 'string' ? normalizedErrorEntry.message : '';
|
|
15361
|
-
const reason = typeof normalizedErrorEntry.reason === 'string' ? normalizedErrorEntry.reason : '';
|
|
15362
|
-
return [detailMessage, reason].filter(Boolean).join(' | ');
|
|
15363
|
-
})
|
|
15364
|
-
.filter(Boolean);
|
|
15365
|
-
if (message || flattenedErrors.length > 0) {
|
|
15366
|
-
return [message, ...flattenedErrors].filter(Boolean).join(' | ');
|
|
15367
|
-
}
|
|
15368
|
-
}
|
|
15369
|
-
}
|
|
15370
|
-
return fallbackText || 'Unknown Google Calendar API error';
|
|
15371
|
-
}
|
|
15372
|
-
|
|
15373
15317
|
/**
|
|
15374
15318
|
* Hostnames accepted for Google Calendar references.
|
|
15375
15319
|
*
|
|
@@ -15551,6 +15495,96 @@ function removeTokenFromLine(line, token) {
|
|
|
15551
15495
|
}
|
|
15552
15496
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
15553
15497
|
|
|
15498
|
+
/**
|
|
15499
|
+
* Base Google Calendar API URL.
|
|
15500
|
+
*
|
|
15501
|
+
* @private constant of callGoogleCalendarApi
|
|
15502
|
+
*/
|
|
15503
|
+
const GOOGLE_CALENDAR_API_BASE_URL = 'https://www.googleapis.com/calendar/v3';
|
|
15504
|
+
/**
|
|
15505
|
+
* Runs one Google Calendar API request and parses JSON response payload.
|
|
15506
|
+
*
|
|
15507
|
+
* @private function of UseCalendarCommitmentDefinition
|
|
15508
|
+
*/
|
|
15509
|
+
async function callGoogleCalendarApi(accessToken, options) {
|
|
15510
|
+
const url = new URL(options.path, GOOGLE_CALENDAR_API_BASE_URL);
|
|
15511
|
+
if (options.query) {
|
|
15512
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
15513
|
+
if (value && value.trim()) {
|
|
15514
|
+
url.searchParams.set(key, value);
|
|
15515
|
+
}
|
|
15516
|
+
}
|
|
15517
|
+
}
|
|
15518
|
+
const response = await fetch(url.toString(), {
|
|
15519
|
+
method: options.method,
|
|
15520
|
+
headers: {
|
|
15521
|
+
Authorization: `Bearer ${accessToken}`,
|
|
15522
|
+
Accept: 'application/json',
|
|
15523
|
+
'Content-Type': 'application/json',
|
|
15524
|
+
},
|
|
15525
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
15526
|
+
});
|
|
15527
|
+
const textPayload = await response.text();
|
|
15528
|
+
const parsedPayload = tryParseJson$2(textPayload);
|
|
15529
|
+
if (options.allowNotFound && response.status === 404) {
|
|
15530
|
+
return null;
|
|
15531
|
+
}
|
|
15532
|
+
if (!response.ok) {
|
|
15533
|
+
throw new Error(spaceTrim$1(`
|
|
15534
|
+
Google Calendar API request failed (${response.status} ${response.statusText}):
|
|
15535
|
+
${extractGoogleCalendarApiErrorMessage(parsedPayload, textPayload)}
|
|
15536
|
+
`));
|
|
15537
|
+
}
|
|
15538
|
+
return parsedPayload;
|
|
15539
|
+
}
|
|
15540
|
+
/**
|
|
15541
|
+
* Parses raw text into JSON when possible.
|
|
15542
|
+
*
|
|
15543
|
+
* @private function of callGoogleCalendarApi
|
|
15544
|
+
*/
|
|
15545
|
+
function tryParseJson$2(rawText) {
|
|
15546
|
+
if (!rawText.trim()) {
|
|
15547
|
+
return {};
|
|
15548
|
+
}
|
|
15549
|
+
try {
|
|
15550
|
+
return JSON.parse(rawText);
|
|
15551
|
+
}
|
|
15552
|
+
catch (_a) {
|
|
15553
|
+
return rawText;
|
|
15554
|
+
}
|
|
15555
|
+
}
|
|
15556
|
+
/**
|
|
15557
|
+
* Extracts a user-friendly Google Calendar API error message.
|
|
15558
|
+
*
|
|
15559
|
+
* @private function of callGoogleCalendarApi
|
|
15560
|
+
*/
|
|
15561
|
+
function extractGoogleCalendarApiErrorMessage(parsedPayload, fallbackText) {
|
|
15562
|
+
if (parsedPayload && typeof parsedPayload === 'object') {
|
|
15563
|
+
const payload = parsedPayload;
|
|
15564
|
+
const errorPayload = payload.error;
|
|
15565
|
+
if (errorPayload && typeof errorPayload === 'object') {
|
|
15566
|
+
const normalizedErrorPayload = errorPayload;
|
|
15567
|
+
const message = typeof normalizedErrorPayload.message === 'string' ? normalizedErrorPayload.message : '';
|
|
15568
|
+
const errors = Array.isArray(normalizedErrorPayload.errors) ? normalizedErrorPayload.errors : [];
|
|
15569
|
+
const flattenedErrors = errors
|
|
15570
|
+
.map((errorEntry) => {
|
|
15571
|
+
if (!errorEntry || typeof errorEntry !== 'object') {
|
|
15572
|
+
return '';
|
|
15573
|
+
}
|
|
15574
|
+
const normalizedErrorEntry = errorEntry;
|
|
15575
|
+
const detailMessage = typeof normalizedErrorEntry.message === 'string' ? normalizedErrorEntry.message : '';
|
|
15576
|
+
const reason = typeof normalizedErrorEntry.reason === 'string' ? normalizedErrorEntry.reason : '';
|
|
15577
|
+
return [detailMessage, reason].filter(Boolean).join(' | ');
|
|
15578
|
+
})
|
|
15579
|
+
.filter(Boolean);
|
|
15580
|
+
if (message || flattenedErrors.length > 0) {
|
|
15581
|
+
return [message, ...flattenedErrors].filter(Boolean).join(' | ');
|
|
15582
|
+
}
|
|
15583
|
+
}
|
|
15584
|
+
}
|
|
15585
|
+
return fallbackText || 'Unknown Google Calendar API error';
|
|
15586
|
+
}
|
|
15587
|
+
|
|
15554
15588
|
/**
|
|
15555
15589
|
* Wallet metadata used by USE CALENDAR when resolving Google Calendar credentials.
|
|
15556
15590
|
*
|
|
@@ -16451,18 +16485,20 @@ class UseCalendarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
16451
16485
|
if (parsedCommitment.calendar) {
|
|
16452
16486
|
addConfiguredCalendarIfMissing(existingConfiguredCalendars, parsedCommitment.calendar);
|
|
16453
16487
|
}
|
|
16454
|
-
const
|
|
16455
|
-
? existingConfiguredCalendars
|
|
16456
|
-
|
|
16457
|
-
`- ${calendar.provider}: ${calendar.url}`,
|
|
16458
|
-
calendar.scopes.length > 0 ? ` scopes: ${calendar.scopes.join(', ')}` : '',
|
|
16459
|
-
]
|
|
16460
|
-
.filter(Boolean)
|
|
16461
|
-
.join('\n'))
|
|
16462
|
-
.join('\n')
|
|
16463
|
-
: '- Calendar is resolved from runtime context';
|
|
16488
|
+
const calendarBullets = existingConfiguredCalendars.length > 0
|
|
16489
|
+
? existingConfiguredCalendars.map((calendar) => `- ${calendar.provider}: ${calendar.url}`).join('\n')
|
|
16490
|
+
: '- Calendar is resolved from runtime context';
|
|
16464
16491
|
const extraInstructions = formatOptionalInstructionBlock('Calendar instructions', parsedCommitment.instructions);
|
|
16465
|
-
|
|
16492
|
+
const calendarSectionContent = spaceTrim$1((block) => `
|
|
16493
|
+
## Calendar
|
|
16494
|
+
|
|
16495
|
+
- Use \`calendar_list_events\`, \`calendar_get_event\`, \`calendar_create_event\`, \`calendar_update_event\`, \`calendar_delete_event\`, and \`calendar_invite_guests\` to manage events in configured calendars.
|
|
16496
|
+
- Supported operations include read, create, update, delete, invite guests, and reminders.
|
|
16497
|
+
- Configured calendars:
|
|
16498
|
+
${block(calendarBullets)}
|
|
16499
|
+
${block(extraInstructions)}
|
|
16500
|
+
`);
|
|
16501
|
+
return this.replaceOrCreateSection({
|
|
16466
16502
|
...requirements,
|
|
16467
16503
|
tools: createUseCalendarTools(requirements.tools || []),
|
|
16468
16504
|
_metadata: {
|
|
@@ -16470,16 +16506,7 @@ class UseCalendarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
16470
16506
|
useCalendar: true,
|
|
16471
16507
|
useCalendars: existingConfiguredCalendars,
|
|
16472
16508
|
},
|
|
16473
|
-
},
|
|
16474
|
-
Calendar tools:
|
|
16475
|
-
- You can inspect and manage events in configured calendars.
|
|
16476
|
-
- Supported operations include read, create, update, delete, invite guests, and reminders.
|
|
16477
|
-
- Configured calendars:
|
|
16478
|
-
${block(calendarsList)}
|
|
16479
|
-
- USE CALENDAR credentials are read from wallet records (ACCESS_TOKEN, service "${UseCalendarWallet.service}", key "${UseCalendarWallet.key}").
|
|
16480
|
-
- If credentials are missing, ask user to connect calendar credentials in host UI and/or add them to wallet.
|
|
16481
|
-
${block(extraInstructions)}
|
|
16482
|
-
`));
|
|
16509
|
+
}, 'Calendar', calendarSectionContent);
|
|
16483
16510
|
}
|
|
16484
16511
|
/**
|
|
16485
16512
|
* Gets human-readable titles for tool functions provided by this commitment.
|
|
@@ -16816,18 +16843,6 @@ async function sendEmailViaBrowser(args, agentsServerUrl) {
|
|
|
16816
16843
|
* @private internal USE EMAIL constant
|
|
16817
16844
|
*/
|
|
16818
16845
|
const SEND_EMAIL_TOOL_NAME = 'send_email';
|
|
16819
|
-
/**
|
|
16820
|
-
* Wallet service used for SMTP credentials required by USE EMAIL.
|
|
16821
|
-
*
|
|
16822
|
-
* @private internal USE EMAIL constant
|
|
16823
|
-
*/
|
|
16824
|
-
const USE_EMAIL_SMTP_WALLET_SERVICE = 'smtp';
|
|
16825
|
-
/**
|
|
16826
|
-
* Wallet key used for SMTP credentials required by USE EMAIL.
|
|
16827
|
-
*
|
|
16828
|
-
* @private internal USE EMAIL constant
|
|
16829
|
-
*/
|
|
16830
|
-
const USE_EMAIL_SMTP_WALLET_KEY = 'use-email-smtp-credentials';
|
|
16831
16846
|
/**
|
|
16832
16847
|
* USE EMAIL commitment definition.
|
|
16833
16848
|
*
|
|
@@ -16886,31 +16901,41 @@ class UseEmailCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
16886
16901
|
`);
|
|
16887
16902
|
}
|
|
16888
16903
|
applyToAgentModelRequirements(requirements, content) {
|
|
16904
|
+
var _a;
|
|
16889
16905
|
const parsedCommitment = parseUseEmailCommitmentContent(content);
|
|
16890
|
-
const extraInstructions = formatOptionalInstructionBlock('Email instructions', parsedCommitment.instructions);
|
|
16891
|
-
const senderInstruction = parsedCommitment.senderEmail
|
|
16892
|
-
? `- Default sender address from commitment: "${parsedCommitment.senderEmail}".`
|
|
16893
|
-
: '';
|
|
16894
16906
|
const updatedTools = addUseEmailTools(requirements.tools || []);
|
|
16895
|
-
|
|
16907
|
+
// Collect all configured sender emails across multiple USE EMAIL commitments
|
|
16908
|
+
const existingSenders = Array.isArray((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.useEmailSenders)
|
|
16909
|
+
? [...requirements._metadata.useEmailSenders]
|
|
16910
|
+
: [];
|
|
16911
|
+
if (parsedCommitment.senderEmail && !existingSenders.includes(parsedCommitment.senderEmail)) {
|
|
16912
|
+
existingSenders.push(parsedCommitment.senderEmail);
|
|
16913
|
+
}
|
|
16914
|
+
const senderBullets = existingSenders.length > 0
|
|
16915
|
+
? existingSenders
|
|
16916
|
+
.map((email, index) => index === 0
|
|
16917
|
+
? `- Default sender address: "${email}".`
|
|
16918
|
+
: `- Additional sender address: "${email}".`)
|
|
16919
|
+
.join('\n')
|
|
16920
|
+
: '';
|
|
16921
|
+
const extraInstructions = formatOptionalInstructionBlock('Email instructions', parsedCommitment.instructions);
|
|
16922
|
+
const emailSectionContent = spaceTrim$1((block) => `
|
|
16923
|
+
## Emails
|
|
16924
|
+
|
|
16925
|
+
- Use \`${SEND_EMAIL_TOOL_NAME}\` to send outbound emails.
|
|
16926
|
+
${block(senderBullets)}
|
|
16927
|
+
${block(extraInstructions)}
|
|
16928
|
+
`);
|
|
16929
|
+
return this.replaceOrCreateSection({
|
|
16896
16930
|
...requirements,
|
|
16897
16931
|
tools: updatedTools,
|
|
16898
16932
|
_metadata: {
|
|
16899
16933
|
...requirements._metadata,
|
|
16900
16934
|
useEmail: true,
|
|
16901
16935
|
...(parsedCommitment.senderEmail ? { useEmailSender: parsedCommitment.senderEmail } : {}),
|
|
16936
|
+
useEmailSenders: existingSenders,
|
|
16902
16937
|
},
|
|
16903
|
-
},
|
|
16904
|
-
Email tool:
|
|
16905
|
-
- Use "${SEND_EMAIL_TOOL_NAME}" to send outbound emails.
|
|
16906
|
-
- Prefer \`message\` argument compatible with Promptbook \`Message\` type.
|
|
16907
|
-
- Include subject in \`message.metadata.subject\` (or use legacy \`subject\` argument).
|
|
16908
|
-
- USE EMAIL credentials are read from wallet records (ACCESS_TOKEN, service "${USE_EMAIL_SMTP_WALLET_SERVICE}", key "${USE_EMAIL_SMTP_WALLET_KEY}").
|
|
16909
|
-
- Wallet secret must contain SMTP credentials in JSON format with fields \`host\`, \`port\`, \`secure\`, \`username\`, \`password\`.
|
|
16910
|
-
- If credentials are missing, ask user to add wallet credentials.
|
|
16911
|
-
${block(senderInstruction)}
|
|
16912
|
-
${block(extraInstructions)}
|
|
16913
|
-
`));
|
|
16938
|
+
}, 'Emails', emailSectionContent);
|
|
16914
16939
|
}
|
|
16915
16940
|
/**
|
|
16916
16941
|
* Gets human-readable titles for tool functions provided by this commitment.
|
|
@@ -16946,13 +16971,13 @@ function addUseEmailTools(existingTools) {
|
|
|
16946
16971
|
...existingTools,
|
|
16947
16972
|
{
|
|
16948
16973
|
name: SEND_EMAIL_TOOL_NAME,
|
|
16949
|
-
description: 'Send an outbound email
|
|
16974
|
+
description: 'Send an outbound email.',
|
|
16950
16975
|
parameters: {
|
|
16951
16976
|
type: 'object',
|
|
16952
16977
|
properties: {
|
|
16953
16978
|
message: {
|
|
16954
16979
|
type: 'object',
|
|
16955
|
-
description: '
|
|
16980
|
+
description: 'Email payload. Use metadata.subject for the subject line.',
|
|
16956
16981
|
},
|
|
16957
16982
|
to: {
|
|
16958
16983
|
type: 'string',
|
|
@@ -17056,13 +17081,14 @@ class UseImageGeneratorCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
17056
17081
|
useImageGenerator: content || true,
|
|
17057
17082
|
},
|
|
17058
17083
|
}, spaceTrim$1((block) => `
|
|
17059
|
-
Image generation
|
|
17060
|
-
|
|
17061
|
-
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
-
|
|
17065
|
-
-
|
|
17084
|
+
## Image generation
|
|
17085
|
+
|
|
17086
|
+
- You do not generate images directly and you do not call any image tool.
|
|
17087
|
+
- When the user asks for an image, include markdown notation in your message:
|
|
17088
|
+
\`\`
|
|
17089
|
+
- Keep \`<alt text>\` short and descriptive.
|
|
17090
|
+
- Keep \`<prompt>\` detailed so the generated image matches the request.
|
|
17091
|
+
- You can include normal explanatory text before and after the notation.
|
|
17066
17092
|
${block(extraInstructions)}
|
|
17067
17093
|
`));
|
|
17068
17094
|
}
|
|
@@ -17242,11 +17268,12 @@ class UsePopupCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
17242
17268
|
usePopup: content || true,
|
|
17243
17269
|
},
|
|
17244
17270
|
}, spaceTrim$1((block) => `
|
|
17245
|
-
|
|
17246
|
-
|
|
17247
|
-
-
|
|
17271
|
+
## Popup
|
|
17272
|
+
|
|
17273
|
+
- You can open a popup window with a specific URL using the tool \`open_popup\`.
|
|
17274
|
+
- Use this when you want the user to see or interact with a specific website.
|
|
17248
17275
|
${block(extraInstructions)}
|
|
17249
|
-
|
|
17276
|
+
`));
|
|
17250
17277
|
}
|
|
17251
17278
|
/**
|
|
17252
17279
|
* Gets human-readable titles for tool functions provided by this commitment.
|
|
@@ -17420,11 +17447,12 @@ class UsePrivacyCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
17420
17447
|
usePrivacy: content || true,
|
|
17421
17448
|
},
|
|
17422
17449
|
}, spaceTrim$1((block) => `
|
|
17423
|
-
Privacy
|
|
17424
|
-
|
|
17425
|
-
-
|
|
17426
|
-
-
|
|
17427
|
-
-
|
|
17450
|
+
## Privacy
|
|
17451
|
+
|
|
17452
|
+
- Use \`${TURN_PRIVACY_ON_TOOL_NAME}\` when the user asks for a private/sensitive conversation.
|
|
17453
|
+
- This tool requests a UI confirmation dialog. Private mode is enabled only after user confirms.
|
|
17454
|
+
- Current implementation uses the existing chat private mode (no chat persistence, memory persistence, or self-learning while active).
|
|
17455
|
+
- Do not claim that end-to-end encryption is implemented yet.
|
|
17428
17456
|
${block(extraInstructions)}
|
|
17429
17457
|
`));
|
|
17430
17458
|
}
|
|
@@ -19067,9 +19095,16 @@ class UseProjectCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19067
19095
|
}
|
|
19068
19096
|
const existingConfiguredProjects = normalizeConfiguredProjects((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.useProjects);
|
|
19069
19097
|
addConfiguredProjectIfMissing(existingConfiguredProjects, parsedCommitment.repository);
|
|
19070
|
-
const repositoriesList = existingConfiguredProjects.map((project) => `- ${project.url}`).join('\n');
|
|
19071
19098
|
const extraInstructions = formatOptionalInstructionBlock('Project instructions', parsedCommitment.instructions);
|
|
19072
|
-
|
|
19099
|
+
const sectionContent = spaceTrim$1((block) => `
|
|
19100
|
+
- You can inspect and edit configured GitHub repositories using project tools.
|
|
19101
|
+
- Configured repositories:
|
|
19102
|
+
${block(existingConfiguredProjects.map((project) => `- ${project.url}`).join('\n'))}
|
|
19103
|
+
- When a repository is not obvious from context, pass \`repository\` in tool arguments explicitly.
|
|
19104
|
+
- If credentials are missing, ask the user to connect their GitHub account in the host UI.
|
|
19105
|
+
${block(extraInstructions)}
|
|
19106
|
+
`);
|
|
19107
|
+
return this.replaceOrCreateSection({
|
|
19073
19108
|
...requirements,
|
|
19074
19109
|
tools: createUseProjectTools(requirements.tools || []),
|
|
19075
19110
|
_metadata: {
|
|
@@ -19077,16 +19112,7 @@ class UseProjectCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19077
19112
|
useProject: true,
|
|
19078
19113
|
useProjects: existingConfiguredProjects,
|
|
19079
19114
|
},
|
|
19080
|
-
},
|
|
19081
|
-
Project tools:
|
|
19082
|
-
- You can inspect and edit configured GitHub repositories using project tools.
|
|
19083
|
-
- Configured repositories:
|
|
19084
|
-
${block(repositoriesList)}
|
|
19085
|
-
- When a repository is not obvious from context, pass "repository" in tool arguments explicitly.
|
|
19086
|
-
- USE PROJECT credentials are read from wallet records (ACCESS_TOKEN, service "${UseProjectWallet.service}", key "${UseProjectWallet.key}").
|
|
19087
|
-
- If credentials are missing, ask the user to connect credentials in host UI and/or add them to wallet.
|
|
19088
|
-
${block(extraInstructions)}
|
|
19089
|
-
`));
|
|
19115
|
+
}, 'GitHub repositories', sectionContent);
|
|
19090
19116
|
}
|
|
19091
19117
|
/**
|
|
19092
19118
|
* Gets human-readable titles for tool functions provided by this commitment.
|
|
@@ -19433,11 +19459,12 @@ class UseSpawnCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19433
19459
|
useSpawn: content || true,
|
|
19434
19460
|
},
|
|
19435
19461
|
}, spaceTrim$1((block) => `
|
|
19436
|
-
Spawning agents
|
|
19437
|
-
|
|
19438
|
-
-
|
|
19439
|
-
-
|
|
19440
|
-
-
|
|
19462
|
+
## Spawning agents
|
|
19463
|
+
|
|
19464
|
+
- Use \`${SPAWN_AGENT_TOOL_NAME}\` only when user asks to create a persistent new agent.
|
|
19465
|
+
- Pass full agent source in \`source\`.
|
|
19466
|
+
- Keep \`source\` concise; the maximum accepted length is ${CREATE_AGENT_INPUT_SOURCE_MAX_LENGTH} characters.
|
|
19467
|
+
- Do not add unknown fields in tool arguments.
|
|
19441
19468
|
${block(extraInstructions)}
|
|
19442
19469
|
`));
|
|
19443
19470
|
}
|
|
@@ -19471,13 +19498,14 @@ class UseSpawnCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19471
19498
|
*/
|
|
19472
19499
|
function createTimeoutSystemMessage(extraInstructions) {
|
|
19473
19500
|
return spaceTrim$1((block) => `
|
|
19474
|
-
Timeout scheduling
|
|
19475
|
-
|
|
19476
|
-
-
|
|
19477
|
-
-
|
|
19478
|
-
-
|
|
19479
|
-
-
|
|
19480
|
-
-
|
|
19501
|
+
## Timeout scheduling
|
|
19502
|
+
|
|
19503
|
+
- Use \`set_timeout\` to wake this same chat thread in the future.
|
|
19504
|
+
- Use \`list_timeouts\` to review timeout ids/details across all chats for the same user+agent scope.
|
|
19505
|
+
- \`cancel_timeout\` accepts either one timeout id or \`allActive: true\` to cancel all active timeouts in this same user+agent scope.
|
|
19506
|
+
- Use \`update_timeout\` to pause/resume, edit next run, edit recurrence, or update timeout payload details.
|
|
19507
|
+
- When one timeout elapses, you will receive a new user-like message that explicitly says it is a timeout wake-up and includes the \`timeoutId\`.
|
|
19508
|
+
- Do not claim a timer was set or cancelled unless the tool confirms it.
|
|
19481
19509
|
${block(extraInstructions)}
|
|
19482
19510
|
`);
|
|
19483
19511
|
}
|
|
@@ -20577,10 +20605,11 @@ class UseUserLocationCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20577
20605
|
useUserLocation: content || true,
|
|
20578
20606
|
},
|
|
20579
20607
|
}, spaceTrim$1((block) => `
|
|
20580
|
-
User location
|
|
20581
|
-
|
|
20582
|
-
-
|
|
20583
|
-
-
|
|
20608
|
+
## User location
|
|
20609
|
+
|
|
20610
|
+
- Use \`${GET_USER_LOCATION_TOOL_NAME}\` only when location is needed for a better answer.
|
|
20611
|
+
- If the tool returns "unavailable" or "permission-denied", ask user to share location or provide city manually.
|
|
20612
|
+
- Do not invent coordinates or local facts when location is unavailable.
|
|
20584
20613
|
${block(extraInstructions)}
|
|
20585
20614
|
`));
|
|
20586
20615
|
}
|
|
@@ -23532,6 +23561,241 @@ function useBookEditorMonacoDiagnostics({ editor, monaco, diagnostics }) {
|
|
|
23532
23561
|
}, [diagnostics, editor, monaco]);
|
|
23533
23562
|
}
|
|
23534
23563
|
|
|
23564
|
+
/**
|
|
23565
|
+
* Clipboard MIME types treated as rich text documents for upload.
|
|
23566
|
+
*
|
|
23567
|
+
* @private function of BookEditorMonaco
|
|
23568
|
+
*/
|
|
23569
|
+
const RICH_CLIPBOARD_TEXT_MIME_TYPES = new Set(['text/html', 'text/rtf']);
|
|
23570
|
+
/**
|
|
23571
|
+
* Uploaded filename mapping for known rich clipboard MIME types.
|
|
23572
|
+
*
|
|
23573
|
+
* @private function of BookEditorMonaco
|
|
23574
|
+
*/
|
|
23575
|
+
const CLIPBOARD_RICH_CONTENT_FILENAMES = {
|
|
23576
|
+
'text/html': 'clipboard-content.html',
|
|
23577
|
+
'text/rtf': 'clipboard-content.rtf',
|
|
23578
|
+
'application/rtf': 'clipboard-content.rtf',
|
|
23579
|
+
};
|
|
23580
|
+
/**
|
|
23581
|
+
* Fallback filename used when clipboard MIME type is unknown.
|
|
23582
|
+
*
|
|
23583
|
+
* @private function of BookEditorMonaco
|
|
23584
|
+
*/
|
|
23585
|
+
const DEFAULT_CLIPBOARD_RICH_CONTENT_FILENAME = 'clipboard-content.txt';
|
|
23586
|
+
/**
|
|
23587
|
+
* Maximum pointer travel still treated as a tap on the touch focus overlay.
|
|
23588
|
+
*
|
|
23589
|
+
* @private function of BookEditorMonaco
|
|
23590
|
+
*/
|
|
23591
|
+
const TOUCH_TAP_THRESHOLD = 10;
|
|
23592
|
+
/**
|
|
23593
|
+
* Lists transferable items from a browser `DataTransfer` object.
|
|
23594
|
+
*
|
|
23595
|
+
* @private function of BookEditorMonaco
|
|
23596
|
+
*/
|
|
23597
|
+
function listDataTransferItems(dataTransfer) {
|
|
23598
|
+
const items = [];
|
|
23599
|
+
for (let index = 0; index < dataTransfer.items.length; index++) {
|
|
23600
|
+
const item = dataTransfer.items[index];
|
|
23601
|
+
if (item) {
|
|
23602
|
+
items.push(item);
|
|
23603
|
+
}
|
|
23604
|
+
}
|
|
23605
|
+
return items;
|
|
23606
|
+
}
|
|
23607
|
+
/**
|
|
23608
|
+
* Removes duplicate files by using stable file metadata signature.
|
|
23609
|
+
*
|
|
23610
|
+
* @private function of BookEditorMonaco
|
|
23611
|
+
*/
|
|
23612
|
+
function deduplicateFiles(files) {
|
|
23613
|
+
const uniqueFiles = new Map();
|
|
23614
|
+
for (const file of files) {
|
|
23615
|
+
uniqueFiles.set(`${file.name}:${file.type}:${file.size}`, file);
|
|
23616
|
+
}
|
|
23617
|
+
return Array.from(uniqueFiles.values());
|
|
23618
|
+
}
|
|
23619
|
+
/**
|
|
23620
|
+
* Extracts all file-like clipboard/drop payloads from a `DataTransfer`.
|
|
23621
|
+
*
|
|
23622
|
+
* @private function of BookEditorMonaco
|
|
23623
|
+
*/
|
|
23624
|
+
function getDataTransferFiles(dataTransfer) {
|
|
23625
|
+
const directFiles = Array.from(dataTransfer.files || []);
|
|
23626
|
+
const itemFiles = listDataTransferItems(dataTransfer)
|
|
23627
|
+
.filter((item) => item.kind === 'file')
|
|
23628
|
+
.map((item) => item.getAsFile())
|
|
23629
|
+
.filter((file) => file !== null);
|
|
23630
|
+
return deduplicateFiles([...directFiles, ...itemFiles]);
|
|
23631
|
+
}
|
|
23632
|
+
/**
|
|
23633
|
+
* Picks the richest textual clipboard item that should be uploaded as a document.
|
|
23634
|
+
*
|
|
23635
|
+
* @private function of BookEditorMonaco
|
|
23636
|
+
*/
|
|
23637
|
+
function getRichClipboardTextItem(dataTransfer) {
|
|
23638
|
+
const items = listDataTransferItems(dataTransfer);
|
|
23639
|
+
const hasPlainTextItem = items.some((item) => item.kind === 'string' && item.type.toLowerCase() === 'text/plain');
|
|
23640
|
+
const applicationItem = items.find((item) => item.kind === 'string' && item.type.toLowerCase().startsWith('application/'));
|
|
23641
|
+
if (applicationItem) {
|
|
23642
|
+
return applicationItem;
|
|
23643
|
+
}
|
|
23644
|
+
if (hasPlainTextItem) {
|
|
23645
|
+
return null;
|
|
23646
|
+
}
|
|
23647
|
+
const richTextItem = items.find((item) => {
|
|
23648
|
+
if (item.kind !== 'string') {
|
|
23649
|
+
return false;
|
|
23650
|
+
}
|
|
23651
|
+
return RICH_CLIPBOARD_TEXT_MIME_TYPES.has(item.type.toLowerCase());
|
|
23652
|
+
});
|
|
23653
|
+
return richTextItem || null;
|
|
23654
|
+
}
|
|
23655
|
+
/**
|
|
23656
|
+
* Resolves whether paste should route into upload workflow instead of text insert.
|
|
23657
|
+
*
|
|
23658
|
+
* @private function of BookEditorMonaco
|
|
23659
|
+
*/
|
|
23660
|
+
function hasUploadableClipboardContent(dataTransfer) {
|
|
23661
|
+
if (getDataTransferFiles(dataTransfer).length > 0) {
|
|
23662
|
+
return true;
|
|
23663
|
+
}
|
|
23664
|
+
return getRichClipboardTextItem(dataTransfer) !== null;
|
|
23665
|
+
}
|
|
23666
|
+
/**
|
|
23667
|
+
* Reads string payload from clipboard item.
|
|
23668
|
+
*
|
|
23669
|
+
* @private function of BookEditorMonaco
|
|
23670
|
+
*/
|
|
23671
|
+
function getClipboardItemString(item) {
|
|
23672
|
+
return new Promise((resolve) => {
|
|
23673
|
+
try {
|
|
23674
|
+
item.getAsString((value) => resolve(value || ''));
|
|
23675
|
+
}
|
|
23676
|
+
catch (_a) {
|
|
23677
|
+
resolve('');
|
|
23678
|
+
}
|
|
23679
|
+
});
|
|
23680
|
+
}
|
|
23681
|
+
/**
|
|
23682
|
+
* Determines filename for generated clipboard rich-content uploads.
|
|
23683
|
+
*
|
|
23684
|
+
* @private function of BookEditorMonaco
|
|
23685
|
+
*/
|
|
23686
|
+
function getClipboardRichContentFilename(mimeType) {
|
|
23687
|
+
return CLIPBOARD_RICH_CONTENT_FILENAMES[mimeType.toLowerCase()] || DEFAULT_CLIPBOARD_RICH_CONTENT_FILENAME;
|
|
23688
|
+
}
|
|
23689
|
+
/**
|
|
23690
|
+
* Converts clipboard payload into upload-ready files.
|
|
23691
|
+
*
|
|
23692
|
+
* @private function of BookEditorMonaco
|
|
23693
|
+
*/
|
|
23694
|
+
async function resolveClipboardUploadFiles(dataTransfer) {
|
|
23695
|
+
const files = getDataTransferFiles(dataTransfer);
|
|
23696
|
+
if (files.length > 0) {
|
|
23697
|
+
return files;
|
|
23698
|
+
}
|
|
23699
|
+
const richTextItem = getRichClipboardTextItem(dataTransfer);
|
|
23700
|
+
if (!richTextItem) {
|
|
23701
|
+
return [];
|
|
23702
|
+
}
|
|
23703
|
+
const content = await getClipboardItemString(richTextItem);
|
|
23704
|
+
const mimeType = richTextItem.type || 'text/plain';
|
|
23705
|
+
if (!content.trim()) {
|
|
23706
|
+
return [];
|
|
23707
|
+
}
|
|
23708
|
+
return [new File([content], getClipboardRichContentFilename(mimeType), { type: mimeType })];
|
|
23709
|
+
}
|
|
23710
|
+
/**
|
|
23711
|
+
* Manages drag, paste and file input interactions for `BookEditorMonaco`.
|
|
23712
|
+
*
|
|
23713
|
+
* @private function of BookEditorMonaco
|
|
23714
|
+
*/
|
|
23715
|
+
function useBookEditorMonacoInteractions({ editor, handleFiles, }) {
|
|
23716
|
+
const [isDragOver, setIsDragOver] = useState(false);
|
|
23717
|
+
const touchStartRef = useRef(null);
|
|
23718
|
+
const fileUploadInputRef = useRef(null);
|
|
23719
|
+
const cameraInputRef = useRef(null);
|
|
23720
|
+
const handleDrop = useCallback(async (event) => {
|
|
23721
|
+
event.preventDefault();
|
|
23722
|
+
setIsDragOver(false);
|
|
23723
|
+
const files = getDataTransferFiles(event.dataTransfer);
|
|
23724
|
+
await handleFiles(files);
|
|
23725
|
+
}, [handleFiles]);
|
|
23726
|
+
const handlePaste = useCallback(async (event) => {
|
|
23727
|
+
const clipboardData = event.clipboardData;
|
|
23728
|
+
if (!hasUploadableClipboardContent(clipboardData)) {
|
|
23729
|
+
return;
|
|
23730
|
+
}
|
|
23731
|
+
event.preventDefault();
|
|
23732
|
+
event.stopPropagation();
|
|
23733
|
+
const files = await resolveClipboardUploadFiles(clipboardData);
|
|
23734
|
+
await handleFiles(files);
|
|
23735
|
+
}, [handleFiles]);
|
|
23736
|
+
const handleUploadDocument = useCallback(() => {
|
|
23737
|
+
var _a;
|
|
23738
|
+
(_a = fileUploadInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
23739
|
+
}, []);
|
|
23740
|
+
const handleTakePhoto = useCallback(() => {
|
|
23741
|
+
var _a;
|
|
23742
|
+
(_a = cameraInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
23743
|
+
}, []);
|
|
23744
|
+
const handleFileInputChange = useCallback((event) => {
|
|
23745
|
+
const files = Array.from(event.target.files || []);
|
|
23746
|
+
void handleFiles(files);
|
|
23747
|
+
event.target.value = '';
|
|
23748
|
+
}, [handleFiles]);
|
|
23749
|
+
const handleDragOver = useCallback((event) => {
|
|
23750
|
+
event.preventDefault();
|
|
23751
|
+
setIsDragOver(true);
|
|
23752
|
+
}, []);
|
|
23753
|
+
const handleDragEnter = useCallback((event) => {
|
|
23754
|
+
event.preventDefault();
|
|
23755
|
+
setIsDragOver(true);
|
|
23756
|
+
}, []);
|
|
23757
|
+
const handleDragLeave = useCallback((event) => {
|
|
23758
|
+
event.preventDefault();
|
|
23759
|
+
setIsDragOver(false);
|
|
23760
|
+
}, []);
|
|
23761
|
+
const handleFocusOverlayTouchStart = useCallback((event) => {
|
|
23762
|
+
const touch = event.touches[0];
|
|
23763
|
+
if (touch) {
|
|
23764
|
+
touchStartRef.current = { x: touch.clientX, y: touch.clientY };
|
|
23765
|
+
}
|
|
23766
|
+
}, []);
|
|
23767
|
+
const handleFocusOverlayTouchEnd = useCallback((event) => {
|
|
23768
|
+
event.preventDefault();
|
|
23769
|
+
const touch = event.changedTouches[0];
|
|
23770
|
+
if (touch && touchStartRef.current) {
|
|
23771
|
+
const deltaX = Math.abs(touch.clientX - touchStartRef.current.x);
|
|
23772
|
+
const deltaY = Math.abs(touch.clientY - touchStartRef.current.y);
|
|
23773
|
+
if (deltaX < TOUCH_TAP_THRESHOLD && deltaY < TOUCH_TAP_THRESHOLD) {
|
|
23774
|
+
editor === null || editor === void 0 ? void 0 : editor.focus();
|
|
23775
|
+
}
|
|
23776
|
+
}
|
|
23777
|
+
touchStartRef.current = null;
|
|
23778
|
+
}, [editor]);
|
|
23779
|
+
const focusOverlayTouchHandlers = useMemo(() => ({
|
|
23780
|
+
onTouchStart: handleFocusOverlayTouchStart,
|
|
23781
|
+
onTouchEnd: handleFocusOverlayTouchEnd,
|
|
23782
|
+
}), [handleFocusOverlayTouchEnd, handleFocusOverlayTouchStart]);
|
|
23783
|
+
return {
|
|
23784
|
+
isDragOver,
|
|
23785
|
+
fileUploadInputRef,
|
|
23786
|
+
cameraInputRef,
|
|
23787
|
+
handleDrop,
|
|
23788
|
+
handlePaste,
|
|
23789
|
+
handleUploadDocument,
|
|
23790
|
+
handleTakePhoto,
|
|
23791
|
+
handleFileInputChange,
|
|
23792
|
+
handleDragOver,
|
|
23793
|
+
handleDragEnter,
|
|
23794
|
+
handleDragLeave,
|
|
23795
|
+
focusOverlayTouchHandlers,
|
|
23796
|
+
};
|
|
23797
|
+
}
|
|
23798
|
+
|
|
23535
23799
|
/**
|
|
23536
23800
|
* Priority order for the important commitments shown first in catalogues and intellisense.
|
|
23537
23801
|
*
|
|
@@ -24194,6 +24458,181 @@ function useBookEditorMonacoLanguage({ monaco, theme }) {
|
|
|
24194
24458
|
}, [monaco, theme]);
|
|
24195
24459
|
}
|
|
24196
24460
|
|
|
24461
|
+
/**
|
|
24462
|
+
* Local storage key that enables BookEditor Monaco lifecycle debug logs in development.
|
|
24463
|
+
*
|
|
24464
|
+
* @private function of BookEditorMonaco
|
|
24465
|
+
*/
|
|
24466
|
+
const BOOK_EDITOR_MONACO_DEBUG_STORAGE_KEY = 'promptbook-debug-book-editor-monaco';
|
|
24467
|
+
/**
|
|
24468
|
+
* Duration of the save notification.
|
|
24469
|
+
*
|
|
24470
|
+
* @private function of BookEditorMonaco
|
|
24471
|
+
*/
|
|
24472
|
+
const SAVE_NOTIFICATION_HIDE_DELAY_MS = 2000;
|
|
24473
|
+
/**
|
|
24474
|
+
* Resolves whether verbose BookEditor Monaco lifecycle logs are enabled.
|
|
24475
|
+
*
|
|
24476
|
+
* @private function of BookEditorMonaco
|
|
24477
|
+
*/
|
|
24478
|
+
function isBookEditorMonacoDebugEnabled() {
|
|
24479
|
+
if (process.env.NODE_ENV === 'production' || typeof window === 'undefined') {
|
|
24480
|
+
return false;
|
|
24481
|
+
}
|
|
24482
|
+
try {
|
|
24483
|
+
return window.localStorage.getItem(BOOK_EDITOR_MONACO_DEBUG_STORAGE_KEY) === '1';
|
|
24484
|
+
}
|
|
24485
|
+
catch (_a) {
|
|
24486
|
+
return false;
|
|
24487
|
+
}
|
|
24488
|
+
}
|
|
24489
|
+
/**
|
|
24490
|
+
* Prints one BookEditor Monaco debug line when the dev debug flag is enabled.
|
|
24491
|
+
*
|
|
24492
|
+
* @param message - Human-readable lifecycle message.
|
|
24493
|
+
*
|
|
24494
|
+
* @private function of BookEditorMonaco
|
|
24495
|
+
*/
|
|
24496
|
+
function logBookEditorMonacoDebug(message) {
|
|
24497
|
+
if (!isBookEditorMonacoDebugEnabled()) {
|
|
24498
|
+
return;
|
|
24499
|
+
}
|
|
24500
|
+
console.info(`[BookEditorMonaco] ${message}`);
|
|
24501
|
+
}
|
|
24502
|
+
/**
|
|
24503
|
+
* Detects whether the current device primarily uses a coarse pointer.
|
|
24504
|
+
*
|
|
24505
|
+
* @private function of BookEditorMonaco
|
|
24506
|
+
*/
|
|
24507
|
+
function detectIsTouchDevice() {
|
|
24508
|
+
if (typeof window === 'undefined') {
|
|
24509
|
+
return false;
|
|
24510
|
+
}
|
|
24511
|
+
return window.matchMedia('(pointer: coarse)').matches;
|
|
24512
|
+
}
|
|
24513
|
+
/**
|
|
24514
|
+
* Manages Monaco lifecycle wiring for `BookEditorMonaco`.
|
|
24515
|
+
*
|
|
24516
|
+
* @private function of BookEditorMonaco
|
|
24517
|
+
*/
|
|
24518
|
+
function useBookEditorMonacoLifecycle({ monaco, theme, }) {
|
|
24519
|
+
const [editor, setEditor] = useState(null);
|
|
24520
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
24521
|
+
const [isTouchDevice, setIsTouchDevice] = useState(false);
|
|
24522
|
+
const [isSavedShown, setIsSavedShown] = useState(false);
|
|
24523
|
+
/**
|
|
24524
|
+
* Re-applies Book language + theme to the currently mounted Monaco model.
|
|
24525
|
+
*/
|
|
24526
|
+
const reapplyBookLanguageAndTheme = useCallback((reason) => {
|
|
24527
|
+
if (!editor || !monaco) {
|
|
24528
|
+
return;
|
|
24529
|
+
}
|
|
24530
|
+
ensureBookEditorMonacoLanguageForEditor({ monaco, monacoEditor: editor, theme });
|
|
24531
|
+
logBookEditorMonacoDebug(`Re-applied Book Monaco language/theme (${reason}).`);
|
|
24532
|
+
}, [editor, monaco, theme]);
|
|
24533
|
+
/**
|
|
24534
|
+
* Re-triggers the transient save toast without preventing the browser save dialog.
|
|
24535
|
+
*/
|
|
24536
|
+
const showSavedNotification = useCallback(() => {
|
|
24537
|
+
setIsSavedShown(false);
|
|
24538
|
+
setTimeout(() => setIsSavedShown(true), 0);
|
|
24539
|
+
}, []);
|
|
24540
|
+
useEffect(() => {
|
|
24541
|
+
setIsTouchDevice(detectIsTouchDevice());
|
|
24542
|
+
}, []);
|
|
24543
|
+
useEffect(() => {
|
|
24544
|
+
if (!editor || !monaco) {
|
|
24545
|
+
return;
|
|
24546
|
+
}
|
|
24547
|
+
const focusListener = editor.onDidFocusEditorWidget(() => {
|
|
24548
|
+
setIsFocused(true);
|
|
24549
|
+
reapplyBookLanguageAndTheme('focus');
|
|
24550
|
+
});
|
|
24551
|
+
const blurListener = editor.onDidBlurEditorWidget(() => {
|
|
24552
|
+
setIsFocused(false);
|
|
24553
|
+
});
|
|
24554
|
+
const saveAction = editor.addAction({
|
|
24555
|
+
id: 'save-book',
|
|
24556
|
+
label: 'Save',
|
|
24557
|
+
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
|
|
24558
|
+
run: () => {
|
|
24559
|
+
showSavedNotification();
|
|
24560
|
+
// Note: We don't prevent default, so browser's save dialog still opens
|
|
24561
|
+
},
|
|
24562
|
+
});
|
|
24563
|
+
return () => {
|
|
24564
|
+
focusListener.dispose();
|
|
24565
|
+
blurListener.dispose();
|
|
24566
|
+
saveAction.dispose();
|
|
24567
|
+
};
|
|
24568
|
+
}, [editor, monaco, reapplyBookLanguageAndTheme, showSavedNotification]);
|
|
24569
|
+
useEffect(() => {
|
|
24570
|
+
reapplyBookLanguageAndTheme('editor-ready');
|
|
24571
|
+
}, [reapplyBookLanguageAndTheme]);
|
|
24572
|
+
useEffect(() => {
|
|
24573
|
+
if (!editor || !monaco) {
|
|
24574
|
+
return;
|
|
24575
|
+
}
|
|
24576
|
+
const handlePopState = () => {
|
|
24577
|
+
reapplyBookLanguageAndTheme('history-popstate');
|
|
24578
|
+
};
|
|
24579
|
+
const handlePageShow = () => {
|
|
24580
|
+
reapplyBookLanguageAndTheme('pageshow');
|
|
24581
|
+
};
|
|
24582
|
+
const handleWindowFocus = () => {
|
|
24583
|
+
reapplyBookLanguageAndTheme('window-focus');
|
|
24584
|
+
};
|
|
24585
|
+
const handleVisibilityChange = () => {
|
|
24586
|
+
if (document.visibilityState === 'visible') {
|
|
24587
|
+
reapplyBookLanguageAndTheme('visibility-visible');
|
|
24588
|
+
}
|
|
24589
|
+
};
|
|
24590
|
+
window.addEventListener('popstate', handlePopState);
|
|
24591
|
+
window.addEventListener('pageshow', handlePageShow);
|
|
24592
|
+
window.addEventListener('focus', handleWindowFocus);
|
|
24593
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
|
24594
|
+
return () => {
|
|
24595
|
+
window.removeEventListener('popstate', handlePopState);
|
|
24596
|
+
window.removeEventListener('pageshow', handlePageShow);
|
|
24597
|
+
window.removeEventListener('focus', handleWindowFocus);
|
|
24598
|
+
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
24599
|
+
};
|
|
24600
|
+
}, [editor, monaco, reapplyBookLanguageAndTheme]);
|
|
24601
|
+
useEffect(() => {
|
|
24602
|
+
if (!isSavedShown) {
|
|
24603
|
+
return;
|
|
24604
|
+
}
|
|
24605
|
+
const timer = setTimeout(() => {
|
|
24606
|
+
setIsSavedShown(false);
|
|
24607
|
+
}, SAVE_NOTIFICATION_HIDE_DELAY_MS);
|
|
24608
|
+
return () => {
|
|
24609
|
+
clearTimeout(timer);
|
|
24610
|
+
};
|
|
24611
|
+
}, [isSavedShown]);
|
|
24612
|
+
/**
|
|
24613
|
+
* Ensures Book language/tokenizer is ready before Monaco creates the editor model.
|
|
24614
|
+
*/
|
|
24615
|
+
const handleBeforeMonacoMount = useCallback((beforeMountMonaco) => {
|
|
24616
|
+
ensureBookEditorMonacoLanguage(beforeMountMonaco, theme);
|
|
24617
|
+
}, [theme]);
|
|
24618
|
+
/**
|
|
24619
|
+
* Re-applies Book language/theme once Monaco editor is mounted.
|
|
24620
|
+
*/
|
|
24621
|
+
const handleMonacoMount = useCallback((mountedEditor, mountedMonaco) => {
|
|
24622
|
+
setEditor(mountedEditor);
|
|
24623
|
+
ensureBookEditorMonacoLanguageForEditor({ monaco: mountedMonaco, monacoEditor: mountedEditor, theme });
|
|
24624
|
+
logBookEditorMonacoDebug('Mounted Monaco editor and re-applied Book language/theme.');
|
|
24625
|
+
}, [theme]);
|
|
24626
|
+
return {
|
|
24627
|
+
editor,
|
|
24628
|
+
isFocused,
|
|
24629
|
+
isTouchDevice,
|
|
24630
|
+
isSavedShown,
|
|
24631
|
+
handleBeforeMonacoMount,
|
|
24632
|
+
handleMonacoMount,
|
|
24633
|
+
};
|
|
24634
|
+
}
|
|
24635
|
+
|
|
24197
24636
|
/**
|
|
24198
24637
|
* Relative Y offset multiplier for aligning line background with Monaco rendering.
|
|
24199
24638
|
*
|
|
@@ -25003,190 +25442,101 @@ function BookEditorMonacoUploadPanel({ activeUploadItems, uploadStats, pauseUplo
|
|
|
25003
25442
|
*/
|
|
25004
25443
|
const INVALID_CSS_IDENTIFIER_CHARACTER_PATTERN = /[^a-zA-Z0-9_-]/g;
|
|
25005
25444
|
/**
|
|
25006
|
-
*
|
|
25445
|
+
* Base Book editor font size before zoom scaling.
|
|
25007
25446
|
*
|
|
25008
25447
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25009
25448
|
*/
|
|
25010
|
-
const
|
|
25449
|
+
const BASE_FONT_SIZE = 20;
|
|
25011
25450
|
/**
|
|
25012
|
-
*
|
|
25451
|
+
* Minimum supported Book editor font size after zoom scaling.
|
|
25013
25452
|
*
|
|
25014
25453
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25015
25454
|
*/
|
|
25016
|
-
const
|
|
25017
|
-
'text/html': 'clipboard-content.html',
|
|
25018
|
-
'text/rtf': 'clipboard-content.rtf',
|
|
25019
|
-
'application/rtf': 'clipboard-content.rtf',
|
|
25020
|
-
};
|
|
25455
|
+
const MIN_FONT_SIZE = 8;
|
|
25021
25456
|
/**
|
|
25022
|
-
*
|
|
25023
|
-
*
|
|
25024
|
-
* @private Internal utility of `BookEditorMonaco`.
|
|
25025
|
-
*/
|
|
25026
|
-
const DEFAULT_CLIPBOARD_RICH_CONTENT_FILENAME = 'clipboard-content.txt';
|
|
25027
|
-
/**
|
|
25028
|
-
* Local storage key that enables BookEditor Monaco lifecycle debug logs in development.
|
|
25029
|
-
*
|
|
25030
|
-
* @private Internal utility of `BookEditorMonaco`.
|
|
25031
|
-
*/
|
|
25032
|
-
const BOOK_EDITOR_MONACO_DEBUG_STORAGE_KEY = 'promptbook-debug-book-editor-monaco';
|
|
25033
|
-
/**
|
|
25034
|
-
* Resolves whether verbose BookEditor Monaco lifecycle logs are enabled.
|
|
25457
|
+
* Default Monaco scrollbar size before zoom scaling.
|
|
25035
25458
|
*
|
|
25036
25459
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25037
25460
|
*/
|
|
25038
|
-
|
|
25039
|
-
if (process.env.NODE_ENV === 'production' || typeof window === 'undefined') {
|
|
25040
|
-
return false;
|
|
25041
|
-
}
|
|
25042
|
-
try {
|
|
25043
|
-
return window.localStorage.getItem(BOOK_EDITOR_MONACO_DEBUG_STORAGE_KEY) === '1';
|
|
25044
|
-
}
|
|
25045
|
-
catch (_a) {
|
|
25046
|
-
return false;
|
|
25047
|
-
}
|
|
25048
|
-
}
|
|
25049
|
-
/**
|
|
25050
|
-
* Prints one BookEditor Monaco debug line when the dev debug flag is enabled.
|
|
25051
|
-
*
|
|
25052
|
-
* @param message - Human-readable lifecycle message.
|
|
25053
|
-
*
|
|
25054
|
-
* @private Internal utility of `BookEditorMonaco`.
|
|
25055
|
-
*/
|
|
25056
|
-
function logBookEditorMonacoDebug(message) {
|
|
25057
|
-
if (!isBookEditorMonacoDebugEnabled()) {
|
|
25058
|
-
return;
|
|
25059
|
-
}
|
|
25060
|
-
console.info(`[BookEditorMonaco] ${message}`);
|
|
25061
|
-
}
|
|
25062
|
-
/**
|
|
25063
|
-
* Lists transferable items from a browser `DataTransfer` object.
|
|
25064
|
-
*
|
|
25065
|
-
* @private Internal utility of `BookEditorMonaco`.
|
|
25066
|
-
*/
|
|
25067
|
-
function listDataTransferItems(dataTransfer) {
|
|
25068
|
-
const items = [];
|
|
25069
|
-
for (let index = 0; index < dataTransfer.items.length; index++) {
|
|
25070
|
-
const item = dataTransfer.items[index];
|
|
25071
|
-
if (item) {
|
|
25072
|
-
items.push(item);
|
|
25073
|
-
}
|
|
25074
|
-
}
|
|
25075
|
-
return items;
|
|
25076
|
-
}
|
|
25077
|
-
/**
|
|
25078
|
-
* Removes duplicate files by using stable file metadata signature.
|
|
25079
|
-
*
|
|
25080
|
-
* @private Internal utility of `BookEditorMonaco`.
|
|
25081
|
-
*/
|
|
25082
|
-
function deduplicateFiles(files) {
|
|
25083
|
-
const uniqueFiles = new Map();
|
|
25084
|
-
for (const file of files) {
|
|
25085
|
-
uniqueFiles.set(`${file.name}:${file.type}:${file.size}`, file);
|
|
25086
|
-
}
|
|
25087
|
-
return Array.from(uniqueFiles.values());
|
|
25088
|
-
}
|
|
25089
|
-
/**
|
|
25090
|
-
* Extracts all file-like clipboard/drop payloads from a `DataTransfer`.
|
|
25091
|
-
*
|
|
25092
|
-
* @private Internal utility of `BookEditorMonaco`.
|
|
25093
|
-
*/
|
|
25094
|
-
function getDataTransferFiles(dataTransfer) {
|
|
25095
|
-
const directFiles = Array.from(dataTransfer.files || []);
|
|
25096
|
-
const itemFiles = listDataTransferItems(dataTransfer)
|
|
25097
|
-
.filter((item) => item.kind === 'file')
|
|
25098
|
-
.map((item) => item.getAsFile())
|
|
25099
|
-
.filter((file) => file !== null);
|
|
25100
|
-
return deduplicateFiles([...directFiles, ...itemFiles]);
|
|
25101
|
-
}
|
|
25461
|
+
const BASE_SCROLLBAR_SIZE = 5;
|
|
25102
25462
|
/**
|
|
25103
|
-
*
|
|
25463
|
+
* Minimum Monaco scrollbar size after zoom scaling.
|
|
25104
25464
|
*
|
|
25105
25465
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25106
25466
|
*/
|
|
25107
|
-
|
|
25108
|
-
const items = listDataTransferItems(dataTransfer);
|
|
25109
|
-
const hasPlainTextItem = items.some((item) => item.kind === 'string' && item.type.toLowerCase() === 'text/plain');
|
|
25110
|
-
const applicationItem = items.find((item) => item.kind === 'string' && item.type.toLowerCase().startsWith('application/'));
|
|
25111
|
-
if (applicationItem) {
|
|
25112
|
-
return applicationItem;
|
|
25113
|
-
}
|
|
25114
|
-
if (hasPlainTextItem) {
|
|
25115
|
-
return null;
|
|
25116
|
-
}
|
|
25117
|
-
const richTextItem = items.find((item) => {
|
|
25118
|
-
if (item.kind !== 'string') {
|
|
25119
|
-
return false;
|
|
25120
|
-
}
|
|
25121
|
-
return RICH_CLIPBOARD_TEXT_MIME_TYPES.has(item.type.toLowerCase());
|
|
25122
|
-
});
|
|
25123
|
-
if (richTextItem) {
|
|
25124
|
-
return richTextItem;
|
|
25125
|
-
}
|
|
25126
|
-
return null;
|
|
25127
|
-
}
|
|
25467
|
+
const MIN_SCROLLBAR_SIZE = 2;
|
|
25128
25468
|
/**
|
|
25129
|
-
*
|
|
25469
|
+
* Minimum left padding Monaco reserves for custom line decorations.
|
|
25130
25470
|
*
|
|
25131
25471
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25132
25472
|
*/
|
|
25133
|
-
|
|
25134
|
-
if (getDataTransferFiles(dataTransfer).length > 0) {
|
|
25135
|
-
return true;
|
|
25136
|
-
}
|
|
25137
|
-
return getRichClipboardTextItem(dataTransfer) !== null;
|
|
25138
|
-
}
|
|
25473
|
+
const MIN_CONTENT_PADDING_LEFT = 8;
|
|
25139
25474
|
/**
|
|
25140
|
-
*
|
|
25475
|
+
* Creates a hydration-stable CSS class name from React's `useId()` value.
|
|
25141
25476
|
*
|
|
25142
25477
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25143
25478
|
*/
|
|
25144
|
-
function
|
|
25145
|
-
return
|
|
25146
|
-
try {
|
|
25147
|
-
item.getAsString((value) => resolve(value || ''));
|
|
25148
|
-
}
|
|
25149
|
-
catch (_a) {
|
|
25150
|
-
resolve('');
|
|
25151
|
-
}
|
|
25152
|
-
});
|
|
25479
|
+
function createStableBookEditorInstanceClassName(reactId) {
|
|
25480
|
+
return `book-editor-instance-${reactId.replace(INVALID_CSS_IDENTIFIER_CHARACTER_PATTERN, '-')}`;
|
|
25153
25481
|
}
|
|
25154
25482
|
/**
|
|
25155
|
-
*
|
|
25483
|
+
* Resolves Monaco layout values from the active Book editor zoom level.
|
|
25156
25484
|
*
|
|
25157
25485
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25158
25486
|
*/
|
|
25159
|
-
function
|
|
25160
|
-
return
|
|
25487
|
+
function createBookEditorMonacoScale(zoomLevel) {
|
|
25488
|
+
return {
|
|
25489
|
+
scaledLineHeight: Math.round(BookEditorMonacoConstants.LINE_HEIGHT * zoomLevel),
|
|
25490
|
+
scaledContentPaddingLeft: Math.max(MIN_CONTENT_PADDING_LEFT, Math.round(BookEditorMonacoConstants.CONTENT_PADDING_LEFT * zoomLevel)),
|
|
25491
|
+
scaledVerticalLineLeft: Math.max(0, Math.round(BookEditorMonacoConstants.VERTICAL_LINE_LEFT * zoomLevel)),
|
|
25492
|
+
scaledFontSize: Math.max(MIN_FONT_SIZE, Math.round(BASE_FONT_SIZE * zoomLevel)),
|
|
25493
|
+
scaledScrollbarSize: Math.max(MIN_SCROLLBAR_SIZE, Math.round(BASE_SCROLLBAR_SIZE * zoomLevel)),
|
|
25494
|
+
};
|
|
25161
25495
|
}
|
|
25162
25496
|
/**
|
|
25163
|
-
*
|
|
25497
|
+
* Determines whether the Book editor action bar should be shown.
|
|
25164
25498
|
*
|
|
25165
25499
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25166
25500
|
*/
|
|
25167
|
-
function
|
|
25168
|
-
return
|
|
25501
|
+
function isBookEditorMonacoActionbarVisible({ hoistedMenuItems, isUploadButtonShown, isCameraButtonShown, isDownloadButtonShown, isAboutButtonShown, isFullscreenButtonShown, }) {
|
|
25502
|
+
return (Boolean(hoistedMenuItems && hoistedMenuItems.length > 0) ||
|
|
25503
|
+
Boolean(isUploadButtonShown) ||
|
|
25504
|
+
Boolean(isCameraButtonShown) ||
|
|
25505
|
+
Boolean(isDownloadButtonShown) ||
|
|
25506
|
+
Boolean(isAboutButtonShown) ||
|
|
25507
|
+
Boolean(isFullscreenButtonShown));
|
|
25169
25508
|
}
|
|
25170
25509
|
/**
|
|
25171
|
-
*
|
|
25510
|
+
* Builds the Monaco editor options consumed by `MonacoEditorWithShadowDom`.
|
|
25172
25511
|
*
|
|
25173
25512
|
* @private Internal utility of `BookEditorMonaco`.
|
|
25174
25513
|
*/
|
|
25175
|
-
|
|
25176
|
-
|
|
25177
|
-
|
|
25178
|
-
|
|
25179
|
-
|
|
25180
|
-
|
|
25181
|
-
|
|
25182
|
-
|
|
25183
|
-
|
|
25184
|
-
|
|
25185
|
-
|
|
25186
|
-
|
|
25187
|
-
|
|
25188
|
-
|
|
25189
|
-
|
|
25514
|
+
function createBookEditorMonacoOptions({ isReadonly, translations, scaledFontSize, scaledLineHeight, scaledContentPaddingLeft, scaledScrollbarSize, }) {
|
|
25515
|
+
return {
|
|
25516
|
+
readOnly: isReadonly,
|
|
25517
|
+
readOnlyMessage: {
|
|
25518
|
+
value: (translations === null || translations === void 0 ? void 0 : translations.readonlyMessage) || 'You cannot edit this book',
|
|
25519
|
+
},
|
|
25520
|
+
wordWrap: 'on',
|
|
25521
|
+
minimap: { enabled: false },
|
|
25522
|
+
lineNumbers: 'off',
|
|
25523
|
+
fontSize: scaledFontSize,
|
|
25524
|
+
fontFamily: `"Playfair Display", serif`,
|
|
25525
|
+
lineHeight: scaledLineHeight,
|
|
25526
|
+
renderLineHighlight: 'none',
|
|
25527
|
+
lineDecorationsWidth: scaledContentPaddingLeft,
|
|
25528
|
+
glyphMargin: false,
|
|
25529
|
+
folding: false,
|
|
25530
|
+
lineNumbersMinChars: 0,
|
|
25531
|
+
links: true,
|
|
25532
|
+
scrollbar: {
|
|
25533
|
+
vertical: 'auto',
|
|
25534
|
+
horizontal: 'hidden',
|
|
25535
|
+
verticalScrollbarSize: scaledScrollbarSize,
|
|
25536
|
+
arrowSize: 0,
|
|
25537
|
+
useShadows: false,
|
|
25538
|
+
},
|
|
25539
|
+
};
|
|
25190
25540
|
}
|
|
25191
25541
|
/**
|
|
25192
25542
|
* Handles book editor monaco.
|
|
@@ -25196,29 +25546,40 @@ async function resolveClipboardUploadFiles(dataTransfer) {
|
|
|
25196
25546
|
function BookEditorMonaco(props) {
|
|
25197
25547
|
const { value, onChange, diagnostics, isReadonly, theme = 'LIGHT', translations, onFileUpload, isUploadButtonShown, isCameraButtonShown, isDownloadButtonShown, isAboutButtonShown = true, isFullscreenButtonShown = true, onFullscreenClick, isFullscreen, zoom = 1, monacoModelPath, hoistedMenuItems, } = props;
|
|
25198
25548
|
const zoomLevel = zoom;
|
|
25199
|
-
const scaledLineHeight =
|
|
25200
|
-
const scaledContentPaddingLeft = Math.max(8, Math.round(BookEditorMonacoConstants.CONTENT_PADDING_LEFT * zoomLevel));
|
|
25201
|
-
const scaledVerticalLineLeft = Math.max(0, Math.round(BookEditorMonacoConstants.VERTICAL_LINE_LEFT * zoomLevel));
|
|
25202
|
-
const baseFontSize = 20;
|
|
25203
|
-
const scaledFontSize = Math.max(8, Math.round(baseFontSize * zoomLevel));
|
|
25204
|
-
const scaledScrollbarSize = Math.max(2, Math.round(5 * zoomLevel));
|
|
25205
|
-
const [isDragOver, setIsDragOver] = useState(false);
|
|
25206
|
-
const [editor, setEditor] = useState(null);
|
|
25207
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
25208
|
-
const [isTouchDevice, setIsTouchDevice] = useState(false);
|
|
25209
|
-
const [isSavedShown, setIsSavedShown] = useState(false);
|
|
25549
|
+
const { scaledLineHeight, scaledContentPaddingLeft, scaledVerticalLineLeft, scaledFontSize, scaledScrollbarSize } = createBookEditorMonacoScale(zoomLevel);
|
|
25210
25550
|
const monaco = useMonaco();
|
|
25211
25551
|
const reactId = useId();
|
|
25212
25552
|
const instanceClass = createStableBookEditorInstanceClassName(reactId);
|
|
25213
|
-
const
|
|
25214
|
-
|
|
25215
|
-
|
|
25553
|
+
const { editor, isFocused, isTouchDevice, isSavedShown, handleBeforeMonacoMount, handleMonacoMount } = useBookEditorMonacoLifecycle({
|
|
25554
|
+
monaco,
|
|
25555
|
+
theme,
|
|
25556
|
+
});
|
|
25216
25557
|
const { activeUploadItems, uploadStats, pauseUpload, resumeUpload, handleFiles } = useBookEditorMonacoUploads({
|
|
25217
25558
|
editor,
|
|
25218
25559
|
monaco,
|
|
25219
25560
|
onFileUpload,
|
|
25220
25561
|
});
|
|
25562
|
+
const { isDragOver, fileUploadInputRef, cameraInputRef, handleDrop, handlePaste, handleUploadDocument, handleTakePhoto, handleFileInputChange, handleDragOver, handleDragEnter, handleDragLeave, focusOverlayTouchHandlers, } = useBookEditorMonacoInteractions({
|
|
25563
|
+
editor,
|
|
25564
|
+
handleFiles,
|
|
25565
|
+
});
|
|
25221
25566
|
const combinedDiagnostics = [...(diagnostics || []), ...createDeprecatedCommitmentDiagnostics(value)];
|
|
25567
|
+
const isActionBarVisible = isBookEditorMonacoActionbarVisible({
|
|
25568
|
+
hoistedMenuItems,
|
|
25569
|
+
isUploadButtonShown,
|
|
25570
|
+
isCameraButtonShown,
|
|
25571
|
+
isDownloadButtonShown,
|
|
25572
|
+
isAboutButtonShown,
|
|
25573
|
+
isFullscreenButtonShown,
|
|
25574
|
+
});
|
|
25575
|
+
const monacoOptions = createBookEditorMonacoOptions({
|
|
25576
|
+
isReadonly,
|
|
25577
|
+
translations,
|
|
25578
|
+
scaledFontSize,
|
|
25579
|
+
scaledLineHeight,
|
|
25580
|
+
scaledContentPaddingLeft,
|
|
25581
|
+
scaledScrollbarSize,
|
|
25582
|
+
});
|
|
25222
25583
|
useBookEditorMonacoLanguage({ monaco, theme });
|
|
25223
25584
|
useBookEditorMonacoDiagnostics({ monaco, editor, diagnostics: combinedDiagnostics });
|
|
25224
25585
|
useBookEditorMonacoDecorations({ editor, monaco });
|
|
@@ -25230,171 +25591,6 @@ function BookEditorMonaco(props) {
|
|
|
25230
25591
|
zoomLevel,
|
|
25231
25592
|
theme,
|
|
25232
25593
|
});
|
|
25233
|
-
/**
|
|
25234
|
-
* Re-applies Book language + theme to the currently mounted Monaco model.
|
|
25235
|
-
*/
|
|
25236
|
-
const reapplyBookLanguageAndTheme = useCallback((reason) => {
|
|
25237
|
-
if (!editor || !monaco) {
|
|
25238
|
-
return;
|
|
25239
|
-
}
|
|
25240
|
-
ensureBookEditorMonacoLanguageForEditor({ monaco, monacoEditor: editor, theme });
|
|
25241
|
-
logBookEditorMonacoDebug(`Re-applied Book Monaco language/theme (${reason}).`);
|
|
25242
|
-
}, [editor, monaco, theme]);
|
|
25243
|
-
useEffect(() => {
|
|
25244
|
-
setIsTouchDevice(typeof window !== 'undefined' && window.matchMedia('(pointer: coarse)').matches);
|
|
25245
|
-
}, []);
|
|
25246
|
-
useEffect(() => {
|
|
25247
|
-
if (!editor || !monaco) {
|
|
25248
|
-
return;
|
|
25249
|
-
}
|
|
25250
|
-
const focusListener = editor.onDidFocusEditorWidget(() => {
|
|
25251
|
-
setIsFocused(true);
|
|
25252
|
-
reapplyBookLanguageAndTheme('focus');
|
|
25253
|
-
});
|
|
25254
|
-
const blurListener = editor.onDidBlurEditorWidget(() => {
|
|
25255
|
-
setIsFocused(false);
|
|
25256
|
-
});
|
|
25257
|
-
const saveAction = editor.addAction({
|
|
25258
|
-
id: 'save-book',
|
|
25259
|
-
label: 'Save',
|
|
25260
|
-
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
|
|
25261
|
-
run: () => {
|
|
25262
|
-
setIsSavedShown(false);
|
|
25263
|
-
setTimeout(() => setIsSavedShown(true), 0);
|
|
25264
|
-
// Note: We don't prevent default, so browser's save dialog still opens
|
|
25265
|
-
},
|
|
25266
|
-
});
|
|
25267
|
-
return () => {
|
|
25268
|
-
focusListener.dispose();
|
|
25269
|
-
blurListener.dispose();
|
|
25270
|
-
saveAction.dispose();
|
|
25271
|
-
};
|
|
25272
|
-
}, [editor, monaco, reapplyBookLanguageAndTheme]);
|
|
25273
|
-
useEffect(() => {
|
|
25274
|
-
reapplyBookLanguageAndTheme('editor-ready');
|
|
25275
|
-
}, [reapplyBookLanguageAndTheme]);
|
|
25276
|
-
useEffect(() => {
|
|
25277
|
-
if (!editor || !monaco) {
|
|
25278
|
-
return;
|
|
25279
|
-
}
|
|
25280
|
-
const handlePopState = () => {
|
|
25281
|
-
reapplyBookLanguageAndTheme('history-popstate');
|
|
25282
|
-
};
|
|
25283
|
-
const handlePageShow = () => {
|
|
25284
|
-
reapplyBookLanguageAndTheme('pageshow');
|
|
25285
|
-
};
|
|
25286
|
-
const handleWindowFocus = () => {
|
|
25287
|
-
reapplyBookLanguageAndTheme('window-focus');
|
|
25288
|
-
};
|
|
25289
|
-
const handleVisibilityChange = () => {
|
|
25290
|
-
if (document.visibilityState === 'visible') {
|
|
25291
|
-
reapplyBookLanguageAndTheme('visibility-visible');
|
|
25292
|
-
}
|
|
25293
|
-
};
|
|
25294
|
-
window.addEventListener('popstate', handlePopState);
|
|
25295
|
-
window.addEventListener('pageshow', handlePageShow);
|
|
25296
|
-
window.addEventListener('focus', handleWindowFocus);
|
|
25297
|
-
document.addEventListener('visibilitychange', handleVisibilityChange);
|
|
25298
|
-
return () => {
|
|
25299
|
-
window.removeEventListener('popstate', handlePopState);
|
|
25300
|
-
window.removeEventListener('pageshow', handlePageShow);
|
|
25301
|
-
window.removeEventListener('focus', handleWindowFocus);
|
|
25302
|
-
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
25303
|
-
};
|
|
25304
|
-
}, [editor, monaco, reapplyBookLanguageAndTheme]);
|
|
25305
|
-
useEffect(() => {
|
|
25306
|
-
if (!isSavedShown) {
|
|
25307
|
-
return;
|
|
25308
|
-
}
|
|
25309
|
-
const timer = setTimeout(() => {
|
|
25310
|
-
setIsSavedShown(false);
|
|
25311
|
-
}, 2000);
|
|
25312
|
-
return () => {
|
|
25313
|
-
clearTimeout(timer);
|
|
25314
|
-
};
|
|
25315
|
-
}, [isSavedShown]);
|
|
25316
|
-
const handleDrop = useCallback(async (event) => {
|
|
25317
|
-
event.preventDefault();
|
|
25318
|
-
setIsDragOver(false);
|
|
25319
|
-
const files = getDataTransferFiles(event.dataTransfer);
|
|
25320
|
-
await handleFiles(files);
|
|
25321
|
-
}, [handleFiles]);
|
|
25322
|
-
const handlePaste = useCallback(async (event) => {
|
|
25323
|
-
const clipboardData = event.clipboardData;
|
|
25324
|
-
if (!hasUploadableClipboardContent(clipboardData)) {
|
|
25325
|
-
return;
|
|
25326
|
-
}
|
|
25327
|
-
event.preventDefault();
|
|
25328
|
-
event.stopPropagation();
|
|
25329
|
-
const files = await resolveClipboardUploadFiles(clipboardData);
|
|
25330
|
-
await handleFiles(files);
|
|
25331
|
-
}, [handleFiles]);
|
|
25332
|
-
const handleUploadDocument = useCallback(() => {
|
|
25333
|
-
var _a;
|
|
25334
|
-
(_a = fileUploadInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
25335
|
-
}, []);
|
|
25336
|
-
const handleTakePhoto = useCallback(() => {
|
|
25337
|
-
var _a;
|
|
25338
|
-
(_a = cameraInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
25339
|
-
}, []);
|
|
25340
|
-
const handleFileInputChange = useCallback((event) => {
|
|
25341
|
-
const files = Array.from(event.target.files || []);
|
|
25342
|
-
void handleFiles(files);
|
|
25343
|
-
event.target.value = '';
|
|
25344
|
-
}, [handleFiles]);
|
|
25345
|
-
/**
|
|
25346
|
-
* Ensures Book language/tokenizer is ready before Monaco creates the editor model.
|
|
25347
|
-
*/
|
|
25348
|
-
const handleBeforeMonacoMount = useCallback((beforeMountMonaco) => {
|
|
25349
|
-
ensureBookEditorMonacoLanguage(beforeMountMonaco, theme);
|
|
25350
|
-
}, [theme]);
|
|
25351
|
-
/**
|
|
25352
|
-
* Re-applies Book language/theme once Monaco editor is mounted.
|
|
25353
|
-
*/
|
|
25354
|
-
const handleMonacoMount = useCallback((mountedEditor, mountedMonaco) => {
|
|
25355
|
-
setEditor(mountedEditor);
|
|
25356
|
-
ensureBookEditorMonacoLanguageForEditor({ monaco: mountedMonaco, monacoEditor: mountedEditor, theme });
|
|
25357
|
-
logBookEditorMonacoDebug('Mounted Monaco editor and re-applied Book language/theme.');
|
|
25358
|
-
}, [theme]);
|
|
25359
|
-
const handleDragOver = useCallback((event) => {
|
|
25360
|
-
event.preventDefault();
|
|
25361
|
-
setIsDragOver(true);
|
|
25362
|
-
}, []);
|
|
25363
|
-
const handleDragEnter = useCallback((event) => {
|
|
25364
|
-
event.preventDefault();
|
|
25365
|
-
setIsDragOver(true);
|
|
25366
|
-
}, []);
|
|
25367
|
-
const handleDragLeave = useCallback((event) => {
|
|
25368
|
-
event.preventDefault();
|
|
25369
|
-
setIsDragOver(false);
|
|
25370
|
-
}, []);
|
|
25371
|
-
const focusOverlayTouchHandlers = {
|
|
25372
|
-
onTouchStart: (event) => {
|
|
25373
|
-
const touch = event.touches[0];
|
|
25374
|
-
if (touch) {
|
|
25375
|
-
touchStartRef.current = { x: touch.clientX, y: touch.clientY };
|
|
25376
|
-
}
|
|
25377
|
-
},
|
|
25378
|
-
onTouchEnd: (event) => {
|
|
25379
|
-
event.preventDefault();
|
|
25380
|
-
const touch = event.changedTouches[0];
|
|
25381
|
-
if (touch && touchStartRef.current) {
|
|
25382
|
-
const deltaX = Math.abs(touch.clientX - touchStartRef.current.x);
|
|
25383
|
-
const deltaY = Math.abs(touch.clientY - touchStartRef.current.y);
|
|
25384
|
-
const threshold = 10;
|
|
25385
|
-
if (deltaX < threshold && deltaY < threshold) {
|
|
25386
|
-
editor === null || editor === void 0 ? void 0 : editor.focus();
|
|
25387
|
-
}
|
|
25388
|
-
}
|
|
25389
|
-
touchStartRef.current = null;
|
|
25390
|
-
},
|
|
25391
|
-
};
|
|
25392
|
-
const isActionBarVisible = Boolean(hoistedMenuItems && hoistedMenuItems.length > 0) ||
|
|
25393
|
-
isUploadButtonShown ||
|
|
25394
|
-
isCameraButtonShown ||
|
|
25395
|
-
isDownloadButtonShown ||
|
|
25396
|
-
isAboutButtonShown ||
|
|
25397
|
-
isFullscreenButtonShown;
|
|
25398
25594
|
return (jsxs("div", { className: classNames(styles$d.bookEditorContainer, instanceClass), onDrop: handleDrop, onPaste: handlePaste, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, children: [isActionBarVisible && (jsx(BookEditorActionbar, { value,
|
|
25399
25595
|
isUploadButtonShown,
|
|
25400
25596
|
isCameraButtonShown: isCameraButtonShown !== null && isCameraButtonShown !== void 0 ? isCameraButtonShown : isTouchDevice,
|
|
@@ -25420,31 +25616,7 @@ function BookEditorMonaco(props) {
|
|
|
25420
25616
|
height: '100%',
|
|
25421
25617
|
width: '100%',
|
|
25422
25618
|
backgroundColor: 'transparent',
|
|
25423
|
-
}, ...focusOverlayTouchHandlers })), jsx(MonacoEditorWithShadowDom, { language: BookEditorMonacoConstants.BOOK_LANGUAGE_ID, theme: BookEditorMonacoConstants.BOOK_THEME_ID, path: monacoModelPath, saveViewState: Boolean(monacoModelPath), value: value, beforeMount: handleBeforeMonacoMount, onMount: handleMonacoMount, onChange: (newValue) => onChange === null || onChange === void 0 ? void 0 : onChange(newValue), options: {
|
|
25424
|
-
readOnly: isReadonly,
|
|
25425
|
-
readOnlyMessage: {
|
|
25426
|
-
value: (translations === null || translations === void 0 ? void 0 : translations.readonlyMessage) || 'You cannot edit this book',
|
|
25427
|
-
},
|
|
25428
|
-
wordWrap: 'on',
|
|
25429
|
-
minimap: { enabled: false },
|
|
25430
|
-
lineNumbers: 'off',
|
|
25431
|
-
fontSize: scaledFontSize,
|
|
25432
|
-
fontFamily: `"Playfair Display", serif`,
|
|
25433
|
-
lineHeight: scaledLineHeight,
|
|
25434
|
-
renderLineHighlight: 'none',
|
|
25435
|
-
lineDecorationsWidth: scaledContentPaddingLeft,
|
|
25436
|
-
glyphMargin: false,
|
|
25437
|
-
folding: false,
|
|
25438
|
-
lineNumbersMinChars: 0,
|
|
25439
|
-
links: true,
|
|
25440
|
-
scrollbar: {
|
|
25441
|
-
vertical: 'auto',
|
|
25442
|
-
horizontal: 'hidden',
|
|
25443
|
-
verticalScrollbarSize: scaledScrollbarSize,
|
|
25444
|
-
arrowSize: 0,
|
|
25445
|
-
useShadows: false,
|
|
25446
|
-
},
|
|
25447
|
-
}, loading: jsx("div", { className: styles$d.loading, children: "\uD83D\uDCD6" }) })] })] }));
|
|
25619
|
+
}, ...focusOverlayTouchHandlers })), jsx(MonacoEditorWithShadowDom, { language: BookEditorMonacoConstants.BOOK_LANGUAGE_ID, theme: BookEditorMonacoConstants.BOOK_THEME_ID, path: monacoModelPath, saveViewState: Boolean(monacoModelPath), value: value, beforeMount: handleBeforeMonacoMount, onMount: handleMonacoMount, onChange: (newValue) => onChange === null || onChange === void 0 ? void 0 : onChange(newValue), options: monacoOptions, loading: jsx("div", { className: styles$d.loading, children: "\uD83D\uDCD6" }) })] })] }));
|
|
25448
25620
|
}
|
|
25449
25621
|
|
|
25450
25622
|
/**
|
|
@@ -36204,7 +36376,7 @@ function createExampleInteractionsContent(parseResult, samples) {
|
|
|
36204
36376
|
if (examples.length === 0) {
|
|
36205
36377
|
return null;
|
|
36206
36378
|
}
|
|
36207
|
-
return
|
|
36379
|
+
return `## Sample of communication with the agent:\n\n${examples.join('\n\n')}`;
|
|
36208
36380
|
}
|
|
36209
36381
|
/**
|
|
36210
36382
|
* Collects the individual lines used in the example interaction section.
|
|
@@ -36220,11 +36392,11 @@ function collectExampleInteractionLines(parseResult, samples) {
|
|
|
36220
36392
|
const examples = [];
|
|
36221
36393
|
const initialMessage = (_a = parseResult.commitments.find((commitment) => commitment.type === 'INITIAL MESSAGE')) === null || _a === void 0 ? void 0 : _a.content;
|
|
36222
36394
|
if (initialMessage) {
|
|
36223
|
-
examples.push(
|
|
36395
|
+
examples.push(`**Agent:**\n${initialMessage}`);
|
|
36224
36396
|
}
|
|
36225
36397
|
if (samples && samples.length > 0) {
|
|
36226
36398
|
for (const sample of samples) {
|
|
36227
|
-
examples.push(
|
|
36399
|
+
examples.push(`**User:** ${sample.question}\n\n**Agent:**\n${sample.answer}`);
|
|
36228
36400
|
}
|
|
36229
36401
|
}
|
|
36230
36402
|
return examples;
|
|
@@ -41061,8 +41233,8 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
|
|
|
41061
41233
|
* Prepares an AgentKit agent with optional knowledge sources and tool definitions.
|
|
41062
41234
|
*/
|
|
41063
41235
|
async prepareAgentKitAgent(options) {
|
|
41064
|
-
var _a, _b;
|
|
41065
|
-
const { name, instructions, knowledgeSources, tools, vectorStoreId: cachedVectorStoreId, storeAsPrepared, } = options;
|
|
41236
|
+
var _a, _b, _c;
|
|
41237
|
+
const { name, instructions, knowledgeSources, tools, nativeAgentKitTools, vectorStoreId: cachedVectorStoreId, storeAsPrepared, } = options;
|
|
41066
41238
|
await this.ensureAgentKitDefaults();
|
|
41067
41239
|
if (this.options.isVerbose) {
|
|
41068
41240
|
console.info('[🤰]', 'Preparing OpenAI AgentKit agent', {
|
|
@@ -41070,6 +41242,7 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
|
|
|
41070
41242
|
instructionsLength: instructions.length,
|
|
41071
41243
|
knowledgeSourcesCount: (_a = knowledgeSources === null || knowledgeSources === void 0 ? void 0 : knowledgeSources.length) !== null && _a !== void 0 ? _a : 0,
|
|
41072
41244
|
toolsCount: (_b = tools === null || tools === void 0 ? void 0 : tools.length) !== null && _b !== void 0 ? _b : 0,
|
|
41245
|
+
nativeAgentKitToolsCount: (_c = nativeAgentKitTools === null || nativeAgentKitTools === void 0 ? void 0 : nativeAgentKitTools.length) !== null && _c !== void 0 ? _c : 0,
|
|
41073
41246
|
});
|
|
41074
41247
|
}
|
|
41075
41248
|
let vectorStoreId = cachedVectorStoreId;
|
|
@@ -41088,7 +41261,7 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
|
|
|
41088
41261
|
vectorStoreId,
|
|
41089
41262
|
});
|
|
41090
41263
|
}
|
|
41091
|
-
const agentKitTools = this.buildAgentKitTools({ tools, vectorStoreId });
|
|
41264
|
+
const agentKitTools = this.buildAgentKitTools({ tools, nativeAgentKitTools, vectorStoreId });
|
|
41092
41265
|
const openAiAgentKitAgent = new Agent$1({
|
|
41093
41266
|
name,
|
|
41094
41267
|
model: this.agentKitModelName,
|
|
@@ -41127,11 +41300,14 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
|
|
|
41127
41300
|
* Builds the tool list for AgentKit, including hosted file search when applicable.
|
|
41128
41301
|
*/
|
|
41129
41302
|
buildAgentKitTools(options) {
|
|
41130
|
-
const { tools, vectorStoreId } = options;
|
|
41303
|
+
const { tools, nativeAgentKitTools, vectorStoreId } = options;
|
|
41131
41304
|
const agentKitTools = [];
|
|
41132
41305
|
if (vectorStoreId) {
|
|
41133
41306
|
agentKitTools.push(fileSearchTool(vectorStoreId));
|
|
41134
41307
|
}
|
|
41308
|
+
if (nativeAgentKitTools && nativeAgentKitTools.length > 0) {
|
|
41309
|
+
agentKitTools.push(...nativeAgentKitTools);
|
|
41310
|
+
}
|
|
41135
41311
|
if (tools && tools.length > 0) {
|
|
41136
41312
|
let scriptTools = null;
|
|
41137
41313
|
for (const toolDefinition of tools) {
|