@promptbook/components 0.105.0-11 → 0.105.0-12
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 +98 -27
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/execution/AvailableModel.d.ts +5 -4
- package/esm/typings/src/llm-providers/google/createGoogleExecutionTools.d.ts +1 -0
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +2 -2
- package/esm/typings/src/llm-providers/openai/utils/uploadFilesToOpenAi.d.ts +7 -0
- package/esm/typings/src/speech-recognition/OpenAiSpeechRecognition.d.ts +3 -0
- package/esm/typings/src/types/Prompt.d.ts +4 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +98 -27
- package/umd/index.umd.js.map +1 -1
package/esm/index.es.js
CHANGED
|
@@ -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.105.0-
|
|
38
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.105.0-12';
|
|
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
|
|
@@ -11456,7 +11456,9 @@ const ChatMessageItem = memo(({ message, participant, participants, isLastMessag
|
|
|
11456
11456
|
const toolInfo = TOOL_TITLES[toolCall.name];
|
|
11457
11457
|
const toolTitle = (toolTitles === null || toolTitles === void 0 ? void 0 : toolTitles[toolCall.name]) || (toolInfo === null || toolInfo === void 0 ? void 0 : toolInfo.title);
|
|
11458
11458
|
const emoji = (toolInfo === null || toolInfo === void 0 ? void 0 : toolInfo.emoji) || '🛠️';
|
|
11459
|
-
return (jsxs("div", { className: chatStyles.ongoingToolCall, children: [jsx("div", { className: chatStyles.ongoingToolCallSpinner }), jsx("span", { className: chatStyles.ongoingToolCallName, children: toolTitle
|
|
11459
|
+
return (jsxs("div", { className: chatStyles.ongoingToolCall, children: [jsx("div", { className: chatStyles.ongoingToolCallSpinner }), jsx("span", { className: chatStyles.ongoingToolCallName, children: toolTitle
|
|
11460
|
+
? `${emoji} ${toolTitle}...`
|
|
11461
|
+
: `${emoji} Executing ${toolCall.name}...` })] }, index));
|
|
11460
11462
|
})) : (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) => {
|
|
11461
11463
|
event.stopPropagation();
|
|
11462
11464
|
if (onMessage) {
|
|
@@ -11576,7 +11578,6 @@ function Chat(props) {
|
|
|
11576
11578
|
const [isUploading, setIsUploading] = useState(false);
|
|
11577
11579
|
// Voice recognition state
|
|
11578
11580
|
const [speechRecognitionState, setSpeechRecognitionState] = useState('IDLE');
|
|
11579
|
-
const [speechRecognitionText, setSpeechRecognitionText] = useState('');
|
|
11580
11581
|
// Use mobile detection from the hook
|
|
11581
11582
|
const isMobile = isMobileFromHook;
|
|
11582
11583
|
useEffect(( /* Focus textarea on page load */) => {
|
|
@@ -11597,23 +11598,16 @@ function Chat(props) {
|
|
|
11597
11598
|
const unsubscribe = speechRecognition.subscribe((event) => {
|
|
11598
11599
|
if (event.type === 'START') {
|
|
11599
11600
|
setSpeechRecognitionState('RECORDING');
|
|
11600
|
-
setSpeechRecognitionText('');
|
|
11601
11601
|
}
|
|
11602
11602
|
else if (event.type === 'RESULT') {
|
|
11603
|
-
|
|
11603
|
+
// [🧠] Note: This logic assumes that interim results are being updated.
|
|
11604
|
+
// For OpenAiSpeechRecognition, it's just one final result.
|
|
11604
11605
|
if (textareaRef.current) {
|
|
11605
11606
|
const textarea = textareaRef.current;
|
|
11606
11607
|
const currentValue = textarea.value;
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
textarea.value = currentValue.slice(0, -lastResult.length) + event.text;
|
|
11611
|
-
}
|
|
11612
|
-
else {
|
|
11613
|
-
// Otherwise just append with a space if needed
|
|
11614
|
-
const separator = currentValue && !currentValue.endsWith(' ') ? ' ' : '';
|
|
11615
|
-
textarea.value += separator + event.text;
|
|
11616
|
-
}
|
|
11608
|
+
// Append the transcribed text with a space if needed
|
|
11609
|
+
const separator = currentValue && !currentValue.endsWith(' ') && !currentValue.endsWith('\n') ? ' ' : '';
|
|
11610
|
+
textarea.value += separator + event.text;
|
|
11617
11611
|
if (onChange) {
|
|
11618
11612
|
onChange(textarea.value);
|
|
11619
11613
|
}
|
|
@@ -11625,13 +11619,12 @@ function Chat(props) {
|
|
|
11625
11619
|
}
|
|
11626
11620
|
else if (event.type === 'STOP') {
|
|
11627
11621
|
setSpeechRecognitionState('IDLE');
|
|
11628
|
-
setSpeechRecognitionText('');
|
|
11629
11622
|
}
|
|
11630
11623
|
});
|
|
11631
11624
|
return () => {
|
|
11632
11625
|
unsubscribe();
|
|
11633
11626
|
};
|
|
11634
|
-
}, [speechRecognition, onChange
|
|
11627
|
+
}, [speechRecognition, onChange]);
|
|
11635
11628
|
const handleToggleVoiceInput = useCallback(() => {
|
|
11636
11629
|
if (!speechRecognition) {
|
|
11637
11630
|
return;
|
|
@@ -11688,6 +11681,15 @@ function Chat(props) {
|
|
|
11688
11681
|
event.preventDefault();
|
|
11689
11682
|
setIsDragOver(false);
|
|
11690
11683
|
}, []);
|
|
11684
|
+
const handlePaste = useCallback((event) => {
|
|
11685
|
+
if (!onFileUpload)
|
|
11686
|
+
return;
|
|
11687
|
+
const files = event.clipboardData.files;
|
|
11688
|
+
if (files.length > 0) {
|
|
11689
|
+
// event.preventDefault(); // [🧠] Do NOT prevent default, because we want to allow pasting text too
|
|
11690
|
+
handleFileUpload(files);
|
|
11691
|
+
}
|
|
11692
|
+
}, [onFileUpload, handleFileUpload]);
|
|
11691
11693
|
const handleFileInputChange = useCallback((event) => {
|
|
11692
11694
|
const files = event.target.files;
|
|
11693
11695
|
if (files && files.length > 0) {
|
|
@@ -11934,7 +11936,7 @@ function Chat(props) {
|
|
|
11934
11936
|
'--brand-color': buttonColor.toHex(),
|
|
11935
11937
|
}, children: [jsx("textarea", { ref: (element) => {
|
|
11936
11938
|
textareaRef.current = element;
|
|
11937
|
-
}, style: {
|
|
11939
|
+
}, onPaste: handlePaste, style: {
|
|
11938
11940
|
height: Math.max(countLines(((_b = textareaRef.current) === null || _b === void 0 ? void 0 : _b.value) || defaultMessage || ''), (((_c = textareaRef.current) === null || _c === void 0 ? void 0 : _c.value) || defaultMessage || '').split('\n')
|
|
11939
11941
|
.length, 3) *
|
|
11940
11942
|
25 +
|
|
@@ -12002,13 +12004,27 @@ function Chat(props) {
|
|
|
12002
12004
|
? JSON.parse(selectedToolCall.arguments)
|
|
12003
12005
|
: selectedToolCall.arguments || {};
|
|
12004
12006
|
const resultRaw = selectedToolCall.result;
|
|
12005
|
-
|
|
12007
|
+
let results = Array.isArray(resultRaw)
|
|
12006
12008
|
? resultRaw
|
|
12007
12009
|
: resultRaw && typeof resultRaw === 'object' && Array.isArray(resultRaw.results)
|
|
12008
12010
|
? resultRaw.results
|
|
12009
12011
|
: [];
|
|
12012
|
+
// [🧠] In Agent Server, search result might be wrapped in another result object
|
|
12013
|
+
if (results.length === 0 &&
|
|
12014
|
+
resultRaw &&
|
|
12015
|
+
typeof resultRaw === 'object' &&
|
|
12016
|
+
resultRaw.result) {
|
|
12017
|
+
const subResult = resultRaw.result;
|
|
12018
|
+
results = Array.isArray(subResult)
|
|
12019
|
+
? subResult
|
|
12020
|
+
: subResult && typeof subResult === 'object' && Array.isArray(subResult.results)
|
|
12021
|
+
? subResult.results
|
|
12022
|
+
: [];
|
|
12023
|
+
}
|
|
12010
12024
|
if (isSearch) {
|
|
12011
|
-
return (jsxs(Fragment, { children: [jsxs("div", { className: chatStyles.searchModalHeader, children: [jsx("span", { className: chatStyles.searchModalIcon, children: "\uD83D\uDD0E" }), jsx("h3", { className: chatStyles.searchModalQuery, children: args.query || 'Search Results' })] }), jsx("div", { className: chatStyles.searchModalContent, children: results.length > 0 ? (jsx("div", { className: chatStyles.searchResultsList, children: results.map((item, i) => (jsxs("div", { className: chatStyles.searchResultItem, children: [jsx("div", { className: chatStyles.searchResultUrl, children: item.url && (jsx("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url })) }), jsx("h4", { className: chatStyles.searchResultTitle, children: item.url ? (jsx("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.title || 'Untitled' })) : (item.title || 'Untitled') }), jsx("p", { className: chatStyles.searchResultSnippet, children: item.snippet || item.content || '' })] }, i))) })) : (jsx("div", { className: chatStyles.noResults, children: resultRaw
|
|
12025
|
+
return (jsxs(Fragment, { children: [jsxs("div", { className: chatStyles.searchModalHeader, children: [jsx("span", { className: chatStyles.searchModalIcon, children: "\uD83D\uDD0E" }), jsx("h3", { className: chatStyles.searchModalQuery, children: args.query || args.searchText || 'Search Results' })] }), jsx("div", { className: chatStyles.searchModalContent, children: results.length > 0 ? (jsx("div", { className: chatStyles.searchResultsList, children: results.map((item, i) => (jsxs("div", { className: chatStyles.searchResultItem, children: [jsx("div", { className: chatStyles.searchResultUrl, children: item.url && (jsx("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url })) }), jsx("h4", { className: chatStyles.searchResultTitle, children: item.url ? (jsx("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.title || 'Untitled' })) : (item.title || 'Untitled') }), jsx("p", { className: chatStyles.searchResultSnippet, children: item.snippet || item.content || '' })] }, i))) })) : (jsx("div", { className: chatStyles.noResults, children: resultRaw
|
|
12026
|
+
? 'No search results found.'
|
|
12027
|
+
: 'Search results are not available.' })) })] }));
|
|
12012
12028
|
}
|
|
12013
12029
|
// Fallback for other tools
|
|
12014
12030
|
return (jsxs(Fragment, { children: [jsxs("h3", { children: ["Tool Call: ", (toolTitles === null || toolTitles === void 0 ? void 0 : toolTitles[selectedToolCall.name]) || selectedToolCall.name] }), jsxs("div", { className: chatStyles.toolCallDetails, children: [jsx("p", { children: jsx("strong", { children: "Arguments:" }) }), jsx("div", { className: chatStyles.toolCallDataContainer, children: args && typeof args === 'object' ? (jsx("ul", { className: chatStyles.toolCallArgsList, children: Object.entries(args).map(([key, value]) => (jsxs("li", { children: [jsxs("strong", { children: [key, ":"] }), ' ', typeof value === 'object'
|
|
@@ -18361,11 +18377,35 @@ class OpenAiCompatibleExecutionTools {
|
|
|
18361
18377
|
},
|
|
18362
18378
|
]),
|
|
18363
18379
|
...threadMessages,
|
|
18364
|
-
|
|
18380
|
+
];
|
|
18381
|
+
if ('files' in prompt && Array.isArray(prompt.files) && prompt.files.length > 0) {
|
|
18382
|
+
const filesContent = await Promise.all(prompt.files.map(async (file) => {
|
|
18383
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
18384
|
+
const base64 = Buffer.from(arrayBuffer).toString('base64');
|
|
18385
|
+
return {
|
|
18386
|
+
type: 'image_url',
|
|
18387
|
+
image_url: {
|
|
18388
|
+
url: `data:${file.type};base64,${base64}`,
|
|
18389
|
+
},
|
|
18390
|
+
};
|
|
18391
|
+
}));
|
|
18392
|
+
messages.push({
|
|
18393
|
+
role: 'user',
|
|
18394
|
+
content: [
|
|
18395
|
+
{
|
|
18396
|
+
type: 'text',
|
|
18397
|
+
text: rawPromptContent,
|
|
18398
|
+
},
|
|
18399
|
+
...filesContent,
|
|
18400
|
+
],
|
|
18401
|
+
});
|
|
18402
|
+
}
|
|
18403
|
+
else {
|
|
18404
|
+
messages.push({
|
|
18365
18405
|
role: 'user',
|
|
18366
18406
|
content: rawPromptContent,
|
|
18367
|
-
}
|
|
18368
|
-
|
|
18407
|
+
});
|
|
18408
|
+
}
|
|
18369
18409
|
let totalUsage = {
|
|
18370
18410
|
price: uncertainNumber(0),
|
|
18371
18411
|
input: {
|
|
@@ -19148,6 +19188,27 @@ class OpenAiExecutionTools extends OpenAiCompatibleExecutionTools {
|
|
|
19148
19188
|
}
|
|
19149
19189
|
}
|
|
19150
19190
|
|
|
19191
|
+
/**
|
|
19192
|
+
* Uploads files to OpenAI and returns their IDs
|
|
19193
|
+
*
|
|
19194
|
+
* @private utility for `OpenAiAssistantExecutionTools` and `OpenAiCompatibleExecutionTools`
|
|
19195
|
+
*/
|
|
19196
|
+
async function uploadFilesToOpenAi(client, files) {
|
|
19197
|
+
const fileIds = [];
|
|
19198
|
+
for (const file of files) {
|
|
19199
|
+
// Note: OpenAI API expects a File object or a ReadStream
|
|
19200
|
+
// In browser environment, we can pass the File object directly
|
|
19201
|
+
// In Node.js environment, we might need to convert it or use a different approach
|
|
19202
|
+
// But since `Prompt.files` already contains `File` objects, we try to pass them directly
|
|
19203
|
+
const uploadedFile = await client.files.create({
|
|
19204
|
+
file: file,
|
|
19205
|
+
purpose: 'assistants',
|
|
19206
|
+
});
|
|
19207
|
+
fileIds.push(uploadedFile.id);
|
|
19208
|
+
}
|
|
19209
|
+
return fileIds;
|
|
19210
|
+
}
|
|
19211
|
+
|
|
19151
19212
|
/**
|
|
19152
19213
|
* Execution Tools for calling OpenAI API Assistants
|
|
19153
19214
|
*
|
|
@@ -19244,16 +19305,26 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
19244
19305
|
const threadMessages = [];
|
|
19245
19306
|
// TODO: [🈹] Maybe this should not be here but in other place, look at commit 39d705e75e5bcf7a818c3af36bc13e1c8475c30c
|
|
19246
19307
|
// Add previous messages from thread (if any)
|
|
19247
|
-
if ('thread' in prompt &&
|
|
19248
|
-
Array.isArray(prompt.thread)) {
|
|
19308
|
+
if ('thread' in prompt && Array.isArray(prompt.thread)) {
|
|
19249
19309
|
const previousMessages = prompt.thread.map((msg) => ({
|
|
19250
|
-
role: (msg.
|
|
19310
|
+
role: (msg.sender === 'assistant' ? 'assistant' : 'user'),
|
|
19251
19311
|
content: msg.content,
|
|
19252
19312
|
}));
|
|
19253
19313
|
threadMessages.push(...previousMessages);
|
|
19254
19314
|
}
|
|
19255
19315
|
// Always add the current user message
|
|
19256
|
-
|
|
19316
|
+
const currentUserMessage = {
|
|
19317
|
+
role: 'user',
|
|
19318
|
+
content: rawPromptContent,
|
|
19319
|
+
};
|
|
19320
|
+
if ('files' in prompt && Array.isArray(prompt.files) && prompt.files.length > 0) {
|
|
19321
|
+
const fileIds = await uploadFilesToOpenAi(client, prompt.files);
|
|
19322
|
+
currentUserMessage.attachments = fileIds.map((fileId) => ({
|
|
19323
|
+
file_id: fileId,
|
|
19324
|
+
tools: [{ type: 'file_search' }, { type: 'code_interpreter' }],
|
|
19325
|
+
}));
|
|
19326
|
+
}
|
|
19327
|
+
threadMessages.push(currentUserMessage);
|
|
19257
19328
|
// Check if tools are being used - if so, use non-streaming mode
|
|
19258
19329
|
const hasTools = modelRequirements.tools !== undefined && modelRequirements.tools.length > 0;
|
|
19259
19330
|
const start = $getCurrentDate();
|