mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-20 18:30:15 +01:00
cleanup: code formatting and improve readability across multiple components
This commit is contained in:
parent
4808c5be48
commit
a06e999dd6
144 changed files with 608 additions and 648 deletions
|
|
@ -244,9 +244,9 @@ class ChatGPTClient extends BaseClient {
|
||||||
|
|
||||||
baseURL = this.langchainProxy
|
baseURL = this.langchainProxy
|
||||||
? constructAzureURL({
|
? constructAzureURL({
|
||||||
baseURL: this.langchainProxy,
|
baseURL: this.langchainProxy,
|
||||||
azureOptions: this.azure,
|
azureOptions: this.azure,
|
||||||
})
|
})
|
||||||
: this.azureEndpoint.split(/(?<!\/)\/(chat|completion)\//)[0];
|
: this.azureEndpoint.split(/(?<!\/)\/(chat|completion)\//)[0];
|
||||||
|
|
||||||
if (this.options.forcePrompt) {
|
if (this.options.forcePrompt) {
|
||||||
|
|
@ -339,7 +339,6 @@ class ChatGPTClient extends BaseClient {
|
||||||
opts.body = JSON.stringify(modelOptions);
|
opts.body = JSON.stringify(modelOptions);
|
||||||
|
|
||||||
if (modelOptions.stream) {
|
if (modelOptions.stream) {
|
||||||
|
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
let done = false;
|
let done = false;
|
||||||
|
|
|
||||||
|
|
@ -236,11 +236,11 @@ class GoogleClient extends BaseClient {
|
||||||
msg.content = (
|
msg.content = (
|
||||||
!Array.isArray(msg.content)
|
!Array.isArray(msg.content)
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
type: ContentTypes.TEXT,
|
type: ContentTypes.TEXT,
|
||||||
[ContentTypes.TEXT]: msg.content,
|
[ContentTypes.TEXT]: msg.content,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: msg.content
|
: msg.content
|
||||||
).concat(message.image_urls);
|
).concat(message.image_urls);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class OllamaClient {
|
||||||
return models;
|
return models;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const logMessage =
|
const logMessage =
|
||||||
'Failed to fetch models from Ollama API. If you are not using Ollama directly, and instead, through some aggregator or reverse proxy that handles fetching via OpenAI spec, ensure the name of the endpoint doesn\'t start with `ollama` (case-insensitive).';
|
"Failed to fetch models from Ollama API. If you are not using Ollama directly, and instead, through some aggregator or reverse proxy that handles fetching via OpenAI spec, ensure the name of the endpoint doesn't start with `ollama` (case-insensitive).";
|
||||||
logAxiosError({ message: logMessage, error });
|
logAxiosError({ message: logMessage, error });
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,17 @@
|
||||||
'\n' +
|
'\n' +
|
||||||
'Celestia had the power to grant one wish to anyone who dared to find her abode. Ethan, captivated by the tales he had read and yearning for something greater, approached the cottage with trepidation. When he shared his desire to embark on a grand adventure, Celestia smiled warmly and agreed to grant his wish.\n' +
|
'Celestia had the power to grant one wish to anyone who dared to find her abode. Ethan, captivated by the tales he had read and yearning for something greater, approached the cottage with trepidation. When he shared his desire to embark on a grand adventure, Celestia smiled warmly and agreed to grant his wish.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'With a wave of her wand and a sprinkle of stardust, Celestia bestowed upon Ethan a magical necklace. This necklace, adorned with a rare gemstone called the Eye of Imagination, had the power to turn dreams and imagination into reality. From that moment forward, Ethan\'s every thought and idea became manifest.\n' +
|
"With a wave of her wand and a sprinkle of stardust, Celestia bestowed upon Ethan a magical necklace. This necklace, adorned with a rare gemstone called the Eye of Imagination, had the power to turn dreams and imagination into reality. From that moment forward, Ethan's every thought and idea became manifest.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Energized by this newfound power, Ethan continued his journey, encountering mythical creatures, solving riddles, and overcoming treacherous obstacles along the way. With the Eye of Imagination, he brought life to ancient statues, unlocked hidden doors, and even tamed fiery dragons.\n' +
|
'Energized by this newfound power, Ethan continued his journey, encountering mythical creatures, solving riddles, and overcoming treacherous obstacles along the way. With the Eye of Imagination, he brought life to ancient statues, unlocked hidden doors, and even tamed fiery dragons.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'As days turned into weeks and weeks into months, Ethan became wiser and more in tune with the world around him. He learned that true adventure was not merely about seeking thrills and conquering the unknown, but also about fostering compassion, friendship, and a deep appreciation for the beauty of the ordinary.\n' +
|
'As days turned into weeks and weeks into months, Ethan became wiser and more in tune with the world around him. He learned that true adventure was not merely about seeking thrills and conquering the unknown, but also about fostering compassion, friendship, and a deep appreciation for the beauty of the ordinary.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Eventually, Ethan\'s journey led him back to his village. With the Eye of Imagination, he transformed the village into a place of wonders and endless possibilities. Fields blossomed into vibrant gardens, simple tools turned into intricate works of art, and the villagers felt a renewed sense of hope and inspiration.\n' +
|
"Eventually, Ethan's journey led him back to his village. With the Eye of Imagination, he transformed the village into a place of wonders and endless possibilities. Fields blossomed into vibrant gardens, simple tools turned into intricate works of art, and the villagers felt a renewed sense of hope and inspiration.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Ethan, now known as the Village Magician, realized that the true magic lied within everyone\'s hearts. He taught the villagers to embrace their creativity, to dream big, and to never underestimate the power of imagination. And so, the village flourished, becoming a beacon of wonder and creativity for all to see.\n' +
|
"Ethan, now known as the Village Magician, realized that the true magic lied within everyone's hearts. He taught the villagers to embrace their creativity, to dream big, and to never underestimate the power of imagination. And so, the village flourished, becoming a beacon of wonder and creativity for all to see.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'In the years that followed, Ethan\'s adventures continued, though mostly within the confines of his beloved village. But he never forgot the thrill of that first grand adventure. And every now and then, when looking up at the starry night sky, he would allow his mind to wander, knowing that the greatest adventures were still waiting to be discovered.',
|
"In the years that followed, Ethan's adventures continued, though mostly within the confines of his beloved village. But he never forgot the thrill of that first grand adventure. And every now and then, when looking up at the starry night sky, he would allow his mind to wander, knowing that the greatest adventures were still waiting to be discovered.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
|
|
@ -41,30 +41,30 @@
|
||||||
'\n' +
|
'\n' +
|
||||||
'Once there was a young lad by the name of Ethan, raised in a little hamlet nestled betwixt the verdant knolls, who possessed an irrepressible yearning for knowledge, a thirst unquenchable and a spirit teeming with curiosity. As the golden sun bathed the bucolic land in its effulgent light, he would tread through the village, his ears attuned to the tales spun by the townsfolk, his eyes absorbing the tapestry woven by the world surrounding him.\n' +
|
'Once there was a young lad by the name of Ethan, raised in a little hamlet nestled betwixt the verdant knolls, who possessed an irrepressible yearning for knowledge, a thirst unquenchable and a spirit teeming with curiosity. As the golden sun bathed the bucolic land in its effulgent light, he would tread through the village, his ears attuned to the tales spun by the townsfolk, his eyes absorbing the tapestry woven by the world surrounding him.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'One radiant day, whilst exploring the periphery of the settlement, Ethan chanced upon a timeworn tome, ensconced amidst the roots of an ancient oak, cloaked in the shroud of neglect. The dust gathered upon it spoke of time\'s relentless march. A book of fairy tales – garnished with vivid descriptions of mystical woods, fantastical beasts, and ventures daring beyond the ordinary humdrum existence. Intrigued and beguiled, Ethan pried open the weathered pages and succumbed to their beckoning whispers.\n' +
|
"One radiant day, whilst exploring the periphery of the settlement, Ethan chanced upon a timeworn tome, ensconced amidst the roots of an ancient oak, cloaked in the shroud of neglect. The dust gathered upon it spoke of time's relentless march. A book of fairy tales – garnished with vivid descriptions of mystical woods, fantastical beasts, and ventures daring beyond the ordinary humdrum existence. Intrigued and beguiled, Ethan pried open the weathered pages and succumbed to their beckoning whispers.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'In each tale, he was transported to a realm of enchantment and wonderment, inexorably tugging at the strings of his yearning for peripatetic exploration. Inspired by the narratives he had devoured, Ethan resolved to bid adieu to kinfolk and embark upon a sojourn, with dreams of procuring a firsthand glimpse into the domain of mystique that lay beyond the village\'s circumscribed boundary.\n' +
|
"In each tale, he was transported to a realm of enchantment and wonderment, inexorably tugging at the strings of his yearning for peripatetic exploration. Inspired by the narratives he had devoured, Ethan resolved to bid adieu to kinfolk and embark upon a sojourn, with dreams of procuring a firsthand glimpse into the domain of mystique that lay beyond the village's circumscribed boundary.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Thus, he bade tearful farewells, girding himself for a path that guided him to a dense and captivating woodland, whispered of as a sanctuary to mythical beings and clandestine troves of treasures. As Ethan plunged deeper into the heart of the arboreal labyrinth, he felt a palpable surge of electricity, as though the sylvan sentinels whispered enigmatic secrets that only the perceptive ear could discern.\n' +
|
'Thus, he bade tearful farewells, girding himself for a path that guided him to a dense and captivating woodland, whispered of as a sanctuary to mythical beings and clandestine troves of treasures. As Ethan plunged deeper into the heart of the arboreal labyrinth, he felt a palpable surge of electricity, as though the sylvan sentinels whispered enigmatic secrets that only the perceptive ear could discern.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'It wasn\'t long before his path intertwined with that of a capricious sprite christened Sparkle, bearing an impish grin and eyes sparkling with mischief. Sparkle played the role of Virgil to Ethan\'s Dante, guiding him through the intricate tapestry of arboreal scions, issuing warnings of perils concealed and spinning tales of ancient entities that called this very bosky enclave home.\n' +
|
"It wasn't long before his path intertwined with that of a capricious sprite christened Sparkle, bearing an impish grin and eyes sparkling with mischief. Sparkle played the role of Virgil to Ethan's Dante, guiding him through the intricate tapestry of arboreal scions, issuing warnings of perils concealed and spinning tales of ancient entities that called this very bosky enclave home.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Together, they stumbled upon a luminous lake, its shimmering waters imbued with a celestial light. At the center lay a diminutive island, upon which reposed a cottage fashioned from tender petals and verdant leaves. It belonged to an ancient sorceress of considerable wisdom, Celestia by name.\n' +
|
'Together, they stumbled upon a luminous lake, its shimmering waters imbued with a celestial light. At the center lay a diminutive island, upon which reposed a cottage fashioned from tender petals and verdant leaves. It belonged to an ancient sorceress of considerable wisdom, Celestia by name.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Celestia, with her power to bestow a single wish on any intrepid soul who happened upon her abode, met Ethan\'s desire with a congenial nod, his fervor for a grand expedition not lost on her penetrating gaze. In response, she bequeathed unto him a necklace of magical manufacture – adorned with the rare gemstone known as the Eye of Imagination – whose very essence transformed dreams into vivid reality. From that moment forward, not a single cogitation nor nebulous fanciful notion of Ethan\'s ever lacked physicality.\n' +
|
"Celestia, with her power to bestow a single wish on any intrepid soul who happened upon her abode, met Ethan's desire with a congenial nod, his fervor for a grand expedition not lost on her penetrating gaze. In response, she bequeathed unto him a necklace of magical manufacture – adorned with the rare gemstone known as the Eye of Imagination – whose very essence transformed dreams into vivid reality. From that moment forward, not a single cogitation nor nebulous fanciful notion of Ethan's ever lacked physicality.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Energized by this newfound potency, Ethan continued his sojourn, encountering mythical creatures, unraveling cerebral enigmas, and braving perils aplenty along the winding roads of destiny. Armed with the Eye of Imagination, he brought forth life from immobile statuary, unlocked forbidding portals, and even tamed the ferocious beasts of yore – their fiery breath reduced to a whisper.\n' +
|
'Energized by this newfound potency, Ethan continued his sojourn, encountering mythical creatures, unraveling cerebral enigmas, and braving perils aplenty along the winding roads of destiny. Armed with the Eye of Imagination, he brought forth life from immobile statuary, unlocked forbidding portals, and even tamed the ferocious beasts of yore – their fiery breath reduced to a whisper.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'As the weeks metamorphosed into months, Ethan grew wiser and more attuned to the ebb and flow of the world enveloping him. He gleaned that true adventure isn\'t solely confined to sating a thirst for adrenaline and conquering the unknown; indeed, it resides in fostering compassion, fostering amicable bonds, and cherishing the beauty entwined within the quotidian veld.\n' +
|
"As the weeks metamorphosed into months, Ethan grew wiser and more attuned to the ebb and flow of the world enveloping him. He gleaned that true adventure isn't solely confined to sating a thirst for adrenaline and conquering the unknown; indeed, it resides in fostering compassion, fostering amicable bonds, and cherishing the beauty entwined within the quotidian veld.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Eventually, Ethan\'s quest drew him homeward, back to his village. Buoying the Eye of Imagination\'s ethereal power, he imbued the hitherto unremarkable settlement with the patina of infinite possibilities. The bounteous fields bloomed into kaleidoscopic gardens, simple instruments transmuting into intricate masterpieces, and the villagers themselves clasped within their hearts a renewed ardor, a conflagration of hope and inspiration.\n' +
|
"Eventually, Ethan's quest drew him homeward, back to his village. Buoying the Eye of Imagination's ethereal power, he imbued the hitherto unremarkable settlement with the patina of infinite possibilities. The bounteous fields bloomed into kaleidoscopic gardens, simple instruments transmuting into intricate masterpieces, and the villagers themselves clasped within their hearts a renewed ardor, a conflagration of hope and inspiration.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Behold Ethan, at present hailed as the Village Magician – a cognomen befitting his sorcery wielded within the confines of the community he adored. His exploits may have become tethered to a geographical locale, but the flame kindled by that premier sojourn never flickered. Occasionally, beneath the veiled twilight canopy, when peering skyward toward the astral canvas bedecked with countless luminescent diamonds, he\'d allow his mind to wander, cognizant of boundless adventures yet to take flight, forever awaiting his indomitable spirit.',
|
"Behold Ethan, at present hailed as the Village Magician – a cognomen befitting his sorcery wielded within the confines of the community he adored. His exploits may have become tethered to a geographical locale, but the flame kindled by that premier sojourn never flickered. Occasionally, beneath the veiled twilight canopy, when peering skyward toward the astral canvas bedecked with countless luminescent diamonds, he'd allow his mind to wander, cognizant of boundless adventures yet to take flight, forever awaiting his indomitable spirit.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content:
|
content:
|
||||||
'Beautifully rewritten! It captures the essence of Cormac McCarthy\'s style, with its descriptive language and evocative imagery. The story retains the spirit of adventure and the power of imagination seen in the original. Well done! If you have any more requests or if there\'s anything else I can assist you with, feel free to let me know.',
|
"Beautifully rewritten! It captures the essence of Cormac McCarthy's style, with its descriptive language and evocative imagery. The story retains the spirit of adventure and the power of imagination seen in the original. Well done! If you have any more requests or if there's anything else I can assist you with, feel free to let me know.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
|
|
@ -73,19 +73,19 @@
|
||||||
{
|
{
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content:
|
content:
|
||||||
'Certainly! Here\'s a short story reflecting Cormac McCarthy\'s style:\n' +
|
"Certainly! Here's a short story reflecting Cormac McCarthy's style:\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'In a desolate wasteland scarred by the sins of mankind, a lone traveler ventured forth, his name forgotten by time, etched upon the shadows of memory. He navigated the barren plains, where the sun beat down, merciless and unrelenting, scorching the parched earth beneath his weary boots.\n' +
|
'In a desolate wasteland scarred by the sins of mankind, a lone traveler ventured forth, his name forgotten by time, etched upon the shadows of memory. He navigated the barren plains, where the sun beat down, merciless and unrelenting, scorching the parched earth beneath his weary boots.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Desolation was his only companion, the forsaken landscape a testament to the darkness that had befallen this forsaken realm. The wind whispered secrets long lost, carrying with it the echoes of a civilization long since undone, swallowed by the abyss.\n' +
|
'Desolation was his only companion, the forsaken landscape a testament to the darkness that had befallen this forsaken realm. The wind whispered secrets long lost, carrying with it the echoes of a civilization long since undone, swallowed by the abyss.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Amongst the shattered remnants of fallen cities, he sought solace, a glimmer of hope amidst the desolation. Rusted remnants of steel and concrete stood as sentinels of mankind\'s hubris, their jagged edges a chilling reminder of the fragility of all that was once deemed invincible.\n' +
|
"Amongst the shattered remnants of fallen cities, he sought solace, a glimmer of hope amidst the desolation. Rusted remnants of steel and concrete stood as sentinels of mankind's hubris, their jagged edges a chilling reminder of the fragility of all that was once deemed invincible.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'As twilight descended, casting a pallid hue upon the lifeless land, he happened upon a dilapidated house, its walls crumbling under the weight of time. Drawn to the desolation, he pushed open the creaking door, its rusty hinges screaming in protest.\n' +
|
'As twilight descended, casting a pallid hue upon the lifeless land, he happened upon a dilapidated house, its walls crumbling under the weight of time. Drawn to the desolation, he pushed open the creaking door, its rusty hinges screaming in protest.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Inside, a world frozen in time awaited him. Dust particles danced through the air, illuminated by slivers of light that pierced the broken windows. Here, the past lay trapped, a melancholic tableau of lives lost and dreams shattered.\n' +
|
'Inside, a world frozen in time awaited him. Dust particles danced through the air, illuminated by slivers of light that pierced the broken windows. Here, the past lay trapped, a melancholic tableau of lives lost and dreams shattered.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'He wandered through the empty rooms, bare walls whispering stories untold. In the corner, a dilapidated piano stood, its ivory keys long since abandoned by a musician\'s touch. He approached it cautiously, a faint glimmer of anticipation igniting in his weather-worn eyes.\n' +
|
"He wandered through the empty rooms, bare walls whispering stories untold. In the corner, a dilapidated piano stood, its ivory keys long since abandoned by a musician's touch. He approached it cautiously, a faint glimmer of anticipation igniting in his weather-worn eyes.\n" +
|
||||||
'\n' +
|
'\n' +
|
||||||
'Determined, he carefully brushed away the dust and debris that cloaked the instrument. With trembling hands, he pressed a key, and a discordant note filled the air, mingling with the sighs of forgotten melodies. The sound echoed through the silence, bringing with it the remnants of forgotten symphonies.\n' +
|
'Determined, he carefully brushed away the dust and debris that cloaked the instrument. With trembling hands, he pressed a key, and a discordant note filled the air, mingling with the sighs of forgotten melodies. The sound echoed through the silence, bringing with it the remnants of forgotten symphonies.\n' +
|
||||||
'\n' +
|
'\n' +
|
||||||
|
|
@ -103,13 +103,13 @@
|
||||||
{
|
{
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content:
|
content:
|
||||||
'Thank you! I\'m glad you enjoyed it. If you have any more writing requests or if there\'s anything else I can assist you with, feel free to let me know.',
|
"Thank you! I'm glad you enjoyed it. If you have any more writing requests or if there's anything else I can assist you with, feel free to let me know.",
|
||||||
},
|
},
|
||||||
{ role: 'user', content: 'you are very helpful' },
|
{ role: 'user', content: 'you are very helpful' },
|
||||||
{
|
{
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content:
|
content:
|
||||||
'Thank you for your kind words! I\'m here to assist you in any way I can. If you have any more questions, need further assistance, or just want to chat, feel free to reach out.',
|
"Thank you for your kind words! I'm here to assist you in any way I can. If you have any more questions, need further assistance, or just want to chat, feel free to reach out.",
|
||||||
},
|
},
|
||||||
{ role: 'user', content: 'no you man' },
|
{ role: 'user', content: 'no you man' },
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ const chatPromptMemory = new ConversationSummaryBufferMemory({
|
||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await chatPromptMemory.saveContext({ input: 'hi my name\'s Danny' }, { output: 'whats up' });
|
await chatPromptMemory.saveContext({ input: "hi my name's Danny" }, { output: 'whats up' });
|
||||||
await chatPromptMemory.saveContext({ input: 'not much you' }, { output: 'not much' });
|
await chatPromptMemory.saveContext({ input: 'not much you' }, { output: 'not much' });
|
||||||
await chatPromptMemory.saveContext(
|
await chatPromptMemory.saveContext(
|
||||||
{ input: 'are you excited for the olympics?' },
|
{ input: 'are you excited for the olympics?' },
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ describe('addImages', () => {
|
||||||
|
|
||||||
it('should append correctly from a real scenario', () => {
|
it('should append correctly from a real scenario', () => {
|
||||||
responseMessage.text =
|
responseMessage.text =
|
||||||
'Here is the generated image based on your request. It depicts a surreal landscape filled with floating musical notes. The style is impressionistic, with vibrant sunset hues dominating the scene. At the center, there\'s a silhouette of a grand piano, adding a dreamy emotion to the overall image. This could serve as a unique and creative music album cover. Would you like to make any changes or generate another image?';
|
"Here is the generated image based on your request. It depicts a surreal landscape filled with floating musical notes. The style is impressionistic, with vibrant sunset hues dominating the scene. At the center, there's a silhouette of a grand piano, adding a dreamy emotion to the overall image. This could serve as a unique and creative music album cover. Would you like to make any changes or generate another image?";
|
||||||
const originalText = responseMessage.text;
|
const originalText = responseMessage.text;
|
||||||
const imageMarkdown = '';
|
const imageMarkdown = '';
|
||||||
intermediateSteps.push({ observation: imageMarkdown });
|
intermediateSteps.push({ observation: imageMarkdown });
|
||||||
|
|
|
||||||
|
|
@ -65,14 +65,14 @@ function buildPromptPrefix({ result, message, functionsAgent }) {
|
||||||
const preliminaryAnswer =
|
const preliminaryAnswer =
|
||||||
result.output?.length > 0 ? `Preliminary Answer: "${result.output.trim()}"` : '';
|
result.output?.length > 0 ? `Preliminary Answer: "${result.output.trim()}"` : '';
|
||||||
const prefix = preliminaryAnswer
|
const prefix = preliminaryAnswer
|
||||||
? 'review and improve the answer you generated using plugins in response to the User Message below. The user hasn\'t seen your answer or thoughts yet.'
|
? "review and improve the answer you generated using plugins in response to the User Message below. The user hasn't seen your answer or thoughts yet."
|
||||||
: 'respond to the User Message below based on your preliminary thoughts & actions.';
|
: 'respond to the User Message below based on your preliminary thoughts & actions.';
|
||||||
|
|
||||||
return `As a helpful AI Assistant, ${prefix}${errorMessage}\n${internalActions}
|
return `As a helpful AI Assistant, ${prefix}${errorMessage}\n${internalActions}
|
||||||
${preliminaryAnswer}
|
${preliminaryAnswer}
|
||||||
Reply conversationally to the User based on your ${
|
Reply conversationally to the User based on your ${
|
||||||
preliminaryAnswer ? 'preliminary answer, ' : ''
|
preliminaryAnswer ? 'preliminary answer, ' : ''
|
||||||
}internal actions, thoughts, and observations, making improvements wherever possible, but do not modify URLs.
|
}internal actions, thoughts, and observations, making improvements wherever possible, but do not modify URLs.
|
||||||
${
|
${
|
||||||
preliminaryAnswer
|
preliminaryAnswer
|
||||||
? ''
|
? ''
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ describe('addCacheControl', () => {
|
||||||
{ role: 'user', content: [{ type: 'text', text: 'Hello' }] },
|
{ role: 'user', content: [{ type: 'text', text: 'Hello' }] },
|
||||||
{ role: 'assistant', content: [{ type: 'text', text: 'Hi there' }] },
|
{ role: 'assistant', content: [{ type: 'text', text: 'Hi there' }] },
|
||||||
{ role: 'user', content: [{ type: 'text', text: 'How are you?' }] },
|
{ role: 'user', content: [{ type: 'text', text: 'How are you?' }] },
|
||||||
{ role: 'assistant', content: [{ type: 'text', text: 'I\'m doing well, thanks!' }] },
|
{ role: 'assistant', content: [{ type: 'text', text: "I'm doing well, thanks!" }] },
|
||||||
{ role: 'user', content: [{ type: 'text', text: 'Great!' }] },
|
{ role: 'user', content: [{ type: 'text', text: 'Great!' }] },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ describe('addCacheControl', () => {
|
||||||
{ role: 'user', content: 'Hello' },
|
{ role: 'user', content: 'Hello' },
|
||||||
{ role: 'assistant', content: 'Hi there' },
|
{ role: 'assistant', content: 'Hi there' },
|
||||||
{ role: 'user', content: 'How are you?' },
|
{ role: 'user', content: 'How are you?' },
|
||||||
{ role: 'assistant', content: 'I\'m doing well, thanks!' },
|
{ role: 'assistant', content: "I'm doing well, thanks!" },
|
||||||
{ role: 'user', content: 'Great!' },
|
{ role: 'user', content: 'Great!' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -140,7 +140,7 @@ describe('addCacheControl', () => {
|
||||||
{ role: 'user', content: 'Hello' },
|
{ role: 'user', content: 'Hello' },
|
||||||
{ role: 'assistant', content: 'Hi there' },
|
{ role: 'assistant', content: 'Hi there' },
|
||||||
{ role: 'user', content: [{ type: 'text', text: 'How are you?' }] },
|
{ role: 'user', content: [{ type: 'text', text: 'How are you?' }] },
|
||||||
{ role: 'assistant', content: 'I\'m doing well, thanks!' },
|
{ role: 'assistant', content: "I'm doing well, thanks!" },
|
||||||
{ role: 'user', content: 'Great!' },
|
{ role: 'user', content: 'Great!' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -160,7 +160,7 @@ describe('addCacheControl', () => {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expect(result[1].content).toBe('Hi there');
|
expect(result[1].content).toBe('Hi there');
|
||||||
expect(result[3].content).toBe('I\'m doing well, thanks!');
|
expect(result[3].content).toBe("I'm doing well, thanks!");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle edge case with multiple content types', () => {
|
test('should handle edge case with multiple content types', () => {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ const { EModelEndpoint, ArtifactModes } = require('librechat-data-provider');
|
||||||
const { generateShadcnPrompt } = require('~/app/clients/prompts/shadcn-docs/generate');
|
const { generateShadcnPrompt } = require('~/app/clients/prompts/shadcn-docs/generate');
|
||||||
const { components } = require('~/app/clients/prompts/shadcn-docs/components');
|
const { components } = require('~/app/clients/prompts/shadcn-docs/components');
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
const artifactsPromptV1 = dedent`The assistant can create and reference artifacts during conversations.
|
const artifactsPromptV1 = dedent`The assistant can create and reference artifacts during conversations.
|
||||||
|
|
||||||
Artifacts are for substantial, self-contained content that users might modify or reuse, displayed in a separate UI window for clarity.
|
Artifacts are for substantial, self-contained content that users might modify or reuse, displayed in a separate UI window for clarity.
|
||||||
|
|
|
||||||
|
|
@ -96,35 +96,35 @@ function createContextHandlers(req, userMessageContent) {
|
||||||
resolvedQueries.length === 0
|
resolvedQueries.length === 0
|
||||||
? '\n\tThe semantic search did not return any results.'
|
? '\n\tThe semantic search did not return any results.'
|
||||||
: resolvedQueries
|
: resolvedQueries
|
||||||
.map((queryResult, index) => {
|
.map((queryResult, index) => {
|
||||||
const file = processedFiles[index];
|
const file = processedFiles[index];
|
||||||
let contextItems = queryResult.data;
|
let contextItems = queryResult.data;
|
||||||
|
|
||||||
const generateContext = (currentContext) =>
|
const generateContext = (currentContext) =>
|
||||||
`
|
`
|
||||||
<file>
|
<file>
|
||||||
<filename>${file.filename}</filename>
|
<filename>${file.filename}</filename>
|
||||||
<context>${currentContext}
|
<context>${currentContext}
|
||||||
</context>
|
</context>
|
||||||
</file>`;
|
</file>`;
|
||||||
|
|
||||||
if (useFullContext) {
|
if (useFullContext) {
|
||||||
return generateContext(`\n${contextItems}`);
|
return generateContext(`\n${contextItems}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
contextItems = queryResult.data
|
contextItems = queryResult.data
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
const pageContent = item[0].page_content;
|
const pageContent = item[0].page_content;
|
||||||
return `
|
return `
|
||||||
<contextItem>
|
<contextItem>
|
||||||
<![CDATA[${pageContent?.trim()}]]>
|
<![CDATA[${pageContent?.trim()}]]>
|
||||||
</contextItem>`;
|
</contextItem>`;
|
||||||
})
|
})
|
||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
return generateContext(contextItems);
|
return generateContext(contextItems);
|
||||||
})
|
})
|
||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
if (useFullContext) {
|
if (useFullContext) {
|
||||||
const prompt = `${header}
|
const prompt = `${header}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ describe('formatAgentMessages', () => {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: ContentTypes.TEXT,
|
type: ContentTypes.TEXT,
|
||||||
[ContentTypes.TEXT]: 'I\'ll search for that information.',
|
[ContentTypes.TEXT]: "I'll search for that information.",
|
||||||
tool_call_ids: ['search_1'],
|
tool_call_ids: ['search_1'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -144,7 +144,7 @@ describe('formatAgentMessages', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: ContentTypes.TEXT,
|
type: ContentTypes.TEXT,
|
||||||
[ContentTypes.TEXT]: 'Now, I\'ll convert the temperature.',
|
[ContentTypes.TEXT]: "Now, I'll convert the temperature.",
|
||||||
tool_call_ids: ['convert_1'],
|
tool_call_ids: ['convert_1'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -156,7 +156,7 @@ describe('formatAgentMessages', () => {
|
||||||
output: '23.89°C',
|
output: '23.89°C',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: 'Here\'s your answer.' },
|
{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: "Here's your answer." },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -171,7 +171,7 @@ describe('formatAgentMessages', () => {
|
||||||
expect(result[4]).toBeInstanceOf(AIMessage);
|
expect(result[4]).toBeInstanceOf(AIMessage);
|
||||||
|
|
||||||
// Check first AIMessage
|
// Check first AIMessage
|
||||||
expect(result[0].content).toBe('I\'ll search for that information.');
|
expect(result[0].content).toBe("I'll search for that information.");
|
||||||
expect(result[0].tool_calls).toHaveLength(1);
|
expect(result[0].tool_calls).toHaveLength(1);
|
||||||
expect(result[0].tool_calls[0]).toEqual({
|
expect(result[0].tool_calls[0]).toEqual({
|
||||||
id: 'search_1',
|
id: 'search_1',
|
||||||
|
|
@ -187,7 +187,7 @@ describe('formatAgentMessages', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check second AIMessage
|
// Check second AIMessage
|
||||||
expect(result[2].content).toBe('Now, I\'ll convert the temperature.');
|
expect(result[2].content).toBe("Now, I'll convert the temperature.");
|
||||||
expect(result[2].tool_calls).toHaveLength(1);
|
expect(result[2].tool_calls).toHaveLength(1);
|
||||||
expect(result[2].tool_calls[0]).toEqual({
|
expect(result[2].tool_calls[0]).toEqual({
|
||||||
id: 'convert_1',
|
id: 'convert_1',
|
||||||
|
|
@ -202,7 +202,7 @@ describe('formatAgentMessages', () => {
|
||||||
|
|
||||||
// Check final AIMessage
|
// Check final AIMessage
|
||||||
expect(result[4].content).toStrictEqual([
|
expect(result[4].content).toStrictEqual([
|
||||||
{ [ContentTypes.TEXT]: 'Here\'s your answer.', type: ContentTypes.TEXT },
|
{ [ContentTypes.TEXT]: "Here's your answer.", type: ContentTypes.TEXT },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -217,7 +217,7 @@ describe('formatAgentMessages', () => {
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: [{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: 'How can I help you?' }],
|
content: [{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: 'How can I help you?' }],
|
||||||
},
|
},
|
||||||
{ role: 'user', content: 'What\'s the weather?' },
|
{ role: 'user', content: "What's the weather?" },
|
||||||
{
|
{
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: [
|
content: [
|
||||||
|
|
@ -240,7 +240,7 @@ describe('formatAgentMessages', () => {
|
||||||
{
|
{
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: [
|
content: [
|
||||||
{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: 'Here\'s the weather information.' },
|
{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: "Here's the weather information." },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -265,12 +265,12 @@ describe('formatAgentMessages', () => {
|
||||||
{ [ContentTypes.TEXT]: 'How can I help you?', type: ContentTypes.TEXT },
|
{ [ContentTypes.TEXT]: 'How can I help you?', type: ContentTypes.TEXT },
|
||||||
]);
|
]);
|
||||||
expect(result[2].content).toStrictEqual([
|
expect(result[2].content).toStrictEqual([
|
||||||
{ [ContentTypes.TEXT]: 'What\'s the weather?', type: ContentTypes.TEXT },
|
{ [ContentTypes.TEXT]: "What's the weather?", type: ContentTypes.TEXT },
|
||||||
]);
|
]);
|
||||||
expect(result[3].content).toBe('Let me check that for you.');
|
expect(result[3].content).toBe('Let me check that for you.');
|
||||||
expect(result[4].content).toBe('Sunny, 75°F');
|
expect(result[4].content).toBe('Sunny, 75°F');
|
||||||
expect(result[5].content).toStrictEqual([
|
expect(result[5].content).toStrictEqual([
|
||||||
{ [ContentTypes.TEXT]: 'Here\'s the weather information.', type: ContentTypes.TEXT },
|
{ [ContentTypes.TEXT]: "Here's the weather information.", type: ContentTypes.TEXT },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Check that there are no consecutive AIMessages
|
// Check that there are no consecutive AIMessages
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
instructions:
|
instructions:
|
||||||
'Remember, all your responses MUST be in the format described. Do not respond unless it\'s in the format described, using the structure of Action, Action Input, etc.',
|
"Remember, all your responses MUST be in the format described. Do not respond unless it's in the format described, using the structure of Action, Action Input, etc.",
|
||||||
errorInstructions:
|
errorInstructions:
|
||||||
'\nYou encountered an error in attempting a response. The user is not aware of the error so you shouldn\'t mention it.\nReview the actions taken carefully in case there is a partial or complete answer within them.\nError Message:',
|
"\nYou encountered an error in attempting a response. The user is not aware of the error so you shouldn't mention it.\nReview the actions taken carefully in case there is a partial or complete answer within them.\nError Message:",
|
||||||
imageInstructions:
|
imageInstructions:
|
||||||
'You must include the exact image paths from above, formatted in Markdown syntax: ',
|
'You must include the exact image paths from above, formatted in Markdown syntax: ',
|
||||||
completionInstructions:
|
completionInstructions:
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,17 @@ function generateShadcnPrompt(options) {
|
||||||
Here are the components that are available, along with how to import them, and how to use them:
|
Here are the components that are available, along with how to import them, and how to use them:
|
||||||
|
|
||||||
${Object.values(components)
|
${Object.values(components)
|
||||||
.map((component) => {
|
.map((component) => {
|
||||||
if (useXML) {
|
if (useXML) {
|
||||||
return dedent`
|
return dedent`
|
||||||
<component>
|
<component>
|
||||||
<name>${component.componentName}</name>
|
<name>${component.componentName}</name>
|
||||||
<import-instructions>${component.importDocs}</import-instructions>
|
<import-instructions>${component.importDocs}</import-instructions>
|
||||||
<usage-instructions>${component.usageDocs}</usage-instructions>
|
<usage-instructions>${component.usageDocs}</usage-instructions>
|
||||||
</component>
|
</component>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
return dedent`
|
return dedent`
|
||||||
# ${component.componentName}
|
# ${component.componentName}
|
||||||
|
|
||||||
## Import Instructions
|
## Import Instructions
|
||||||
|
|
@ -37,9 +37,9 @@ function generateShadcnPrompt(options) {
|
||||||
## Usage Instructions
|
## Usage Instructions
|
||||||
${component.usageDocs}
|
${component.usageDocs}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join('\n\n')}
|
.join('\n\n')}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return systemPrompt;
|
return systemPrompt;
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ const messageHistory = [
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
isCreatedByUser: true,
|
isCreatedByUser: true,
|
||||||
text: 'What\'s up',
|
text: "What's up",
|
||||||
messageId: '3',
|
messageId: '3',
|
||||||
parentMessageId: '2',
|
parentMessageId: '2',
|
||||||
},
|
},
|
||||||
|
|
@ -456,7 +456,7 @@ describe('BaseClient', () => {
|
||||||
|
|
||||||
const chatMessages2 = await TestClient.loadHistory(conversationId, '3');
|
const chatMessages2 = await TestClient.loadHistory(conversationId, '3');
|
||||||
expect(TestClient.currentMessages).toHaveLength(3);
|
expect(TestClient.currentMessages).toHaveLength(3);
|
||||||
expect(chatMessages2[chatMessages2.length - 1].text).toEqual('What\'s up');
|
expect(chatMessages2[chatMessages2.length - 1].text).toEqual("What's up");
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Most of the new sendMessage logic revolving around edited/continued AI messages
|
/* Most of the new sendMessage logic revolving around edited/continued AI messages
|
||||||
|
|
|
||||||
|
|
@ -462,17 +462,17 @@ describe('OpenAIClient', () => {
|
||||||
role: 'system',
|
role: 'system',
|
||||||
name: 'example_user',
|
name: 'example_user',
|
||||||
content:
|
content:
|
||||||
'Let\'s circle back when we have more bandwidth to touch base on opportunities for increased leverage.',
|
"Let's circle back when we have more bandwidth to touch base on opportunities for increased leverage.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'system',
|
role: 'system',
|
||||||
name: 'example_assistant',
|
name: 'example_assistant',
|
||||||
content: 'Let\'s talk later when we\'re less busy about how to do better.',
|
content: "Let's talk later when we're less busy about how to do better.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content:
|
content:
|
||||||
'This late pivot means we don\'t have time to boil the ocean for the client deliverable.',
|
"This late pivot means we don't have time to boil the ocean for the client deliverable.",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class AzureAISearch extends Tool {
|
||||||
super();
|
super();
|
||||||
this.name = 'azure-ai-search';
|
this.name = 'azure-ai-search';
|
||||||
this.description =
|
this.description =
|
||||||
'Use the \'azure-ai-search\' tool to retrieve search results relevant to your input';
|
"Use the 'azure-ai-search' tool to retrieve search results relevant to your input";
|
||||||
/* Used to initialize the Tool without necessary variables. */
|
/* Used to initialize the Tool without necessary variables. */
|
||||||
this.override = fields.override ?? false;
|
this.override = fields.override ?? false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const extractBaseURL = require('~/utils/extractBaseURL');
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
|
|
||||||
const displayMessage =
|
const displayMessage =
|
||||||
'DALL-E displayed an image. All generated images are already plainly visible, so don\'t repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.';
|
"DALL-E displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
|
||||||
class DALLE3 extends Tool {
|
class DALLE3 extends Tool {
|
||||||
constructor(fields = {}) {
|
constructor(fields = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const { FileContext, ContentTypes } = require('librechat-data-provider');
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
|
|
||||||
const displayMessage =
|
const displayMessage =
|
||||||
'Flux displayed an image. All generated images are already plainly visible, so don\'t repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.';
|
"Flux displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FluxAPI - A tool for generating high-quality images from text prompts using the Flux API.
|
* FluxAPI - A tool for generating high-quality images from text prompts using the Flux API.
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ const DEFAULT_IMAGE_EDIT_PROMPT_DESCRIPTION = `Describe the changes, enhancement
|
||||||
Always base this prompt on the most recently uploaded reference images.`;
|
Always base this prompt on the most recently uploaded reference images.`;
|
||||||
|
|
||||||
const displayMessage =
|
const displayMessage =
|
||||||
'The tool displayed an image. All generated images are already plainly visible, so don\'t repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.';
|
"The tool displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces unwanted characters from the input string
|
* Replaces unwanted characters from the input string
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ class OpenWeather extends Tool {
|
||||||
|
|
||||||
if (['current_forecast', 'timestamp', 'daily_aggregation', 'overview'].includes(action)) {
|
if (['current_forecast', 'timestamp', 'daily_aggregation', 'overview'].includes(action)) {
|
||||||
if (typeof finalLat !== 'number' || typeof finalLon !== 'number') {
|
if (typeof finalLat !== 'number' || typeof finalLon !== 'number') {
|
||||||
return 'Error: lat and lon are required and must be numbers for this action (or specify \'city\').';
|
return "Error: lat and lon are required and must be numbers for this action (or specify 'city').";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,7 +243,7 @@ class OpenWeather extends Tool {
|
||||||
let dt;
|
let dt;
|
||||||
if (action === 'timestamp') {
|
if (action === 'timestamp') {
|
||||||
if (!date) {
|
if (!date) {
|
||||||
return 'Error: For timestamp action, a \'date\' in YYYY-MM-DD format is required.';
|
return "Error: For timestamp action, a 'date' in YYYY-MM-DD format is required.";
|
||||||
}
|
}
|
||||||
dt = this.convertDateToUnix(date);
|
dt = this.convertDateToUnix(date);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const paths = require('~/config/paths');
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
|
|
||||||
const displayMessage =
|
const displayMessage =
|
||||||
'Stable Diffusion displayed an image. All generated images are already plainly visible, so don\'t repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.';
|
"Stable Diffusion displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
|
||||||
|
|
||||||
class StableDiffusionAPI extends Tool {
|
class StableDiffusionAPI extends Tool {
|
||||||
constructor(fields) {
|
constructor(fields) {
|
||||||
|
|
@ -44,7 +44,7 @@ class StableDiffusionAPI extends Tool {
|
||||||
// "negative_prompt":"semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, out of frame, low quality, ugly, mutation, deformed"
|
// "negative_prompt":"semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, out of frame, low quality, ugly, mutation, deformed"
|
||||||
// - Generate images only once per human query unless explicitly requested by the user`;
|
// - Generate images only once per human query unless explicitly requested by the user`;
|
||||||
this.description =
|
this.description =
|
||||||
'You can generate images using text with \'stable-diffusion\'. This tool is exclusively for visual content.';
|
"You can generate images using text with 'stable-diffusion'. This tool is exclusively for visual content.";
|
||||||
this.schema = z.object({
|
this.schema = z.object({
|
||||||
prompt: z
|
prompt: z
|
||||||
.string()
|
.string()
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class TraversaalSearch extends Tool {
|
||||||
query: z
|
query: z
|
||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe(
|
||||||
'A properly written sentence to be interpreted by an AI to search the web according to the user\'s request.',
|
"A properly written sentence to be interpreted by an AI to search the web according to the user's request.",
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -38,7 +38,6 @@ class TraversaalSearch extends Tool {
|
||||||
return apiKey;
|
return apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
async _call({ query }, _runManager) {
|
async _call({ query }, _runManager) {
|
||||||
const body = {
|
const body = {
|
||||||
query: [query],
|
query: [query],
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ function parseTranscript(transcriptResponse) {
|
||||||
.map((entry) => entry.text.trim())
|
.map((entry) => entry.text.trim())
|
||||||
.filter((text) => text)
|
.filter((text) => text)
|
||||||
.join(' ')
|
.join(' ')
|
||||||
.replaceAll('&#39;', '\'');
|
.replaceAll('&#39;', "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
function createYouTubeTools(fields = {}) {
|
function createYouTubeTools(fields = {}) {
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ const createFileSearchTool = async ({ req, files, entity_id }) => {
|
||||||
query: z
|
query: z
|
||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe(
|
||||||
'A natural language query to search for relevant information in the files. Be specific and use keywords related to the information you\'re looking for. The query will be used for semantic similarity matching against the file contents.',
|
"A natural language query to search for relevant information in the files. Be specific and use keywords related to the information you're looking for. The query will be used for semantic similarity matching against the file contents.",
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,6 @@ describe('Tool Handlers', () => {
|
||||||
try {
|
try {
|
||||||
await loadTool2();
|
await loadTool2();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line jest/no-conditional-expect
|
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -140,13 +140,13 @@ const adjustPositions = async (user, oldPosition, newPosition) => {
|
||||||
const position =
|
const position =
|
||||||
oldPosition < newPosition
|
oldPosition < newPosition
|
||||||
? {
|
? {
|
||||||
$gt: Math.min(oldPosition, newPosition),
|
$gt: Math.min(oldPosition, newPosition),
|
||||||
$lte: Math.max(oldPosition, newPosition),
|
$lte: Math.max(oldPosition, newPosition),
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
$gte: Math.min(oldPosition, newPosition),
|
$gte: Math.min(oldPosition, newPosition),
|
||||||
$lt: Math.max(oldPosition, newPosition),
|
$lt: Math.max(oldPosition, newPosition),
|
||||||
};
|
};
|
||||||
|
|
||||||
await ConversationTag.updateMany(
|
await ConversationTag.updateMany(
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ describe('Message Operations', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Conversation Hijacking Prevention', () => {
|
describe('Conversation Hijacking Prevention', () => {
|
||||||
it('should not allow editing a message in another user\'s conversation', async () => {
|
it("should not allow editing a message in another user's conversation", async () => {
|
||||||
const attackerReq = { user: { id: 'attacker123' } };
|
const attackerReq = { user: { id: 'attacker123' } };
|
||||||
const victimConversationId = 'victim-convo-123';
|
const victimConversationId = 'victim-convo-123';
|
||||||
const victimMessageId = 'victim-msg-123';
|
const victimMessageId = 'victim-msg-123';
|
||||||
|
|
@ -175,7 +175,7 @@ describe('Message Operations', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow deleting messages from another user\'s conversation', async () => {
|
it("should not allow deleting messages from another user's conversation", async () => {
|
||||||
const attackerReq = { user: { id: 'attacker123' } };
|
const attackerReq = { user: { id: 'attacker123' } };
|
||||||
const victimConversationId = 'victim-convo-123';
|
const victimConversationId = 'victim-convo-123';
|
||||||
const victimMessageId = 'victim-msg-123';
|
const victimMessageId = 'victim-msg-123';
|
||||||
|
|
@ -193,7 +193,7 @@ describe('Message Operations', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow inserting a new message into another user\'s conversation', async () => {
|
it("should not allow inserting a new message into another user's conversation", async () => {
|
||||||
const attackerReq = { user: { id: 'attacker123' } };
|
const attackerReq = { user: { id: 'attacker123' } };
|
||||||
const victimConversationId = uuidv4(); // Use a valid UUID
|
const victimConversationId = uuidv4(); // Use a valid UUID
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ const handleValidationError = (err, res) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
module.exports = (err, req, res, next) => {
|
module.exports = (err, req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (err.name === 'ValidationError') {
|
if (err.name === 'ValidationError') {
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ const createErrorHandler = ({ req, res, getContext, originPath = '/assistants/ch
|
||||||
} else if (/Files.*are invalid/.test(error.message)) {
|
} else if (/Files.*are invalid/.test(error.message)) {
|
||||||
const errorMessage = `Files are invalid, or may not have uploaded yet.${
|
const errorMessage = `Files are invalid, or may not have uploaded yet.${
|
||||||
endpoint === 'azureAssistants'
|
endpoint === 'azureAssistants'
|
||||||
? ' If using Azure OpenAI, files are only available in the region of the assistant\'s model at the time of upload.'
|
? " If using Azure OpenAI, files are only available in the region of the assistant's model at the time of upload."
|
||||||
: ''
|
: ''
|
||||||
}`;
|
}`;
|
||||||
return sendResponse(req, res, messageData, errorMessage);
|
return sendResponse(req, res, messageData, errorMessage);
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
|
||||||
// Save user message if needed
|
// Save user message if needed
|
||||||
if (!client.skipSaveUserMessage) {
|
if (!client.skipSaveUserMessage) {
|
||||||
await saveMessage(req, userMessage, {
|
await saveMessage(req, userMessage, {
|
||||||
context: 'api/server/controllers/agents/request.js - don\'t skip saving user message',
|
context: "api/server/controllers/agents/request.js - don't skip saving user message",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ const createErrorHandler = ({ req, res, getContext, originPath = '/assistants/ch
|
||||||
} else if (/Files.*are invalid/.test(error.message)) {
|
} else if (/Files.*are invalid/.test(error.message)) {
|
||||||
const errorMessage = `Files are invalid, or may not have uploaded yet.${
|
const errorMessage = `Files are invalid, or may not have uploaded yet.${
|
||||||
endpoint === 'azureAssistants'
|
endpoint === 'azureAssistants'
|
||||||
? ' If using Azure OpenAI, files are only available in the region of the assistant\'s model at the time of upload.'
|
? " If using Azure OpenAI, files are only available in the region of the assistant's model at the time of upload."
|
||||||
: ''
|
: ''
|
||||||
}`;
|
}`;
|
||||||
return sendResponse(req, res, messageData, errorMessage);
|
return sendResponse(req, res, messageData, errorMessage);
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,10 @@ const createAssistant = async (req, res) => {
|
||||||
const toolDefinitions = req.app.locals.availableTools;
|
const toolDefinitions = req.app.locals.availableTools;
|
||||||
const toolDef = toolDefinitions[tool];
|
const toolDef = toolDefinitions[tool];
|
||||||
if (!toolDef && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
|
if (!toolDef && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
|
||||||
return (
|
return Object.entries(toolDefinitions)
|
||||||
Object.entries(toolDefinitions)
|
.filter(([key]) => key.startsWith(`${tool}_`))
|
||||||
.filter(([key]) => key.startsWith(`${tool}_`))
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
.map(([_, val]) => val);
|
||||||
.map(([_, val]) => val)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return toolDef;
|
return toolDef;
|
||||||
|
|
@ -144,12 +142,10 @@ const patchAssistant = async (req, res) => {
|
||||||
const toolDefinitions = req.app.locals.availableTools;
|
const toolDefinitions = req.app.locals.availableTools;
|
||||||
const toolDef = toolDefinitions[tool];
|
const toolDef = toolDefinitions[tool];
|
||||||
if (!toolDef && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
|
if (!toolDef && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
|
||||||
return (
|
return Object.entries(toolDefinitions)
|
||||||
Object.entries(toolDefinitions)
|
.filter(([key]) => key.startsWith(`${tool}_`))
|
||||||
.filter(([key]) => key.startsWith(`${tool}_`))
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
.map(([_, val]) => val);
|
||||||
.map(([_, val]) => val)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return toolDef;
|
return toolDef;
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,10 @@ const createAssistant = async (req, res) => {
|
||||||
const toolDefinitions = req.app.locals.availableTools;
|
const toolDefinitions = req.app.locals.availableTools;
|
||||||
const toolDef = toolDefinitions[tool];
|
const toolDef = toolDefinitions[tool];
|
||||||
if (!toolDef && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
|
if (!toolDef && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
|
||||||
return (
|
return Object.entries(toolDefinitions)
|
||||||
Object.entries(toolDefinitions)
|
.filter(([key]) => key.startsWith(`${tool}_`))
|
||||||
.filter(([key]) => key.startsWith(`${tool}_`))
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
.map(([_, val]) => val);
|
||||||
.map(([_, val]) => val)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return toolDef;
|
return toolDef;
|
||||||
|
|
@ -131,7 +129,7 @@ const updateAssistant = async ({ req, openai, assistant_id, updateData }) => {
|
||||||
if (!actualTool && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
|
if (!actualTool && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
|
||||||
actualTool = Object.entries(toolDefinitions)
|
actualTool = Object.entries(toolDefinitions)
|
||||||
.filter(([key]) => key.startsWith(`${tool}_`))
|
.filter(([key]) => key.startsWith(`${tool}_`))
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
.map(([_, val]) => val);
|
.map(([_, val]) => val);
|
||||||
} else if (!actualTool) {
|
} else if (!actualTool) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,7 @@ const handleAbortError = async (res, req, error, data) => {
|
||||||
errorText = `{"type":"${ErrorTypes.INVALID_REQUEST}"}`;
|
errorText = `{"type":"${ErrorTypes.INVALID_REQUEST}"}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error?.message?.includes('does not support \'system\'')) {
|
if (error?.message?.includes("does not support 'system'")) {
|
||||||
errorText = `{"type":"${ErrorTypes.NO_SYSTEM_MESSAGES}"}`;
|
errorText = `{"type":"${ErrorTypes.NO_SYSTEM_MESSAGES}"}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ async function abortRun(req, res) {
|
||||||
const [thread_id, run_id] = runValues.split(':');
|
const [thread_id, run_id] = runValues.split(':');
|
||||||
|
|
||||||
if (!run_id) {
|
if (!run_id) {
|
||||||
logger.warn('[abortRun] Couldn\'t find run for cancel request', { thread_id });
|
logger.warn("[abortRun] Couldn't find run for cancel request", { thread_id });
|
||||||
return res.status(204).send({ message: 'Run not found' });
|
return res.status(204).send({ message: 'Run not found' });
|
||||||
} else if (run_id === 'cancelled') {
|
} else if (run_id === 'cancelled') {
|
||||||
logger.warn('[abortRun] Run already cancelled', { thread_id });
|
logger.warn('[abortRun] Run already cancelled', { thread_id });
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ afterEach(() => {
|
||||||
|
|
||||||
//TODO: This works/passes locally but http request tests fail with 404 in CI. Need to figure out why.
|
//TODO: This works/passes locally but http request tests fail with 404 in CI. Need to figure out why.
|
||||||
|
|
||||||
// eslint-disable-next-line jest/no-disabled-tests
|
|
||||||
describe.skip('GET /', () => {
|
describe.skip('GET /', () => {
|
||||||
it('should return 200 and the correct body', async () => {
|
it('should return 200 and the correct body', async () => {
|
||||||
process.env.APP_TITLE = 'Test Title';
|
process.env.APP_TITLE = 'Test Title';
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,7 @@ router.get('/', requireJwtAuth, async (req, res) => {
|
||||||
sortDirection: ['asc', 'desc'].includes(req.query.sortDirection)
|
sortDirection: ['asc', 'desc'].includes(req.query.sortDirection)
|
||||||
? req.query.sortDirection
|
? req.query.sortDirection
|
||||||
: 'desc',
|
: 'desc',
|
||||||
search: req.query.search
|
search: req.query.search ? decodeURIComponent(req.query.search.trim()) : undefined,
|
||||||
? decodeURIComponent(req.query.search.trim())
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await getSharedLinks(
|
const result = await getSharedLinks(
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* @readonly
|
* @readonly
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
const Tools = {
|
const Tools = {
|
||||||
code_interpreter: 'code_interpreter',
|
code_interpreter: 'code_interpreter',
|
||||||
retrieval: 'retrieval',
|
retrieval: 'retrieval',
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,9 @@ describe('replaceArtifactContent', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should replace content within artifact boundaries', () => {
|
test('should replace content within artifact boundaries', () => {
|
||||||
const original = 'console.log(\'hello\')';
|
const original = "console.log('hello')";
|
||||||
const artifact = createTestArtifact(original);
|
const artifact = createTestArtifact(original);
|
||||||
const updated = 'console.log(\'updated\')';
|
const updated = "console.log('updated')";
|
||||||
|
|
||||||
const result = replaceArtifactContent(artifact.text, artifact, original, updated);
|
const result = replaceArtifactContent(artifact.text, artifact, original, updated);
|
||||||
expect(result).toContain(updated);
|
expect(result).toContain(updated);
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,14 @@ async function loadAsyncEndpoints(req) {
|
||||||
const gptPlugins =
|
const gptPlugins =
|
||||||
useAzure || openAIApiKey || azureOpenAIApiKey
|
useAzure || openAIApiKey || azureOpenAIApiKey
|
||||||
? {
|
? {
|
||||||
availableAgents: ['classic', 'functions'],
|
availableAgents: ['classic', 'functions'],
|
||||||
userProvide: useAzure ? false : userProvidedOpenAI,
|
userProvide: useAzure ? false : userProvidedOpenAI,
|
||||||
userProvideURL: useAzure
|
userProvideURL: useAzure
|
||||||
? false
|
? false
|
||||||
: config[EModelEndpoint.openAI]?.userProvideURL ||
|
: config[EModelEndpoint.openAI]?.userProvideURL ||
|
||||||
config[EModelEndpoint.azureOpenAI]?.userProvideURL,
|
config[EModelEndpoint.azureOpenAI]?.userProvideURL,
|
||||||
azure: useAzurePlugins || useAzure,
|
azure: useAzurePlugins || useAzure,
|
||||||
}
|
}
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
return { google, gptPlugins };
|
return { google, gptPlugins };
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
|
||||||
const { getAssistant } = require('~/models/Assistant');
|
const { getAssistant } = require('~/models/Assistant');
|
||||||
|
|
||||||
const buildOptions = async (endpoint, parsedBody) => {
|
const buildOptions = async (endpoint, parsedBody) => {
|
||||||
|
|
||||||
const { promptPrefix, assistant_id, iconURL, greeting, spec, artifacts, ...modelOptions } =
|
const { promptPrefix, assistant_id, iconURL, greeting, spec, artifacts, ...modelOptions } =
|
||||||
parsedBody;
|
parsedBody;
|
||||||
const endpointOption = removeNullishValues({
|
const endpointOption = removeNullishValues({
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ const initializeClient = async ({ req, res, endpointOption, overrideModel, optio
|
||||||
const credentials = isUserProvided
|
const credentials = isUserProvided
|
||||||
? userKey
|
? userKey
|
||||||
: {
|
: {
|
||||||
[AuthKeys.GOOGLE_SERVICE_KEY]: serviceKey,
|
[AuthKeys.GOOGLE_SERVICE_KEY]: serviceKey,
|
||||||
[AuthKeys.GOOGLE_API_KEY]: GOOGLE_KEY,
|
[AuthKeys.GOOGLE_API_KEY]: GOOGLE_KEY,
|
||||||
};
|
};
|
||||||
|
|
||||||
let clientOptions = {};
|
let clientOptions = {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ function getLLMConfig(credentials, options = {}) {
|
||||||
// Extract from credentials
|
// Extract from credentials
|
||||||
const serviceKeyRaw = creds[AuthKeys.GOOGLE_SERVICE_KEY] ?? {};
|
const serviceKeyRaw = creds[AuthKeys.GOOGLE_SERVICE_KEY] ?? {};
|
||||||
const serviceKey =
|
const serviceKey =
|
||||||
typeof serviceKeyRaw === 'string' ? JSON.parse(serviceKeyRaw) : serviceKeyRaw ?? {};
|
typeof serviceKeyRaw === 'string' ? JSON.parse(serviceKeyRaw) : (serviceKeyRaw ?? {});
|
||||||
|
|
||||||
const project_id = serviceKey?.project_id ?? null;
|
const project_id = serviceKey?.project_id ?? null;
|
||||||
const apiKey = creds[AuthKeys.GOOGLE_API_KEY] ?? null;
|
const apiKey = creds[AuthKeys.GOOGLE_API_KEY] ?? null;
|
||||||
|
|
|
||||||
|
|
@ -114,11 +114,11 @@ describe('gptPlugins/initializeClient', () => {
|
||||||
test('should initialize PluginsClient with Azure credentials when PLUGINS_USE_AZURE is true', async () => {
|
test('should initialize PluginsClient with Azure credentials when PLUGINS_USE_AZURE is true', async () => {
|
||||||
process.env.AZURE_API_KEY = 'test-azure-api-key';
|
process.env.AZURE_API_KEY = 'test-azure-api-key';
|
||||||
(process.env.AZURE_OPENAI_API_INSTANCE_NAME = 'some-value'),
|
(process.env.AZURE_OPENAI_API_INSTANCE_NAME = 'some-value'),
|
||||||
(process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME = 'some-value'),
|
(process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME = 'some-value'),
|
||||||
(process.env.AZURE_OPENAI_API_VERSION = 'some-value'),
|
(process.env.AZURE_OPENAI_API_VERSION = 'some-value'),
|
||||||
(process.env.AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME = 'some-value'),
|
(process.env.AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME = 'some-value'),
|
||||||
(process.env.AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME = 'some-value'),
|
(process.env.AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME = 'some-value'),
|
||||||
(process.env.PLUGINS_USE_AZURE = 'true');
|
(process.env.PLUGINS_USE_AZURE = 'true');
|
||||||
process.env.DEBUG_PLUGINS = 'false';
|
process.env.DEBUG_PLUGINS = 'false';
|
||||||
process.env.OPENAI_SUMMARIZE = 'false';
|
process.env.OPENAI_SUMMARIZE = 'false';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,11 +112,11 @@ describe('initializeClient', () => {
|
||||||
test('should initialize client with Azure credentials when endpoint is azureOpenAI', async () => {
|
test('should initialize client with Azure credentials when endpoint is azureOpenAI', async () => {
|
||||||
process.env.AZURE_API_KEY = 'test-azure-api-key';
|
process.env.AZURE_API_KEY = 'test-azure-api-key';
|
||||||
(process.env.AZURE_OPENAI_API_INSTANCE_NAME = 'some-value'),
|
(process.env.AZURE_OPENAI_API_INSTANCE_NAME = 'some-value'),
|
||||||
(process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME = 'some-value'),
|
(process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME = 'some-value'),
|
||||||
(process.env.AZURE_OPENAI_API_VERSION = 'some-value'),
|
(process.env.AZURE_OPENAI_API_VERSION = 'some-value'),
|
||||||
(process.env.AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME = 'some-value'),
|
(process.env.AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME = 'some-value'),
|
||||||
(process.env.AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME = 'some-value'),
|
(process.env.AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME = 'some-value'),
|
||||||
(process.env.OPENAI_API_KEY = 'test-openai-api-key');
|
(process.env.OPENAI_API_KEY = 'test-openai-api-key');
|
||||||
process.env.DEBUG_OPENAI = 'false';
|
process.env.DEBUG_OPENAI = 'false';
|
||||||
process.env.OPENAI_SUMMARIZE = 'false';
|
process.env.OPENAI_SUMMARIZE = 'false';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ class StreamRunManager {
|
||||||
|
|
||||||
for (const d of delta[key]) {
|
for (const d of delta[key]) {
|
||||||
if (typeof d === 'object' && !Object.prototype.hasOwnProperty.call(d, 'index')) {
|
if (typeof d === 'object' && !Object.prototype.hasOwnProperty.call(d, 'index')) {
|
||||||
logger.warn('Expected an object with an \'index\' for array updates but got:', d);
|
logger.warn("Expected an object with an 'index' for array updates but got:", d);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ describe('processMessages', () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: {
|
text: {
|
||||||
value:
|
value:
|
||||||
'The text you have uploaded is from the book "Harry Potter and the Philosopher\'s Stone" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander\'s【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher\'s Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry\'s initial experiences in the magical world and set the stage for his adventures at Hogwarts.',
|
"The text you have uploaded is from the book \"Harry Potter and the Philosopher's Stone\" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander's【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher's Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry's initial experiences in the magical world and set the stage for his adventures at Hogwarts.",
|
||||||
annotations: [
|
annotations: [
|
||||||
{
|
{
|
||||||
type: 'file_citation',
|
type: 'file_citation',
|
||||||
|
|
@ -424,7 +424,7 @@ These points highlight Harry's initial experiences in the magical world and set
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: {
|
text: {
|
||||||
value:
|
value:
|
||||||
'The text you have uploaded is from the book "Harry Potter and the Philosopher\'s Stone" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander\'s【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher\'s Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry\'s initial experiences in the magical world and set the stage for his adventures at Hogwarts.',
|
"The text you have uploaded is from the book \"Harry Potter and the Philosopher's Stone\" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander's【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher's Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry's initial experiences in the magical world and set the stage for his adventures at Hogwarts.",
|
||||||
annotations: [
|
annotations: [
|
||||||
{
|
{
|
||||||
type: 'file_citation',
|
type: 'file_citation',
|
||||||
|
|
@ -582,7 +582,7 @@ These points highlight Harry's initial experiences in the magical world and set
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: {
|
text: {
|
||||||
value:
|
value:
|
||||||
'This is a test ^1^ with pre-existing citation-like text. Here\'s a real citation【11:2†source】.',
|
"This is a test ^1^ with pre-existing citation-like text. Here's a real citation【11:2†source】.",
|
||||||
annotations: [
|
annotations: [
|
||||||
{
|
{
|
||||||
type: 'file_citation',
|
type: 'file_citation',
|
||||||
|
|
@ -610,7 +610,7 @@ These points highlight Harry's initial experiences in the magical world and set
|
||||||
});
|
});
|
||||||
|
|
||||||
const expectedText =
|
const expectedText =
|
||||||
'This is a test ^1^ with pre-existing citation-like text. Here\'s a real citation^1^.\n\n^1.^ test.txt';
|
"This is a test ^1^ with pre-existing citation-like text. Here's a real citation^1^.\n\n^1.^ test.txt";
|
||||||
|
|
||||||
expect(result.text).toBe(expectedText);
|
expect(result.text).toBe(expectedText);
|
||||||
expect(result.edited).toBe(true);
|
expect(result.edited).toBe(true);
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,13 @@ const getProfileDetails = ({ idToken, profile }) => {
|
||||||
|
|
||||||
const decoded = jwt.decode(idToken);
|
const decoded = jwt.decode(idToken);
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(`Decoded Apple JWT: ${JSON.stringify(decoded, null, 2)}`);
|
||||||
`Decoded Apple JWT: ${JSON.stringify(decoded, null, 2)}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
email: decoded.email,
|
email: decoded.email,
|
||||||
id: decoded.sub,
|
id: decoded.sub,
|
||||||
avatarUrl: null, // Apple does not provide an avatar URL
|
avatarUrl: null, // Apple does not provide an avatar URL
|
||||||
username: decoded.email
|
username: decoded.email ? decoded.email.split('@')[0].toLowerCase() : `user_${decoded.sub}`,
|
||||||
? decoded.email.split('@')[0].toLowerCase()
|
|
||||||
: `user_${decoded.sub}`,
|
|
||||||
name: decoded.name
|
name: decoded.name
|
||||||
? `${decoded.name.firstName} ${decoded.name.lastName}`
|
? `${decoded.name.firstName} ${decoded.name.lastName}`
|
||||||
: profile.displayName || null,
|
: profile.displayName || null,
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,7 @@ describe('Apple Login Strategy', () => {
|
||||||
email: decoded.email,
|
email: decoded.email,
|
||||||
id: decoded.sub,
|
id: decoded.sub,
|
||||||
avatarUrl: null, // Apple does not provide an avatar URL
|
avatarUrl: null, // Apple does not provide an avatar URL
|
||||||
username: decoded.email
|
username: decoded.email ? decoded.email.split('@')[0].toLowerCase() : `user_${decoded.sub}`,
|
||||||
? decoded.email.split('@')[0].toLowerCase()
|
|
||||||
: `user_${decoded.sub}`,
|
|
||||||
name: decoded.name
|
name: decoded.name
|
||||||
? `${decoded.name.firstName} ${decoded.name.lastName}`
|
? `${decoded.name.firstName} ${decoded.name.lastName}`
|
||||||
: profile.displayName || null,
|
: profile.displayName || null,
|
||||||
|
|
@ -96,8 +94,12 @@ describe('Apple Login Strategy', () => {
|
||||||
|
|
||||||
// Mock isEnabled based on environment variable
|
// Mock isEnabled based on environment variable
|
||||||
isEnabled.mockImplementation((flag) => {
|
isEnabled.mockImplementation((flag) => {
|
||||||
if (flag === 'true') { return true; }
|
if (flag === 'true') {
|
||||||
if (flag === 'false') { return false; }
|
return true;
|
||||||
|
}
|
||||||
|
if (flag === 'false') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -154,9 +156,7 @@ describe('Apple Login Strategy', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(jwt.decode).toHaveBeenCalledWith('fake_id_token');
|
expect(jwt.decode).toHaveBeenCalledWith('fake_id_token');
|
||||||
expect(logger.debug).toHaveBeenCalledWith(
|
expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('Decoded Apple JWT'));
|
||||||
expect.stringContaining('Decoded Apple JWT'),
|
|
||||||
);
|
|
||||||
expect(profileDetails).toEqual({
|
expect(profileDetails).toEqual({
|
||||||
email: 'john.doe@example.com',
|
email: 'john.doe@example.com',
|
||||||
id: 'apple-sub-1234',
|
id: 'apple-sub-1234',
|
||||||
|
|
@ -297,7 +297,7 @@ describe('Apple Login Strategy', () => {
|
||||||
appleStrategyInstance._verify(
|
appleStrategyInstance._verify(
|
||||||
fakeAccessToken,
|
fakeAccessToken,
|
||||||
fakeRefreshToken,
|
fakeRefreshToken,
|
||||||
null, // idToken is missing
|
null, // idToken is missing
|
||||||
mockProfile,
|
mockProfile,
|
||||||
(err, user) => {
|
(err, user) => {
|
||||||
mockVerifyCallback(err, user);
|
mockVerifyCallback(err, user);
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,7 @@ describe('Zod Schemas', () => {
|
||||||
email: 'john@example.com',
|
email: 'john@example.com',
|
||||||
password: 'password123',
|
password: 'password123',
|
||||||
confirm_password: 'password123',
|
confirm_password: 'password123',
|
||||||
extraField: 'I shouldn\'t be here',
|
extraField: "I shouldn't be here",
|
||||||
});
|
});
|
||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
@ -407,7 +407,7 @@ describe('Zod Schemas', () => {
|
||||||
'john{doe}', // Contains `{` and `}`
|
'john{doe}', // Contains `{` and `}`
|
||||||
'j', // Only one character
|
'j', // Only one character
|
||||||
'a'.repeat(81), // More than 80 characters
|
'a'.repeat(81), // More than 80 characters
|
||||||
'\' OR \'1\'=\'1\'; --', // SQL Injection
|
"' OR '1'='1'; --", // SQL Injection
|
||||||
'{$ne: null}', // MongoDB Injection
|
'{$ne: null}', // MongoDB Injection
|
||||||
'<script>alert("XSS")</script>', // Basic XSS
|
'<script>alert("XSS")</script>', // Basic XSS
|
||||||
'"><script>alert("XSS")</script>', // XSS breaking out of an attribute
|
'"><script>alert("XSS")</script>', // XSS breaking out of an attribute
|
||||||
|
|
|
||||||
10
client/src/@types/i18next.d.ts
vendored
10
client/src/@types/i18next.d.ts
vendored
|
|
@ -1,9 +1,9 @@
|
||||||
import { defaultNS, resources } from '~/locales/i18n';
|
import { defaultNS, resources } from '~/locales/i18n';
|
||||||
|
|
||||||
declare module 'i18next' {
|
declare module 'i18next' {
|
||||||
interface CustomTypeOptions {
|
interface CustomTypeOptions {
|
||||||
defaultNS: typeof defaultNS;
|
defaultNS: typeof defaultNS;
|
||||||
resources: typeof resources.en;
|
resources: typeof resources.en;
|
||||||
strictKeyChecks: true
|
strictKeyChecks: true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
export type RenderProp<
|
export type RenderProp<
|
||||||
P = React.HTMLAttributes<any> & {
|
P = React.HTMLAttributes<any> & {
|
||||||
ref?: React.Ref<any>;
|
ref?: React.Ref<any>;
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,17 @@ export function useDebounceCodeBlock() {
|
||||||
const setCodeBlocks = useSetRecoilState(codeBlocksState);
|
const setCodeBlocks = useSetRecoilState(codeBlocksState);
|
||||||
const setCodeBlockIds = useSetRecoilState(codeBlockIdsState);
|
const setCodeBlockIds = useSetRecoilState(codeBlockIdsState);
|
||||||
|
|
||||||
const updateCodeBlock = useCallback((codeBlock: CodeBlock) => {
|
const updateCodeBlock = useCallback(
|
||||||
console.log('Updating code block:', codeBlock);
|
(codeBlock: CodeBlock) => {
|
||||||
setCodeBlocks((prev) => ({
|
console.log('Updating code block:', codeBlock);
|
||||||
...prev,
|
setCodeBlocks((prev) => ({
|
||||||
[codeBlock.id]: codeBlock,
|
...prev,
|
||||||
}));
|
[codeBlock.id]: codeBlock,
|
||||||
setCodeBlockIds((prev) =>
|
}));
|
||||||
prev.includes(codeBlock.id) ? prev : [...prev, codeBlock.id],
|
setCodeBlockIds((prev) => (prev.includes(codeBlock.id) ? prev : [...prev, codeBlock.id]));
|
||||||
);
|
},
|
||||||
}, [setCodeBlocks, setCodeBlockIds]);
|
[setCodeBlocks, setCodeBlockIds],
|
||||||
|
);
|
||||||
|
|
||||||
const debouncedUpdateCodeBlock = useCallback(
|
const debouncedUpdateCodeBlock = useCallback(
|
||||||
debounce((codeBlock: CodeBlock) => {
|
debounce((codeBlock: CodeBlock) => {
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,8 @@ function AuthLayout({
|
||||||
{children}
|
{children}
|
||||||
{!pathname.includes('2fa') &&
|
{!pathname.includes('2fa') &&
|
||||||
(pathname.includes('login') || pathname.includes('register')) && (
|
(pathname.includes('login') || pathname.includes('register')) && (
|
||||||
<SocialLoginRender startupConfig={startupConfig} />
|
<SocialLoginRender startupConfig={startupConfig} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Footer startupConfig={startupConfig} />
|
<Footer startupConfig={startupConfig} />
|
||||||
|
|
|
||||||
|
|
@ -105,23 +105,12 @@ function RequestPasswordReset() {
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
aria-invalid={!!errors.email}
|
aria-invalid={!!errors.email}
|
||||||
className="
|
className="peer w-full rounded-lg border border-gray-300 bg-transparent px-4 py-3 text-base text-gray-900 placeholder-transparent transition-all focus:border-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/20 dark:border-gray-700 dark:text-white dark:focus:border-green-500"
|
||||||
peer w-full rounded-lg border border-gray-300 bg-transparent px-4 py-3
|
|
||||||
text-base text-gray-900 placeholder-transparent transition-all
|
|
||||||
focus:border-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/20
|
|
||||||
dark:border-gray-700 dark:text-white dark:focus:border-green-500
|
|
||||||
"
|
|
||||||
placeholder="email@example.com"
|
placeholder="email@example.com"
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor="email"
|
htmlFor="email"
|
||||||
className="
|
className="absolute -top-2 left-2 z-10 bg-white px-2 text-sm text-gray-600 transition-all peer-placeholder-shown:top-3 peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-500 peer-focus:-top-2 peer-focus:text-sm peer-focus:text-green-600 dark:bg-gray-900 dark:text-gray-400 dark:peer-focus:text-green-500"
|
||||||
absolute -top-2 left-2 z-10 bg-white px-2 text-sm text-gray-600
|
|
||||||
transition-all peer-placeholder-shown:top-3 peer-placeholder-shown:text-base
|
|
||||||
peer-placeholder-shown:text-gray-500 peer-focus:-top-2 peer-focus:text-sm
|
|
||||||
peer-focus:text-green-600 dark:bg-gray-900 dark:text-gray-400
|
|
||||||
dark:peer-focus:text-green-500
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
{localize('com_auth_email_address')}
|
{localize('com_auth_email_address')}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -136,12 +125,7 @@ function RequestPasswordReset() {
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!!errors.email}
|
disabled={!!errors.email}
|
||||||
className="
|
className="w-full rounded-2xl bg-green-600 px-4 py-3 text-sm font-medium text-white transition-colors hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50 disabled:hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-700"
|
||||||
w-full rounded-2xl bg-green-600 px-4 py-3 text-sm font-medium text-white
|
|
||||||
transition-colors hover:bg-green-700 focus:outline-none focus:ring-2
|
|
||||||
focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50
|
|
||||||
disabled:hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-700
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
{localize('com_auth_continue')}
|
{localize('com_auth_continue')}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -89,20 +89,12 @@ function ResetPassword() {
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
aria-invalid={!!errors.password}
|
aria-invalid={!!errors.password}
|
||||||
className="
|
className="webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none"
|
||||||
webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light
|
|
||||||
bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none
|
|
||||||
"
|
|
||||||
placeholder=" "
|
placeholder=" "
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor="password"
|
htmlFor="password"
|
||||||
className="
|
className="absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200 peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100 peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-500 rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4"
|
||||||
absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200
|
|
||||||
peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100
|
|
||||||
peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-500
|
|
||||||
rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
{localize('com_auth_password')}
|
{localize('com_auth_password')}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -124,20 +116,12 @@ function ResetPassword() {
|
||||||
validate: (value) => value === password || localize('com_auth_password_not_match'),
|
validate: (value) => value === password || localize('com_auth_password_not_match'),
|
||||||
})}
|
})}
|
||||||
aria-invalid={!!errors.confirm_password}
|
aria-invalid={!!errors.confirm_password}
|
||||||
className="
|
className="webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none"
|
||||||
webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light
|
|
||||||
bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none
|
|
||||||
"
|
|
||||||
placeholder=" "
|
placeholder=" "
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor="confirm_password"
|
htmlFor="confirm_password"
|
||||||
className="
|
className="absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200 peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100 peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-500 rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4"
|
||||||
absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200
|
|
||||||
peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100
|
|
||||||
peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-500
|
|
||||||
rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
{localize('com_auth_password_confirm')}
|
{localize('com_auth_password_confirm')}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -163,12 +147,7 @@ function ResetPassword() {
|
||||||
disabled={!!errors.password || !!errors.confirm_password}
|
disabled={!!errors.password || !!errors.confirm_password}
|
||||||
type="submit"
|
type="submit"
|
||||||
aria-label={localize('com_auth_submit_registration')}
|
aria-label={localize('com_auth_submit_registration')}
|
||||||
className="
|
className="w-full rounded-2xl bg-green-600 px-4 py-3 text-sm font-medium text-white transition-colors hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50 disabled:hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-700"
|
||||||
w-full rounded-2xl bg-green-600 px-4 py-3 text-sm font-medium text-white
|
|
||||||
transition-colors hover:bg-green-700 focus:outline-none focus:ring-2
|
|
||||||
focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50
|
|
||||||
disabled:hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-700
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
{localize('com_auth_continue')}
|
{localize('com_auth_continue')}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,6 @@ test('renders registration form', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line jest/no-commented-out-tests
|
|
||||||
// test('calls registerUser.mutate on registration', async () => {
|
// test('calls registerUser.mutate on registration', async () => {
|
||||||
// const mutate = jest.fn();
|
// const mutate = jest.fn();
|
||||||
// const { getByTestId, getByRole, history } = setup({
|
// const { getByTestId, getByRole, history } = setup({
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,6 @@
|
||||||
export default function DragDropOverlay() {
|
export default function DragDropOverlay() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="bg-surface-primary/85 fixed inset-0 z-[9999] flex flex-col items-center justify-center gap-2 text-text-primary backdrop-blur-[4px] transition-all duration-200 ease-in-out animate-in fade-in zoom-in-95 hover:backdrop-blur-sm">
|
||||||
className="bg-surface-primary/85 fixed inset-0 z-[9999] flex flex-col items-center justify-center
|
|
||||||
gap-2 text-text-primary
|
|
||||||
backdrop-blur-[4px] transition-all duration-200
|
|
||||||
ease-in-out animate-in fade-in
|
|
||||||
zoom-in-95 hover:backdrop-blur-sm"
|
|
||||||
>
|
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 132 108"
|
viewBox="0 0 132 108"
|
||||||
|
|
@ -55,8 +49,8 @@ export default function DragDropOverlay() {
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
<h3>Add anything</h3>
|
<h3>{localize('com_ui_add_anything')}</h3>
|
||||||
<h4>Drop any file here to add it to the conversation</h4>
|
<h4>{localize('com_ui_add_anything_description')}</h4>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,9 +93,9 @@ const ImagePreview = ({
|
||||||
|
|
||||||
const style: styleProps = imageUrl
|
const style: styleProps = imageUrl
|
||||||
? {
|
? {
|
||||||
...baseStyle,
|
...baseStyle,
|
||||||
backgroundImage: `url(${imageUrl})`,
|
backgroundImage: `url(${imageUrl})`,
|
||||||
}
|
}
|
||||||
: baseStyle;
|
: baseStyle;
|
||||||
|
|
||||||
if (typeof style.backgroundImage !== 'string' || style.backgroundImage.length === 0) {
|
if (typeof style.backgroundImage !== 'string' || style.backgroundImage.length === 0) {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export default function StreamAudio({ index = 0 }) {
|
||||||
const { pauseGlobalAudio } = usePauseGlobalAudio();
|
const { pauseGlobalAudio } = usePauseGlobalAudio();
|
||||||
|
|
||||||
const { conversationId: paramId } = useParams();
|
const { conversationId: paramId } = useParams();
|
||||||
const queryParam = paramId === 'new' ? paramId : latestMessage?.conversationId ?? paramId ?? '';
|
const queryParam = paramId === 'new' ? paramId : (latestMessage?.conversationId ?? paramId ?? '');
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const getMessages = useCallback(
|
const getMessages = useCallback(
|
||||||
|
|
|
||||||
|
|
@ -102,12 +102,12 @@ export function EndpointItem({ endpoint }: EndpointItemProps) {
|
||||||
if (endpoint.hasModels) {
|
if (endpoint.hasModels) {
|
||||||
const filteredModels = searchValue
|
const filteredModels = searchValue
|
||||||
? filterModels(
|
? filterModels(
|
||||||
endpoint,
|
endpoint,
|
||||||
(endpoint.models || []).map((model) => model.name),
|
(endpoint.models || []).map((model) => model.name),
|
||||||
searchValue,
|
searchValue,
|
||||||
agentsMap,
|
agentsMap,
|
||||||
assistantsMap,
|
assistantsMap,
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
const placeholder =
|
const placeholder =
|
||||||
isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)
|
isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,10 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
|
||||||
</div>
|
</div>
|
||||||
) : (isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)) &&
|
) : (isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)) &&
|
||||||
endpoint.icon ? (
|
endpoint.icon ? (
|
||||||
<div className="flex h-5 w-5 items-center justify-center overflow-hidden rounded-full">
|
<div className="flex h-5 w-5 items-center justify-center overflow-hidden rounded-full">
|
||||||
{endpoint.icon}
|
{endpoint.icon}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<span>{modelName}</span>
|
<span>{modelName}</span>
|
||||||
</div>
|
</div>
|
||||||
{isGlobal && <EarthIcon className="ml-auto size-4 text-green-400" />}
|
{isGlobal && <EarthIcon className="ml-auto size-4 text-green-400" />}
|
||||||
|
|
|
||||||
|
|
@ -102,22 +102,22 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
||||||
const filteredModels = endpoint.label.toLowerCase().includes(lowerQuery)
|
const filteredModels = endpoint.label.toLowerCase().includes(lowerQuery)
|
||||||
? endpoint.models
|
? endpoint.models
|
||||||
: endpoint.models.filter((model) => {
|
: endpoint.models.filter((model) => {
|
||||||
let modelName = model.name;
|
let modelName = model.name;
|
||||||
if (
|
if (
|
||||||
isAgentsEndpoint(endpoint.value) &&
|
isAgentsEndpoint(endpoint.value) &&
|
||||||
endpoint.agentNames &&
|
endpoint.agentNames &&
|
||||||
endpoint.agentNames[model.name]
|
endpoint.agentNames[model.name]
|
||||||
) {
|
) {
|
||||||
modelName = endpoint.agentNames[model.name];
|
modelName = endpoint.agentNames[model.name];
|
||||||
} else if (
|
} else if (
|
||||||
isAssistantsEndpoint(endpoint.value) &&
|
isAssistantsEndpoint(endpoint.value) &&
|
||||||
endpoint.assistantNames &&
|
endpoint.assistantNames &&
|
||||||
endpoint.assistantNames[model.name]
|
endpoint.assistantNames[model.name]
|
||||||
) {
|
) {
|
||||||
modelName = endpoint.assistantNames[model.name];
|
modelName = endpoint.assistantNames[model.name];
|
||||||
}
|
}
|
||||||
return modelName.toLowerCase().includes(lowerQuery);
|
return modelName.toLowerCase().includes(lowerQuery);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!filteredModels.length) {
|
if (!filteredModels.length) {
|
||||||
return null; // skip if no models match
|
return null; // skip if no models match
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export const data: TModelSpec[] = [
|
||||||
iconURL: EModelEndpoint.openAI, // Allow using project-included icons
|
iconURL: EModelEndpoint.openAI, // Allow using project-included icons
|
||||||
preset: {
|
preset: {
|
||||||
chatGptLabel: 'Vision Helper',
|
chatGptLabel: 'Vision Helper',
|
||||||
greeting: 'What\'s up!!',
|
greeting: "What's up!!",
|
||||||
endpoint: EModelEndpoint.openAI,
|
endpoint: EModelEndpoint.openAI,
|
||||||
model: 'gpt-4-turbo',
|
model: 'gpt-4-turbo',
|
||||||
promptPrefix:
|
promptPrefix:
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ const MenuItem: FC<MenuItemProps> = ({
|
||||||
>
|
>
|
||||||
<div className="flex grow items-center justify-between gap-2">
|
<div className="flex grow items-center justify-between gap-2">
|
||||||
<div>
|
<div>
|
||||||
<div className={cn('flex items-center gap-1 ')}>
|
<div className={cn('flex items-center gap-1')}>
|
||||||
{icon != null ? icon : null}
|
{icon != null ? icon : null}
|
||||||
<div className={cn('truncate', textClassName)}>
|
<div className={cn('truncate', textClassName)}>
|
||||||
{title}
|
{title}
|
||||||
|
|
@ -72,7 +72,7 @@ const MenuItem: FC<MenuItemProps> = ({
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className="icon-md block "
|
className="icon-md block"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
|
|
|
||||||
|
|
@ -117,9 +117,9 @@ const EditTextPart = ({
|
||||||
messages.map((msg) =>
|
messages.map((msg) =>
|
||||||
msg.messageId === messageId
|
msg.messageId === messageId
|
||||||
? {
|
? {
|
||||||
...msg,
|
...msg,
|
||||||
content: updatedContent,
|
content: updatedContent,
|
||||||
}
|
}
|
||||||
: msg,
|
: msg,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil';
|
||||||
import { useMessageProcess } from '~/hooks';
|
import { useMessageProcess } from '~/hooks';
|
||||||
import type { TMessageProps } from '~/common';
|
import type { TMessageProps } from '~/common';
|
||||||
import MessageRender from './ui/MessageRender';
|
import MessageRender from './ui/MessageRender';
|
||||||
// eslint-disable-next-line import/no-cycle
|
|
||||||
import MultiMessage from './MultiMessage';
|
import MultiMessage from './MultiMessage';
|
||||||
import { cn } from '~/utils';
|
import { cn } from '~/utils';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
@ -73,7 +73,7 @@ export default function Message(props: TMessageProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="m-auto justify-center p-4 py-2 md:gap-6 ">
|
<div className="m-auto justify-center p-4 py-2 md:gap-6">
|
||||||
<MessageRender {...props} />
|
<MessageRender {...props} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ export function TemporaryChat() {
|
||||||
render={
|
render={
|
||||||
<button
|
<button
|
||||||
onClick={handleBadgeToggle}
|
onClick={handleBadgeToggle}
|
||||||
aria-label={localize(temporaryBadge.label)}
|
aria-label={localize(temporaryBadge.label)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex size-10 flex-shrink-0 items-center justify-center rounded-xl border border-border-light text-text-primary transition-all ease-in-out hover:bg-surface-tertiary',
|
'inline-flex size-10 flex-shrink-0 items-center justify-center rounded-xl border border-border-light text-text-primary transition-all ease-in-out hover:bg-surface-tertiary',
|
||||||
isTemporary
|
isTemporary
|
||||||
|
|
|
||||||
|
|
@ -48,15 +48,15 @@ const UserAvatar = memo(({ size, user, avatarSrc, username, className }: UserAva
|
||||||
>
|
>
|
||||||
{(!(user?.avatar ?? '') && (!(user?.username ?? '') || user?.username.trim() === '')) ||
|
{(!(user?.avatar ?? '') && (!(user?.username ?? '') || user?.username.trim() === '')) ||
|
||||||
imageError ? (
|
imageError ? (
|
||||||
renderDefaultAvatar()
|
renderDefaultAvatar()
|
||||||
) : (
|
) : (
|
||||||
<img
|
<img
|
||||||
className="rounded-full"
|
className="rounded-full"
|
||||||
src={(user?.avatar ?? '') || avatarSrc}
|
src={(user?.avatar ?? '') || avatarSrc}
|
||||||
alt="avatar"
|
alt="avatar"
|
||||||
onError={handleImageError}
|
onError={handleImageError}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }: TEditPresetProps) =>
|
||||||
});
|
});
|
||||||
|
|
||||||
const toastTitle =
|
const toastTitle =
|
||||||
_preset.title ?? '' ? `\`${_preset.title}\`` : localize('com_endpoint_preset_title');
|
(_preset.title ?? '') ? `\`${_preset.title}\`` : localize('com_endpoint_preset_title');
|
||||||
|
|
||||||
createPresetMutation.mutate(_preset, {
|
createPresetMutation.mutate(_preset, {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
|
|
@ -76,7 +76,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }: TEditPresetProps) =>
|
||||||
aria-label={localize('com_endpoint_preset_name')}
|
aria-label={localize('com_endpoint_preset_name')}
|
||||||
className={cn(
|
className={cn(
|
||||||
defaultTextProps,
|
defaultTextProps,
|
||||||
'flex h-10 max-h-10 w-full resize-none border-border-medium px-3 py-2 ',
|
'flex h-10 max-h-10 w-full resize-none border-border-medium px-3 py-2',
|
||||||
removeFocusOutlines,
|
removeFocusOutlines,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ export default function Settings({
|
||||||
placeholder={localize('com_endpoint_openai_prompt_prefix_placeholder')}
|
placeholder={localize('com_endpoint_openai_prompt_prefix_placeholder')}
|
||||||
className={cn(
|
className={cn(
|
||||||
defaultTextProps,
|
defaultTextProps,
|
||||||
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2 ',
|
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -160,6 +160,7 @@ export default function Settings({
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<Label htmlFor="top-p-int" className="text-left text-sm font-medium">
|
<Label htmlFor="top-p-int" className="text-left text-sm font-medium">
|
||||||
{localize('com_endpoint_top_p')}{' '}
|
{localize('com_endpoint_top_p')}{' '}
|
||||||
|
{/* eslint-disable-next-line i18next/no-literal-string */}
|
||||||
<small className="opacity-40">({localize('com_endpoint_default')}: 1)</small>
|
<small className="opacity-40">({localize('com_endpoint_default')}: 1)</small>
|
||||||
</Label>
|
</Label>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
|
|
@ -198,7 +199,8 @@ export default function Settings({
|
||||||
<HoverCardTrigger className="grid w-full items-center gap-2">
|
<HoverCardTrigger className="grid w-full items-center gap-2">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<Label htmlFor="freq-penalty-int" className="text-left text-sm font-medium">
|
<Label htmlFor="freq-penalty-int" className="text-left text-sm font-medium">
|
||||||
{localize('com_endpoint_frequency_penalty')}{' '}
|
{localize('com_endpoint_frequency_penalty')}
|
||||||
|
{/* eslint-disable-next-line i18next/no-literal-string */}
|
||||||
<small className="opacity-40">({localize('com_endpoint_default')}: 0)</small>
|
<small className="opacity-40">({localize('com_endpoint_default')}: 0)</small>
|
||||||
</Label>
|
</Label>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
|
|
@ -238,6 +240,7 @@ export default function Settings({
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<Label htmlFor="pres-penalty-int" className="text-left text-sm font-medium">
|
<Label htmlFor="pres-penalty-int" className="text-left text-sm font-medium">
|
||||||
{localize('com_endpoint_presence_penalty')}{' '}
|
{localize('com_endpoint_presence_penalty')}{' '}
|
||||||
|
{/* eslint-disable-next-line i18next/no-literal-string */}
|
||||||
<small className="opacity-40">({localize('com_endpoint_default')}: 0)</small>
|
<small className="opacity-40">({localize('com_endpoint_default')}: 0)</small>
|
||||||
</Label>
|
</Label>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
|
||||||
placeholder={localize('com_endpoint_prompt_prefix_assistants_placeholder')}
|
placeholder={localize('com_endpoint_prompt_prefix_assistants_placeholder')}
|
||||||
className={cn(
|
className={cn(
|
||||||
defaultTextProps,
|
defaultTextProps,
|
||||||
'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2 ',
|
'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -178,7 +178,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
|
||||||
placeholder={localize('com_endpoint_instructions_assistants_placeholder')}
|
placeholder={localize('com_endpoint_instructions_assistants_placeholder')}
|
||||||
className={cn(
|
className={cn(
|
||||||
defaultTextProps,
|
defaultTextProps,
|
||||||
'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2 ',
|
'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ function Examples({ readonly, examples, setExample, addExample, removeExample }:
|
||||||
placeholder="Set example input. Example is ignored if empty."
|
placeholder="Set example input. Example is ignored if empty."
|
||||||
className={cn(
|
className={cn(
|
||||||
defaultTextProps,
|
defaultTextProps,
|
||||||
'flex max-h-[138px] min-h-[75px] w-full resize-none px-3 py-2 ',
|
'flex max-h-[138px] min-h-[75px] w-full resize-none px-3 py-2',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -67,7 +67,7 @@ function Examples({ readonly, examples, setExample, addExample, removeExample }:
|
||||||
placeholder={'Set example output. Example is ignored if empty.'}
|
placeholder={'Set example output. Example is ignored if empty.'}
|
||||||
className={cn(
|
className={cn(
|
||||||
defaultTextProps,
|
defaultTextProps,
|
||||||
'flex max-h-[300px] min-h-[75px] w-full resize-none px-3 py-2 ',
|
'flex max-h-[300px] min-h-[75px] w-full resize-none px-3 py-2',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
|
||||||
placeholder={localize('com_endpoint_prompt_prefix_placeholder')}
|
placeholder={localize('com_endpoint_prompt_prefix_placeholder')}
|
||||||
className={cn(
|
className={cn(
|
||||||
defaultTextProps,
|
defaultTextProps,
|
||||||
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2 ',
|
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -221,7 +221,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
|
||||||
<Label htmlFor="top-k-int" className="text-left text-sm font-medium">
|
<Label htmlFor="top-k-int" className="text-left text-sm font-medium">
|
||||||
{localize('com_endpoint_top_k')}{' '}
|
{localize('com_endpoint_top_k')}{' '}
|
||||||
<small className="opacity-40">
|
<small className="opacity-40">
|
||||||
({localize('com_endpoint_default_with_num',{ 0: google.topK.default + '' })})
|
({localize('com_endpoint_default_with_num', { 0: google.topK.default + '' })})
|
||||||
</small>
|
</small>
|
||||||
</Label>
|
</Label>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
|
|
@ -261,7 +261,11 @@ export default function Settings({ conversation, setOption, models, readonly }:
|
||||||
<Label htmlFor="max-tokens-int" className="text-left text-sm font-medium">
|
<Label htmlFor="max-tokens-int" className="text-left text-sm font-medium">
|
||||||
{localize('com_endpoint_max_output_tokens')}{' '}
|
{localize('com_endpoint_max_output_tokens')}{' '}
|
||||||
<small className="opacity-40">
|
<small className="opacity-40">
|
||||||
({localize('com_endpoint_default_with_num', { 0: google.maxOutputTokens.default + '' })})
|
(
|
||||||
|
{localize('com_endpoint_default_with_num', {
|
||||||
|
0: google.maxOutputTokens.default + '',
|
||||||
|
})}
|
||||||
|
)
|
||||||
</small>
|
</small>
|
||||||
</Label>
|
</Label>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ export default function Settings({
|
||||||
)}
|
)}
|
||||||
className={cn(
|
className={cn(
|
||||||
defaultTextProps,
|
defaultTextProps,
|
||||||
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2 ',
|
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export default function Continue({ onClick }: TGenButtonProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button type="continue" onClick={onClick}>
|
<Button type="continue" onClick={onClick}>
|
||||||
<ContinueIcon className="text-gray-600/90 dark:text-gray-400 " />
|
<ContinueIcon className="text-gray-600/90 dark:text-gray-400" />
|
||||||
{localize('com_ui_continue')}
|
{localize('com_ui_continue')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export default function Stop({ onClick }: TGenButtonProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button type="stop" onClick={onClick}>
|
<Button type="stop" onClick={onClick}>
|
||||||
<StopGeneratingIcon className="text-gray-600/90 dark:text-gray-400 " />
|
<StopGeneratingIcon className="text-gray-600/90 dark:text-gray-400" />
|
||||||
{localize('com_ui_stop')}
|
{localize('com_ui_stop')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -171,8 +171,8 @@ const SetKeyDialog = ({
|
||||||
{expiryTime === 'never'
|
{expiryTime === 'never'
|
||||||
? localize('com_endpoint_config_key_never_expires')
|
? localize('com_endpoint_config_key_never_expires')
|
||||||
: `${localize('com_endpoint_config_key_encryption')} ${new Date(
|
: `${localize('com_endpoint_config_key_encryption')} ${new Date(
|
||||||
expiryTime ?? 0,
|
expiryTime ?? 0,
|
||||||
).toLocaleString()}`}
|
).toLocaleString()}`}
|
||||||
</small>
|
</small>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
label="Expires "
|
label="Expires "
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ const Plugin: React.FC<PluginProps> = ({ plugin }) => {
|
||||||
if (!plugin.loading && latestPlugin === 'self reflection') {
|
if (!plugin.loading && latestPlugin === 'self reflection') {
|
||||||
return 'Finished';
|
return 'Finished';
|
||||||
} else if (latestPlugin === 'self reflection') {
|
} else if (latestPlugin === 'self reflection') {
|
||||||
return 'I\'m thinking...';
|
return "I'm thinking...";
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -112,9 +112,7 @@ const Plugin: React.FC<PluginProps> = ({ plugin }) => {
|
||||||
/>
|
/>
|
||||||
{plugin.outputs && plugin.outputs.length > 0 && (
|
{plugin.outputs && plugin.outputs.length > 0 && (
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
lang={
|
lang={latestPlugin ? `RESPONSE FROM ${latestPlugin.toUpperCase()}` : 'RESPONSE'}
|
||||||
latestPlugin ? `RESPONSE FROM ${latestPlugin.toUpperCase()}` : 'RESPONSE'
|
|
||||||
}
|
|
||||||
codeChildren={formatJSON(plugin.outputs ?? '')}
|
codeChildren={formatJSON(plugin.outputs ?? '')}
|
||||||
plugin={true}
|
plugin={true}
|
||||||
classProp="max-h-[450px]"
|
classProp="max-h-[450px]"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useMessageProcess } from '~/hooks';
|
import { useMessageProcess } from '~/hooks';
|
||||||
import type { TMessageProps } from '~/common';
|
import type { TMessageProps } from '~/common';
|
||||||
// eslint-disable-next-line import/no-cycle
|
|
||||||
import MultiMessage from '~/components/Chat/Messages/MultiMessage';
|
import MultiMessage from '~/components/Chat/Messages/MultiMessage';
|
||||||
import ContentRender from './ContentRender';
|
import ContentRender from './ContentRender';
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ export default function MessageContent(props: TMessageProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="m-auto justify-center p-4 py-2 md:gap-6 ">
|
<div className="m-auto justify-center p-4 py-2 md:gap-6">
|
||||||
<ContentRender {...props} />
|
<ContentRender {...props} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export default function NavToggle({
|
||||||
className,
|
className,
|
||||||
'-translate-y-1/2 transition-transform',
|
'-translate-y-1/2 transition-transform',
|
||||||
navVisible ? 'rotate-0' : 'rotate-180',
|
navVisible ? 'rotate-0' : 'rotate-180',
|
||||||
navVisible && translateX ? 'translate-x-[260px]' : 'translate-x-0 ',
|
navVisible && translateX ? 'translate-x-[260px]' : 'translate-x-0',
|
||||||
)}
|
)}
|
||||||
onMouseEnter={() => setIsHovering(true)}
|
onMouseEnter={() => setIsHovering(true)}
|
||||||
onMouseLeave={() => setIsHovering(false)}
|
onMouseLeave={() => setIsHovering(false)}
|
||||||
|
|
|
||||||
|
|
@ -87,11 +87,11 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
|
||||||
},
|
},
|
||||||
...(startupConfig?.balance?.enabled
|
...(startupConfig?.balance?.enabled
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
value: SettingsTabValues.BALANCE,
|
value: SettingsTabValues.BALANCE,
|
||||||
icon: <DollarSign size={18} />,
|
icon: <DollarSign size={18} />,
|
||||||
label: 'com_nav_setting_balance' as TranslationKeys,
|
label: 'com_nav_setting_balance' as TranslationKeys,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: ([] as { value: SettingsTabValues; icon: React.JSX.Element; label: TranslationKeys }[])),
|
: ([] as { value: SettingsTabValues; icon: React.JSX.Element; label: TranslationKeys }[])),
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ export default function DecibelSelector() {
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>{localize('com_nav_db_sensitivity')}</div>
|
<div>{localize('com_nav_db_sensitivity')}</div>
|
||||||
<div className="w-2" />
|
<div className="w-2" />
|
||||||
<small className="opacity-40">({localize('com_endpoint_default_with_num', { 0: '-45' })})</small>
|
<small className="opacity-40">
|
||||||
|
({localize('com_endpoint_default_with_num', { 0: '-45' })})
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<Slider
|
<Slider
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ const EngineSTTDropdown: React.FC<EngineSTTDropdownProps> = ({ external }) => {
|
||||||
|
|
||||||
const endpointOptions = external
|
const endpointOptions = external
|
||||||
? [
|
? [
|
||||||
{ value: 'browser', label: localize('com_nav_browser') },
|
{ value: 'browser', label: localize('com_nav_browser') },
|
||||||
{ value: 'external', label: localize('com_nav_external') },
|
{ value: 'external', label: localize('com_nav_external') },
|
||||||
]
|
]
|
||||||
: [{ value: 'browser', label: localize('com_nav_browser') }];
|
: [{ value: 'browser', label: localize('com_nav_browser') }];
|
||||||
|
|
||||||
const handleSelect = (value: string) => {
|
const handleSelect = (value: string) => {
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ const EngineTTSDropdown: React.FC<EngineTTSDropdownProps> = ({ external }) => {
|
||||||
|
|
||||||
const endpointOptions = external
|
const endpointOptions = external
|
||||||
? [
|
? [
|
||||||
{ value: 'browser', label: localize('com_nav_browser') },
|
{ value: 'browser', label: localize('com_nav_browser') },
|
||||||
{ value: 'external', label: localize('com_nav_external') },
|
{ value: 'external', label: localize('com_nav_external') },
|
||||||
]
|
]
|
||||||
: [{ value: 'browser', label: localize('com_nav_browser') }];
|
: [{ value: 'browser', label: localize('com_nav_browser') }];
|
||||||
|
|
||||||
const handleSelect = (value: string) => {
|
const handleSelect = (value: string) => {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ export default function DecibelSelector() {
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>{localize('com_nav_playback_rate')}</div>
|
<div>{localize('com_nav_playback_rate')}</div>
|
||||||
<div className="w-2" />
|
<div className="w-2" />
|
||||||
<small className="opacity-40">({localize('com_endpoint_default_with_num', { 0: '1' })})</small>
|
<small className="opacity-40">
|
||||||
|
({localize('com_endpoint_default_with_num', { 0: '1' })})
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<Slider
|
<Slider
|
||||||
|
|
|
||||||
|
|
@ -187,8 +187,7 @@ function PluginStoreDialog({ isOpen, setIsOpen }: TPluginStoreDialogProps) {
|
||||||
value={searchValue}
|
value={searchValue}
|
||||||
onChange={handleSearch}
|
onChange={handleSearch}
|
||||||
placeholder={localize('com_nav_plugin_search')}
|
placeholder={localize('com_nav_plugin_search')}
|
||||||
className="
|
className="text-token-text-primary flex rounded-md border border-border-heavy bg-surface-tertiary py-2 pl-10 pr-2"
|
||||||
text-token-text-primary flex rounded-md border border-border-heavy bg-surface-tertiary py-2 pl-10 pr-2"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ type TPluginTooltipProps = {
|
||||||
function PluginTooltip({ content, position }: TPluginTooltipProps) {
|
function PluginTooltip({ content, position }: TPluginTooltipProps) {
|
||||||
return (
|
return (
|
||||||
<HoverCardPortal>
|
<HoverCardPortal>
|
||||||
<HoverCardContent side={position} className="w-80 ">
|
<HoverCardContent side={position} className="w-80">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="text-sm text-gray-600 dark:text-gray-300">
|
<div className="text-sm text-gray-600 dark:text-gray-300">
|
||||||
<div dangerouslySetInnerHTML={{ __html: content }} />
|
<div dangerouslySetInnerHTML={{ __html: content }} />
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,11 @@ export default function FilterPrompts({
|
||||||
const categoryOptions = categories
|
const categoryOptions = categories
|
||||||
? [...categories]
|
? [...categories]
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
value: SystemCategories.NO_CATEGORY,
|
value: SystemCategories.NO_CATEGORY,
|
||||||
label: localize('com_ui_no_category'),
|
label: localize('com_ui_no_category'),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return [...baseOptions, ...categoryOptions];
|
return [...baseOptions, ...categoryOptions];
|
||||||
}, [categories, localize]);
|
}, [categories, localize]);
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,7 @@ export default function ListCard({
|
||||||
<div
|
<div
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
className="relative my-2 flex w-full cursor-pointer flex-col gap-2 rounded-xl border border-border-light px-3 pb-4 pt-3 text-start
|
className="relative my-2 flex w-full cursor-pointer flex-col gap-2 rounded-xl border border-border-light px-3 pb-4 pt-3 text-start align-top text-[15px] shadow-sm transition-all duration-300 ease-in-out hover:bg-surface-tertiary hover:shadow-lg"
|
||||||
align-top text-[15px] shadow-sm transition-all duration-300 ease-in-out hover:bg-surface-tertiary hover:shadow-lg"
|
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
aria-labelledby={`card-title-${name}`}
|
aria-labelledby={`card-title-${name}`}
|
||||||
|
|
|
||||||
|
|
@ -287,18 +287,18 @@ const PromptForm = () => {
|
||||||
{editorMode === PromptsEditorMode.ADVANCED &&
|
{editorMode === PromptsEditorMode.ADVANCED &&
|
||||||
(isLoadingPrompts
|
(isLoadingPrompts
|
||||||
? Array.from({ length: 6 }).map((_, index: number) => (
|
? Array.from({ length: 6 }).map((_, index: number) => (
|
||||||
<div key={index} className="my-2">
|
<div key={index} className="my-2">
|
||||||
<Skeleton className="h-[72px] w-full" />
|
<Skeleton className="h-[72px] w-full" />
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
: prompts.length > 0 && (
|
: prompts.length > 0 && (
|
||||||
<PromptVersions
|
<PromptVersions
|
||||||
group={group}
|
group={group}
|
||||||
prompts={prompts}
|
prompts={prompts}
|
||||||
selectionIndex={selectionIndex}
|
selectionIndex={selectionIndex}
|
||||||
setSelectionIndex={setSelectionIndex}
|
setSelectionIndex={setSelectionIndex}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import type { TMessage } from 'librechat-data-provider';
|
import type { TMessage } from 'librechat-data-provider';
|
||||||
import type { TMessageProps } from '~/common';
|
import type { TMessageProps } from '~/common';
|
||||||
// eslint-disable-next-line import/no-cycle
|
|
||||||
import Message from './Message';
|
import Message from './Message';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export default function ImageVision() {
|
||||||
{...field}
|
{...field}
|
||||||
checked={field.value}
|
checked={field.value}
|
||||||
onCheckedChange={field.onChange}
|
onCheckedChange={field.onChange}
|
||||||
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
|
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
|
||||||
value={field.value?.toString()}
|
value={field.value?.toString()}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -135,10 +135,9 @@ export default function ShareAgent({
|
||||||
'btn btn-neutral border-token-border-light relative h-9 rounded-lg font-medium',
|
'btn btn-neutral border-token-border-light relative h-9 rounded-lg font-medium',
|
||||||
removeFocusOutlines,
|
removeFocusOutlines,
|
||||||
)}
|
)}
|
||||||
aria-label={localize(
|
aria-label={localize('com_ui_share_var', {
|
||||||
'com_ui_share_var',
|
0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent'),
|
||||||
{ 0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent') },
|
})}
|
||||||
)}
|
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-center gap-2 text-blue-500">
|
<div className="flex items-center justify-center gap-2 text-blue-500">
|
||||||
|
|
@ -148,10 +147,9 @@ export default function ShareAgent({
|
||||||
</OGDialogTrigger>
|
</OGDialogTrigger>
|
||||||
<OGDialogContent className="w-11/12 md:max-w-xl">
|
<OGDialogContent className="w-11/12 md:max-w-xl">
|
||||||
<OGDialogTitle>
|
<OGDialogTitle>
|
||||||
{localize(
|
{localize('com_ui_share_var', {
|
||||||
'com_ui_share_var',
|
0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent'),
|
||||||
{ 0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent') },
|
})}
|
||||||
)}
|
|
||||||
</OGDialogTitle>
|
</OGDialogTitle>
|
||||||
<form
|
<form
|
||||||
className="p-2"
|
className="p-2"
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,9 @@ const BookmarkTableRow: React.FC<BookmarkTableRowProps> = ({ row, moveRow, posit
|
||||||
accept: 'bookmark',
|
accept: 'bookmark',
|
||||||
drop: handleDrop,
|
drop: handleDrop,
|
||||||
hover(item: DragItem) {
|
hover(item: DragItem) {
|
||||||
if (!ref.current || item.index === position) {return;}
|
if (!ref.current || item.index === position) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
moveRow(item.index, position);
|
moveRow(item.index, position);
|
||||||
item.index = position;
|
item.index = position;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,7 @@ export default function ActionsAuth({ disableOAuth }: { disableOAuth?: boolean }
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="border-token-border-medium flex rounded-lg border text-sm hover:cursor-pointer">
|
<div className="border-token-border-medium flex rounded-lg border text-sm hover:cursor-pointer">
|
||||||
<div className="h-9 grow px-3 py-2">
|
<div className="h-9 grow px-3 py-2">{localize(getAuthLocalizationKey(type))}</div>
|
||||||
{localize(getAuthLocalizationKey(type))}
|
|
||||||
</div>
|
|
||||||
<div className="bg-token-border-medium w-px"></div>
|
<div className="bg-token-border-medium w-px"></div>
|
||||||
<button type="button" color="neutral" className="flex items-center gap-2 px-3">
|
<button type="button" color="neutral" className="flex items-center gap-2 px-3">
|
||||||
<svg
|
<svg
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export default function Code({ version }: { version: number | string }) {
|
||||||
{...field}
|
{...field}
|
||||||
checked={field.value}
|
checked={field.value}
|
||||||
onCheckedChange={field.onChange}
|
onCheckedChange={field.onChange}
|
||||||
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
|
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
|
||||||
value={field.value.toString()}
|
value={field.value.toString()}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export default function ImageVision() {
|
||||||
{...field}
|
{...field}
|
||||||
checked={field.value}
|
checked={field.value}
|
||||||
onCheckedChange={field.onChange}
|
onCheckedChange={field.onChange}
|
||||||
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
|
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
|
||||||
value={field.value.toString()}
|
value={field.value.toString()}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ function DynamicCheckbox({
|
||||||
htmlFor={`${settingKey}-dynamic-checkbox`}
|
htmlFor={`${settingKey}-dynamic-checkbox`}
|
||||||
className="text-left text-sm font-medium"
|
className="text-left text-sm font-medium"
|
||||||
>
|
>
|
||||||
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
|
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}{' '}
|
||||||
{showDefault && (
|
{showDefault && (
|
||||||
<small className="opacity-40">
|
<small className="opacity-40">
|
||||||
({localize('com_endpoint_default')}:{' '}
|
({localize('com_endpoint_default')}:{' '}
|
||||||
|
|
@ -81,7 +81,11 @@ function DynamicCheckbox({
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
{description && (
|
{description && (
|
||||||
<OptionHover
|
<OptionHover
|
||||||
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
|
description={
|
||||||
|
descriptionCode
|
||||||
|
? (localize(description as TranslationKeys) ?? description)
|
||||||
|
: description
|
||||||
|
}
|
||||||
side={ESide.Left}
|
side={ESide.Left}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ function DynamicCombobox({
|
||||||
htmlFor={`${settingKey}-dynamic-combobox`}
|
htmlFor={`${settingKey}-dynamic-combobox`}
|
||||||
className="text-left text-sm font-medium"
|
className="text-left text-sm font-medium"
|
||||||
>
|
>
|
||||||
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}
|
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}
|
||||||
{showDefault && (
|
{showDefault && (
|
||||||
<small className="opacity-40">
|
<small className="opacity-40">
|
||||||
({localize('com_endpoint_default')}: {defaultValue})
|
({localize('com_endpoint_default')}: {defaultValue})
|
||||||
|
|
@ -97,10 +97,14 @@ function DynamicCombobox({
|
||||||
<ControlCombobox
|
<ControlCombobox
|
||||||
displayValue={selectedValue}
|
displayValue={selectedValue}
|
||||||
selectPlaceholder={
|
selectPlaceholder={
|
||||||
selectPlaceholderCode === true ? localize(selectPlaceholder as TranslationKeys) : selectPlaceholder
|
selectPlaceholderCode === true
|
||||||
|
? localize(selectPlaceholder as TranslationKeys)
|
||||||
|
: selectPlaceholder
|
||||||
}
|
}
|
||||||
searchPlaceholder={
|
searchPlaceholder={
|
||||||
searchPlaceholderCode === true ? localize(searchPlaceholder as TranslationKeys) : searchPlaceholder
|
searchPlaceholderCode === true
|
||||||
|
? localize(searchPlaceholder as TranslationKeys)
|
||||||
|
: searchPlaceholder
|
||||||
}
|
}
|
||||||
isCollapsed={isCollapsed}
|
isCollapsed={isCollapsed}
|
||||||
ariaLabel={settingKey}
|
ariaLabel={settingKey}
|
||||||
|
|
@ -112,7 +116,11 @@ function DynamicCombobox({
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
{description && (
|
{description && (
|
||||||
<OptionHover
|
<OptionHover
|
||||||
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
|
description={
|
||||||
|
descriptionCode
|
||||||
|
? (localize(description as TranslationKeys) ?? description)
|
||||||
|
: description
|
||||||
|
}
|
||||||
side={ESide.Left}
|
side={ESide.Left}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue