mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
feat(ChatAgent.js): add support for skipping completion mode in ChatAgent
feat(ChatAgent.js): add a check for images when completion is skipped to add to response feat(askGPTPlugins.js): add skipCompletion option to agentOptions feat(client): add Switch component to ui components and use for new Agent Settings chore(package.json): ignore client directory in nodemonConfig
This commit is contained in:
parent
5b1efc48d1
commit
d0be2e6f4a
13 changed files with 150 additions and 32 deletions
|
|
@ -6,7 +6,7 @@ const {
|
|||
} = require('@dqbd/tiktoken');
|
||||
const { fetchEventSource } = require('@waylaidwanderer/fetch-event-source');
|
||||
const { Agent, ProxyAgent } = require('undici');
|
||||
// const TextStream = require('../stream');
|
||||
const TextStream = require('../stream');
|
||||
const { ChatOpenAI } = require('langchain/chat_models/openai');
|
||||
const { CallbackManager } = require('langchain/callbacks');
|
||||
const { HumanChatMessage, AIChatMessage } = require('langchain/schema');
|
||||
|
|
@ -687,13 +687,14 @@ Only respond with your conversational reply to the following User Message:
|
|||
return { ...responseMessage, ...this.result };
|
||||
}
|
||||
|
||||
// if (!this.agentIsGpt3 && this.result.output) {
|
||||
// responseMessage.text = this.result.output;
|
||||
// await this.saveMessageToDatabase(responseMessage, user);
|
||||
// const textStream = new TextStream(this.result.output);
|
||||
// await textStream.processTextStream(opts.onProgress);
|
||||
// return { ...responseMessage, ...this.result };
|
||||
// }
|
||||
if (!completionMode && this.agentOptions.skipCompletion && this.result.output) {
|
||||
responseMessage.text = this.result.output;
|
||||
this.addImages(this.result.intermediateSteps, responseMessage);
|
||||
await this.saveMessageToDatabase(responseMessage, user);
|
||||
const textStream = new TextStream(this.result.output);
|
||||
await textStream.processTextStream(opts.onProgress);
|
||||
return { ...responseMessage, ...this.result };
|
||||
}
|
||||
|
||||
if (this.options.debug) {
|
||||
console.debug('this.result', this.result);
|
||||
|
|
@ -714,6 +715,26 @@ Only respond with your conversational reply to the following User Message:
|
|||
return { ...responseMessage, ...this.result };
|
||||
}
|
||||
|
||||
addImages(intermediateSteps, responseMessage) {
|
||||
if (!intermediateSteps || !responseMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
intermediateSteps.forEach(step => {
|
||||
const { observation } = step;
|
||||
if (!observation || !observation.includes('![')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!responseMessage.text.includes(observation)) {
|
||||
responseMessage.text += '\n' + observation;
|
||||
if (this.options.debug) {
|
||||
console.debug('added image from intermediateSteps');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async buildPrompt({ messages, promptPrefix: _promptPrefix, completionMode = false, isChatGptModel = true }) {
|
||||
if (this.options.debug) {
|
||||
console.debug('buildPrompt messages', messages);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ router.post('/', requireJwtAuth, async (req, res) => {
|
|||
|
||||
const agentOptions = req.body?.agentOptions ?? {
|
||||
agent: 'classic',
|
||||
skipCompletion: false,
|
||||
model: 'gpt-3.5-turbo',
|
||||
temperature: 0,
|
||||
// top_p: 1,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.0.0",
|
||||
"@radix-ui/react-slider": "^1.1.1",
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tabs": "^1.0.3",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tanstack/react-query": "^4.28.0",
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }) => {
|
|||
{preset?.endpoint === 'gptPlugins' && showAgentSettings && (
|
||||
<AgentSettings
|
||||
agent={preset.agent}
|
||||
skipCompletion={preset.agentOptions.skipCompletion}
|
||||
model={preset.agentOptions.model}
|
||||
endpoint={preset.agentOptions.endpoint}
|
||||
temperature={preset.agentOptions.temperature}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { cn } from '~/utils/';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import {
|
||||
Switch,
|
||||
SelectDropDown,
|
||||
Label,
|
||||
Slider,
|
||||
|
|
@ -21,26 +22,28 @@ function Settings(props) {
|
|||
const {
|
||||
readonly,
|
||||
agent,
|
||||
skipCompletion,
|
||||
model,
|
||||
temperature,
|
||||
// topP,
|
||||
// freqP,
|
||||
// presP,
|
||||
setOption,
|
||||
// tools
|
||||
} = props;
|
||||
const endpoint = 'gptPlugins';
|
||||
|
||||
const endpointsConfig = useRecoilValue(store.endpointsConfig);
|
||||
const setModel = setOption('model');
|
||||
const setTemperature = setOption('temperature');
|
||||
// const setTopP = setOption('top_p');
|
||||
// const setFreqP = setOption('presence_penalty');
|
||||
// const setPresP = setOption('frequency_penalty');
|
||||
const setAgent = setOption('agent');
|
||||
const setSkipCompletion = setOption('skipCompletion');
|
||||
const onCheckedChangeAgent = (checked) => {
|
||||
setAgent(checked ? 'functions' : 'classic');
|
||||
};
|
||||
|
||||
const onCheckedChangeSkip = (checked) => {
|
||||
setSkipCompletion(checked);
|
||||
};
|
||||
|
||||
|
||||
// const toolsSelected = tools?.length > 0;
|
||||
const models = endpointsConfig?.[endpoint]?.['availableModels'] || [];
|
||||
const agents = endpointsConfig?.[endpoint]?.['availableAgents'] || [];
|
||||
|
||||
return (
|
||||
<div className="max-h-[350px] min-h-[305px] overflow-y-auto">
|
||||
|
|
@ -60,19 +63,31 @@ function Settings(props) {
|
|||
containerClassName="flex w-full resize-none"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<SelectDropDown
|
||||
title="Agent Mode"
|
||||
value={agent}
|
||||
setValue={setOption('agent')}
|
||||
availableValues={agents}
|
||||
disabled={readonly}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
'flex w-full resize-none focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0'
|
||||
)}
|
||||
containerClassName="flex w-full resize-none"
|
||||
/>
|
||||
<div className="grid w-full items-center gap-2 grid-cols-2">
|
||||
<HoverCard openDelay={500}>
|
||||
<HoverCardTrigger className='w-1/2'>
|
||||
<label
|
||||
htmlFor="functions-agent"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"
|
||||
>
|
||||
<small>Use Functions</small>
|
||||
</label>
|
||||
<Switch id="functions-agent" checked={agent === 'functions'} onCheckedChange={onCheckedChangeAgent} disabled={readonly} className="mt-2 ml-4"/>
|
||||
</HoverCardTrigger>
|
||||
<OptionHover type="temp" side="right" />
|
||||
</HoverCard>
|
||||
<HoverCard openDelay={500}>
|
||||
<HoverCardTrigger className='w-1/2 ml-[-60px]'>
|
||||
<label
|
||||
htmlFor="skip-completion"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"
|
||||
>
|
||||
<small>Skip Completion</small>
|
||||
</label>
|
||||
<Switch id="skip-completion" checked={skipCompletion === true} onCheckedChange={onCheckedChangeSkip} disabled={readonly} className="mt-2 ml-4"/>
|
||||
</HoverCardTrigger>
|
||||
<OptionHover type="temp" side="right" />
|
||||
</HoverCard>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col items-center justify-start gap-6">
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ function PluginsOptions() {
|
|||
{showAgentSettings ? (
|
||||
<AgentSettings
|
||||
agent={agentOptions.agent}
|
||||
skipCompletion={agentOptions.skipCompletion}
|
||||
model={agentOptions.model}
|
||||
endpoint={agentOptions.endpoint}
|
||||
temperature={agentOptions.temperature}
|
||||
|
|
|
|||
27
client/src/components/ui/Switch.tsx
Normal file
27
client/src/components/ui/Switch.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from '../../utils';
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-green-600 data-[state=unchecked]:bg-gray-200",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-5 w-5 rounded-full bg-white shadow-[0_1px_2px_rgba(0,0,0,0.45)] transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
||||
export { Switch }
|
||||
|
|
@ -11,6 +11,7 @@ export * from './Landing';
|
|||
export * from './ModelSelect';
|
||||
export * from './Prompt';
|
||||
export * from './Slider';
|
||||
export * from './Switch';
|
||||
export * from './Tabs';
|
||||
export * from './Templates';
|
||||
export * from './Textarea';
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ const cleanupPreset = ({ preset: _preset, endpointsConfig = {} }) => {
|
|||
} else if (endpoint === 'gptPlugins') {
|
||||
const agentOptions = _preset?.agentOptions ?? {
|
||||
agent: 'classic',
|
||||
skipCompletion: false,
|
||||
model: 'gpt-3.5-turbo',
|
||||
temperature: 0,
|
||||
// top_p: 1,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ const buildDefaultConversation = ({
|
|||
} else if (endpoint === 'gptPlugins') {
|
||||
const agentOptions = lastConversationSetup?.agentOptions ?? {
|
||||
agent: 'classic',
|
||||
skipCompletion: false,
|
||||
model: 'gpt-3.5-turbo',
|
||||
temperature: 0,
|
||||
// top_p: 1,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ const useMessageHandler = () => {
|
|||
} else if (endpoint === 'gptPlugins') {
|
||||
const agentOptions = currentConversation?.agentOptions ?? {
|
||||
agent: 'classic',
|
||||
skipCompletion: false,
|
||||
model: 'gpt-3.5-turbo',
|
||||
temperature: 0,
|
||||
// top_p: 1,
|
||||
|
|
|
|||
48
package-lock.json
generated
48
package-lock.json
generated
|
|
@ -369,6 +369,7 @@
|
|||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.0.0",
|
||||
"@radix-ui/react-slider": "^1.1.1",
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tabs": "^1.0.3",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tanstack/react-query": "^4.28.0",
|
||||
|
|
@ -6506,6 +6507,35 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-switch": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.0.3.tgz",
|
||||
"integrity": "sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"@radix-ui/primitive": "1.0.1",
|
||||
"@radix-ui/react-compose-refs": "1.0.1",
|
||||
"@radix-ui/react-context": "1.0.1",
|
||||
"@radix-ui/react-primitive": "1.0.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.0.1",
|
||||
"@radix-ui/react-use-previous": "1.0.1",
|
||||
"@radix-ui/react-use-size": "1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tabs": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.4.tgz",
|
||||
|
|
@ -29519,7 +29549,7 @@
|
|||
"jsonwebtoken": "^9.0.0",
|
||||
"keyv": "^4.5.2",
|
||||
"keyv-file": "^0.2.0",
|
||||
"langchain": "0.0.94",
|
||||
"langchain": "^0.0.94",
|
||||
"lodash": "^4.17.21",
|
||||
"meilisearch": "^0.33.0",
|
||||
"mongoose": "^7.1.1",
|
||||
|
|
@ -29614,6 +29644,7 @@
|
|||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.0.0",
|
||||
"@radix-ui/react-slider": "^1.1.1",
|
||||
"@radix-ui/react-switch": "*",
|
||||
"@radix-ui/react-tabs": "^1.0.3",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tanstack/react-query": "^4.28.0",
|
||||
|
|
@ -30152,6 +30183,21 @@
|
|||
"@radix-ui/react-compose-refs": "1.0.1"
|
||||
}
|
||||
},
|
||||
"@radix-ui/react-switch": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.0.3.tgz",
|
||||
"integrity": "sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"@radix-ui/primitive": "1.0.1",
|
||||
"@radix-ui/react-compose-refs": "1.0.1",
|
||||
"@radix-ui/react-context": "1.0.1",
|
||||
"@radix-ui/react-primitive": "1.0.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.0.1",
|
||||
"@radix-ui/react-use-previous": "1.0.1",
|
||||
"@radix-ui/react-use-size": "1.0.1"
|
||||
}
|
||||
},
|
||||
"@radix-ui/react-tabs": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.4.tgz",
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@
|
|||
"nodemonConfig": {
|
||||
"ignore": [
|
||||
"api/data/",
|
||||
"data"
|
||||
"data",
|
||||
"client/"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue