From b5a4ed0b006186756870d93da8c9f6743b53f20c Mon Sep 17 00:00:00 2001 From: bedanley Date: Wed, 22 Jan 2025 09:21:10 -0700 Subject: [PATCH 1/5] Create npm-publish-github-packages.yml --- .../workflows/npm-publish-github-packages.yml | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/npm-publish-github-packages.yml diff --git a/.github/workflows/npm-publish-github-packages.yml b/.github/workflows/npm-publish-github-packages.yml new file mode 100644 index 00000000..77048596 --- /dev/null +++ b/.github/workflows/npm-publish-github-packages.yml @@ -0,0 +1,44 @@ +name: Publish LISA NPM GitHub Package +on: + release: + types: [released] + +permissions: + contents: read + packages: write + +jobs: + PublishLISA: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + # Setup .npmrc file to publish to GitHub Packages + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://npm.pkg.github.com' + - run: npm ci + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + SendSlackNotification: + name: Send Slack Notification + needs: [ PublishLISA ] + runs-on: ubuntu-latest + if: always() + steps: + - name: Send Notification that package has published + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{ secrets.INTERNAL_DEV_SLACK_WEBHOOK_URL }} + SLACK_COLOR: ${{ contains(join(needs.*.result, ' '), 'failure') && 'failure' || 'success' }} + SLACK_TITLE: 'NPM Package Published' + SLACK_FOOTER: '' + MSG_MINIMAL: 'actions url,commit' + SLACK_MESSAGE_ON_FAILURE: ' NPM Package publish FAILED for version ${{ github.event.pull_request.head.ref }}|commit>' + SLACK_MESSAGE_ON_SUCCESS: 'NPM Package published SUCCESS for ${{ github.event.pull_request.head.ref }}|commit>.' + SLACK_MESSAGE: 'NPM Publish Finished with status ${{ job.status }} for <${{ github.event.pull_request.head.ref }}|commit>' From 7882a424c9c88b65c26af647945d5e8abaf3e622 Mon Sep 17 00:00:00 2001 From: Bear Danley Date: Wed, 22 Jan 2025 17:30:15 +0000 Subject: [PATCH 2/5] Remove npm action --- .../workflows/npm-publish-github-packages.yml | 44 ------------------- 1 file changed, 44 deletions(-) delete mode 100644 .github/workflows/npm-publish-github-packages.yml diff --git a/.github/workflows/npm-publish-github-packages.yml b/.github/workflows/npm-publish-github-packages.yml deleted file mode 100644 index 77048596..00000000 --- a/.github/workflows/npm-publish-github-packages.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Publish LISA NPM GitHub Package -on: - release: - types: [released] - -permissions: - contents: read - packages: write - -jobs: - PublishLISA: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - uses: actions/checkout@v4 - # Setup .npmrc file to publish to GitHub Packages - - uses: actions/setup-node@v4 - with: - node-version: '20.x' - registry-url: 'https://npm.pkg.github.com' - - run: npm ci - - run: npm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - SendSlackNotification: - name: Send Slack Notification - needs: [ PublishLISA ] - runs-on: ubuntu-latest - if: always() - steps: - - name: Send Notification that package has published - uses: rtCamp/action-slack-notify@v2 - env: - SLACK_WEBHOOK: ${{ secrets.INTERNAL_DEV_SLACK_WEBHOOK_URL }} - SLACK_COLOR: ${{ contains(join(needs.*.result, ' '), 'failure') && 'failure' || 'success' }} - SLACK_TITLE: 'NPM Package Published' - SLACK_FOOTER: '' - MSG_MINIMAL: 'actions url,commit' - SLACK_MESSAGE_ON_FAILURE: ' NPM Package publish FAILED for version ${{ github.event.pull_request.head.ref }}|commit>' - SLACK_MESSAGE_ON_SUCCESS: 'NPM Package published SUCCESS for ${{ github.event.pull_request.head.ref }}|commit>.' - SLACK_MESSAGE: 'NPM Publish Finished with status ${{ job.status }} for <${{ github.event.pull_request.head.ref }}|commit>' From b605e8bd9b9c9f2901cbc9cfda79ed75f28508af Mon Sep 17 00:00:00 2001 From: github_actions_lisa Date: Thu, 30 Jan 2025 22:03:16 +0000 Subject: [PATCH 3/5] Updating version for hotfix v3.5.1 --- VERSION | 2 +- lib/user-interface/react/package.json | 2 +- lisa-sdk/pyproject.toml | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 1545d966..d5c0c991 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.5.0 +3.5.1 diff --git a/lib/user-interface/react/package.json b/lib/user-interface/react/package.json index 1a936588..8255e0b5 100644 --- a/lib/user-interface/react/package.json +++ b/lib/user-interface/react/package.json @@ -1,7 +1,7 @@ { "name": "lisa-web", "private": true, - "version": "3.5.0", + "version": "3.5.1", "type": "module", "scripts": { "dev": "vite", diff --git a/lisa-sdk/pyproject.toml b/lisa-sdk/pyproject.toml index d24cadac..92c40a76 100644 --- a/lisa-sdk/pyproject.toml +++ b/lisa-sdk/pyproject.toml @@ -3,7 +3,7 @@ requires-python = ">=3.11" [tool.poetry] name = "lisapy" -version = "3.5.0" +version = "3.5.1" description = "A simple SDK to help you interact with LISA. LISA is an LLM hosting solution for AWS dedicated clouds or ADCs." authors = ["Steve Goley "] readme = "README.md" diff --git a/package.json b/package.json index 8ba15b17..0efb1cb6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lisa", - "version": "3.5.0", + "version": "3.5.1", "bin": { "lisa": "bin/lisa.js" }, From 68b51864f6d2ff42c36f442aa4376926d18e2ac3 Mon Sep 17 00:00:00 2001 From: Bear Danley Date: Thu, 30 Jan 2025 15:05:47 -0700 Subject: [PATCH 4/5] Fix prompt errors --- .../react/src/components/chatbot/Chat.tsx | 39 +++-- .../chatbot/DocumentSummarizationModal.tsx | 16 +- .../src/components/chatbot/RagOptions.tsx | 2 + .../chatbot/SessionConfiguration.tsx | 150 +++++++++++++----- .../react/src/components/chatbot/Sessions.tsx | 64 +++++--- .../react/src/shared/util/chat-memory.ts | 44 +++++ 6 files changed, 225 insertions(+), 90 deletions(-) create mode 100644 lib/user-interface/react/src/shared/util/chat-memory.ts diff --git a/lib/user-interface/react/src/components/chatbot/Chat.tsx b/lib/user-interface/react/src/components/chatbot/Chat.tsx index a0eb1d71..2671279d 100644 --- a/lib/user-interface/react/src/components/chatbot/Chat.tsx +++ b/lib/user-interface/react/src/components/chatbot/Chat.tsx @@ -14,24 +14,30 @@ limitations under the License. */ -import { useState, useRef, useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useAuth } from 'react-oidc-context'; import Form from '@cloudscape-design/components/form'; import Container from '@cloudscape-design/components/container'; import Box from '@cloudscape-design/components/box'; import { v4 as uuidv4 } from 'uuid'; import SpaceBetween from '@cloudscape-design/components/space-between'; -import { Grid, TextContent, PromptInput, Autosuggest, ButtonGroup } from '@cloudscape-design/components'; +import { + Autosuggest, + ButtonGroup, + ButtonGroupProps, + Grid, + PromptInput, + TextContent, +} from '@cloudscape-design/components'; import StatusIndicator from '@cloudscape-design/components/status-indicator'; import Message from './Message'; -import { LisaChatMessage, LisaChatSession, LisaChatMessageMetadata } from '../types'; -import { RESTAPI_URI, formatDocumentsAsString, RESTAPI_VERSION } from '../utils'; +import { LisaChatMessage, LisaChatMessageMetadata, LisaChatSession } from '../types'; +import { formatDocumentsAsString, RESTAPI_URI, RESTAPI_VERSION } from '../utils'; import { LisaChatMessageHistory } from '../adapters/lisa-chat-history'; import { ChatPromptTemplate, MessagesPlaceholder, PromptTemplate } from '@langchain/core/prompts'; import { RunnableSequence } from '@langchain/core/runnables'; import { StringOutputParser } from '@langchain/core/output_parsers'; -import { BufferWindowMemory } from 'langchain/memory'; import RagControls, { RagConfig } from './RagOptions'; import { ContextUploadModal, RagUploadModal } from './FileUploadModals'; import { ChatOpenAI } from '@langchain/openai'; @@ -41,7 +47,7 @@ import { useLazyGetConfigurationQuery } from '../../shared/reducers/configuratio import { useGetSessionHealthQuery, useLazyGetSessionByIdQuery, - useUpdateSessionMutation + useUpdateSessionMutation, } from '../../shared/reducers/session.reducer'; import { useAppDispatch } from '../../config/store'; import { useNotificationService } from '../../shared/util/hooks'; @@ -51,6 +57,7 @@ import { baseConfig, GenerateLLMRequestParams, IChatConfiguration } from '../../ import { useLazyGetRelevantDocumentsQuery } from '../../shared/reducers/rag.reducer'; import { IConfiguration } from '../../shared/model/configuration.model'; import { DocumentSummarizationModal } from './DocumentSummarizationModal'; +import { ChatMemory } from '../../shared/util/chat-memory'; export default function Chat ({ sessionId }) { const dispatch = useAppDispatch(); @@ -94,7 +101,7 @@ export default function Chat ({ sessionId }) { const [useRag, setUseRag] = useState(false); const [ragConfig, setRagConfig] = useState({} as RagConfig); const [memory, setMemory] = useState( - new BufferWindowMemory({ + new ChatMemory({ chatHistory: new LisaChatMessageHistory(session), returnMessages: false, memoryKey: 'history', @@ -161,8 +168,7 @@ export default function Chat ({ sessionId }) { context: async (input: { input: string; chatHistory?: LisaChatMessage[] }) => { const question = await getContextualizedQuestion(input); const relevantDocs = await fetchRelevantDocuments(question); - const serialized = await updateSessionWithRagContext(relevantDocs); - return serialized; + return await updateSessionWithRagContext(relevantDocs); }, }; @@ -376,7 +382,7 @@ export default function Chat ({ sessionId }) { useEffect(() => { setMemory( - new BufferWindowMemory({ + new ChatMemory({ chatHistory: new LisaChatMessageHistory(session), returnMessages: false, memoryKey: 'history', @@ -543,9 +549,9 @@ export default function Chat ({ sessionId }) {
-
+
e.preventDefault()}> - + No models available.
} filteringType='auto' value={selectedModel?.modelId ?? ''} + enteredTextLabel={(text) => `Use: "${text}"`} onChange={({ detail: { value } }) => { if (!value || value.length === 0) { setSelectedModel(undefined); @@ -635,20 +642,20 @@ export default function Chat ({ sessionId }) { id: 'upload-to-rag', iconName: 'upload', text: 'Upload to RAG' - }] : []), + }] as ButtonGroupProps.Item[] : []), ...(config?.configuration.enabledComponents.uploadContextDocs ? [{ type: 'icon-button', id: 'add-file-to-context', iconName: 'insert-row', text: 'Add file to context' - }] : []), + }] as ButtonGroupProps.Item[] : []), ...(config?.configuration.enabledComponents.documentSummarization ? [{ type: 'icon-button', id: 'summarize-document', iconName: 'transcript', text: 'Summarize Document' - }] : []), + }] as ButtonGroupProps.Item[] : []), ...(config?.configuration.enabledComponents.editPromptTemplate ? [{ type: 'menu-dropdown', @@ -661,7 +668,7 @@ export default function Chat ({ sessionId }) { text: 'Edit Prompt Template' }, ] - }] : []) + }] as ButtonGroupProps.Item[] : []) ]} variant='icon' /> diff --git a/lib/user-interface/react/src/components/chatbot/DocumentSummarizationModal.tsx b/lib/user-interface/react/src/components/chatbot/DocumentSummarizationModal.tsx index fdf1b8a9..77817f00 100644 --- a/lib/user-interface/react/src/components/chatbot/DocumentSummarizationModal.tsx +++ b/lib/user-interface/react/src/components/chatbot/DocumentSummarizationModal.tsx @@ -15,12 +15,14 @@ */ import { - Modal, + Autosuggest, Box, - SpaceBetween, Button, + FileUpload, + Modal, + SpaceBetween, + Textarea, TextContent, - FileUpload, Autosuggest, Textarea, } from '@cloudscape-design/components'; import { FileTypes, LisaChatSession } from '../types'; import { useEffect, useMemo, useState } from 'react'; @@ -32,9 +34,9 @@ import { handleUpload } from './FileUploadModals'; import { IChatConfiguration } from '../../shared/model/chat.configurations.model'; import { v4 as uuidv4 } from 'uuid'; import FormField from '@cloudscape-design/components/form-field'; -import { BufferWindowMemory } from 'langchain/memory'; import { LisaChatMessageHistory } from '../adapters/lisa-chat-history'; import Toggle from '@cloudscape-design/components/toggle'; +import { ChatMemory } from '../../shared/util/chat-memory'; export type DocumentSummarizationModalProps = { showDocumentSummarizationModal: boolean; @@ -51,7 +53,7 @@ export type DocumentSummarizationModalProps = { setSession: (state: LisaChatSession) => void; userName: string; handleSendGenerateRequest: () => void; - setMemory: (state: BufferWindowMemory) => void; + setMemory: (state: ChatMemory) => void; }; export function DocumentSummarizationModal ({ @@ -163,7 +165,7 @@ export function DocumentSummarizationModal ({ }; setSession(newSession); - setMemory(new BufferWindowMemory({ + setMemory(new ChatMemory({ chatHistory: new LisaChatMessageHistory(newSession), returnMessages: false, memoryKey: 'history', @@ -220,6 +222,7 @@ export function DocumentSummarizationModal ({ empty={
No models available.
} filteringType='auto' value={selectedModel?.modelId ?? ''} + enteredTextLabel={(text) => `Use: "${text}"`} onChange={({ detail: { value } }) => { if (!value || value.length === 0) { setSelectedModel(undefined); @@ -243,6 +246,7 @@ export function DocumentSummarizationModal ({ placeholder='Select prompt type' filteringType='auto' value={selectedPromptType} + enteredTextLabel={(text) => `Use: "${text}"`} onChange={({ detail: { value } }) => { setUserPrompt(''); if (value && value.length !== 0) { diff --git a/lib/user-interface/react/src/components/chatbot/RagOptions.tsx b/lib/user-interface/react/src/components/chatbot/RagOptions.tsx index 64091462..abeda38e 100644 --- a/lib/user-interface/react/src/components/chatbot/RagOptions.tsx +++ b/lib/user-interface/react/src/components/chatbot/RagOptions.tsx @@ -67,6 +67,7 @@ export default function RagControls ({isRunning, setUseRag, setRagConfig }: RagC empty={
No repositories available.
} filteringType='auto' value={selectedRepositoryOption ?? ''} + enteredTextLabel={(text) => `Use: "${text}"`} onChange={({ detail }) => { setSelectedRepositoryOption(detail.value); setRagConfig((config) => ({ @@ -85,6 +86,7 @@ export default function RagControls ({isRunning, setUseRag, setRagConfig }: RagC empty={
No embedding models available.
} filteringType='auto' value={selectedEmbeddingOption ?? ''} + enteredTextLabel={(text) => `Use: "${text}"`} onChange={({ detail }) => { setSelectedEmbeddingOption(detail.value); diff --git a/lib/user-interface/react/src/components/chatbot/SessionConfiguration.tsx b/lib/user-interface/react/src/components/chatbot/SessionConfiguration.tsx index 27f30a5d..1ba36211 100644 --- a/lib/user-interface/react/src/components/chatbot/SessionConfiguration.tsx +++ b/lib/user-interface/react/src/components/chatbot/SessionConfiguration.tsx @@ -15,9 +15,16 @@ */ import { + AttributeEditor, + Box, + Container, + FormField, + Grid, + Header, + Input, Modal, + Select, SpaceBetween, - Header, FormField, Input, Container, AttributeEditor, Grid, Select, Box, } from '@cloudscape-design/components'; import Toggle from '@cloudscape-design/components/toggle'; @@ -35,12 +42,23 @@ export type SessionConfigurationProps = { systemConfig: IConfiguration; }; -export default function SessionConfiguration ({ chatConfiguration, setChatConfiguration, selectedModel, isRunning, visible, setVisible, systemConfig } : SessionConfigurationProps) { +export default function SessionConfiguration ({ + chatConfiguration, + setChatConfiguration, + selectedModel, + isRunning, + visible, + setVisible, + systemConfig, +}: SessionConfigurationProps) { // Defaults based on https://huggingface.co/docs/transformers/main_classes/text_generation#transformers.GenerationConfig // Default stop sequences based on User/Assistant instruction prompting for Falcon, Mistral, etc. - const updateSessionConfiguration = (property: string, value: any): void => { - setChatConfiguration({ ...chatConfiguration, sessionConfiguration: { ...chatConfiguration.sessionConfiguration, [property]: value } }); + const updateSessionConfiguration = (property: string, value: any): void => { + setChatConfiguration({ + ...chatConfiguration, + sessionConfiguration: { ...chatConfiguration.sessionConfiguration, [property]: value }, + }); }; const oneThroughTenOptions = [...Array(10).keys()].map((i) => { @@ -60,7 +78,7 @@ export default function SessionConfiguration ({ chatConfiguration, setChatConfig size='large' > - + updateSessionConfiguration('streaming', detail.checked)} checked={chatConfiguration.sessionConfiguration.streaming} @@ -68,17 +86,18 @@ export default function SessionConfiguration ({ chatConfiguration, setChatConfig > Stream Responses - { systemConfig && systemConfig.configuration.enabledComponents.viewMetaData && - updateSessionConfiguration('showMetadata', detail.checked)} - checked={chatConfiguration.sessionConfiguration.showMetadata} - disabled={isRunning} - > - Show Message Metadata - } - { systemConfig && systemConfig.configuration.enabledComponents.editChatHistoryBuffer && + {systemConfig && systemConfig.configuration.enabledComponents.viewMetaData && + updateSessionConfiguration('showMetadata', detail.checked)} + checked={chatConfiguration.sessionConfiguration.showMetadata} + disabled={isRunning} + > + Show Message Metadata + } + {systemConfig && systemConfig.configuration.enabledComponents.editChatHistoryBuffer && - + } - { systemConfig && systemConfig.configuration.enabledComponents.editKwargs && + {systemConfig && systemConfig.configuration.enabledComponents.editKwargs && { const intVal = parseInt(event.detail.value); if (!isNaN(intVal) && intVal >= 0) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, n: intVal}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + n: intVal, + }); } else if (isNaN(intVal)) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, n: null}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + n: null, + }); } }} /> @@ -179,9 +205,15 @@ export default function SessionConfiguration ({ chatConfiguration, setChatConfig onChange={(event) => { const floatVal = parseFloat(event.detail.value); if (!isNaN(floatVal) && floatVal >= 0.0 && floatVal <= 1.0) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, top_p: floatVal}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + top_p: floatVal, + }); } else if (isNaN(floatVal)) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, top_p: null}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + top_p: null, + }); } }} /> @@ -203,9 +235,15 @@ export default function SessionConfiguration ({ chatConfiguration, setChatConfig onChange={(event) => { const floatVal = parseFloat(event.detail.value); if (!isNaN(floatVal) && floatVal >= -2.0 && floatVal <= 2.0) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, frequency_penalty: floatVal}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + frequency_penalty: floatVal, + }); } else if (isNaN(floatVal)) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, frequency_penalty: null}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + frequency_penalty: null, + }); } }} /> @@ -227,9 +265,15 @@ export default function SessionConfiguration ({ chatConfiguration, setChatConfig onChange={(event) => { const floatVal = parseFloat(event.detail.value); if (!isNaN(floatVal) && floatVal >= -2.0 && floatVal <= 2.0) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, presence_penalty: floatVal}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + presence_penalty: floatVal, + }); } else if (isNaN(floatVal)) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, presence_penalty: null}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + presence_penalty: null, + }); } }} /> @@ -251,21 +295,34 @@ export default function SessionConfiguration ({ chatConfiguration, setChatConfig onChange={(event) => { const floatVal = parseFloat(event.detail.value); if (!isNaN(floatVal) && floatVal >= 0.0 && floatVal <= 2.0) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, temperature: floatVal}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + temperature: floatVal, + }); } else if (isNaN(floatVal)) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, temperature: null}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + temperature: null, + }); } }} /> - + updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, stop: chatConfiguration.sessionConfiguration.modelArgs.stop.concat('')})} + onAddButtonClick={() => updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + stop: chatConfiguration.sessionConfiguration.modelArgs.stop.concat(''), + })} removeButtonText='Remove' onRemoveButtonClick={(event) => - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, stop: chatConfiguration.sessionConfiguration.modelArgs.stop.filter((elem, i) => event.detail.itemIndex !== i)}) + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + stop: chatConfiguration.sessionConfiguration.modelArgs.stop.filter((elem, i) => event.detail.itemIndex !== i), + }) } isItemRemovable={() => true} items={chatConfiguration.sessionConfiguration.modelArgs.stop} @@ -277,15 +334,18 @@ export default function SessionConfiguration ({ chatConfiguration, setChatConfig value={item} placeholder='null' onChange={(event) => { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, stop: - chatConfiguration.sessionConfiguration.modelArgs.stop.slice(0, 4).map((elem, j) => { - if (i === j) { - return event.detail.value; - } else { - return elem; - } - })}, - ); + updateSessionConfiguration('modelArgs', + { + ...chatConfiguration.sessionConfiguration.modelArgs, + stop: chatConfiguration.sessionConfiguration.modelArgs.stop.slice(0, 4) + .map((elem, j) => { + if (i === j) { + return event.detail.value; + } else { + return elem; + } + }), + }); }} /> ); @@ -312,9 +372,15 @@ export default function SessionConfiguration ({ chatConfiguration, setChatConfig onChange={(event) => { const intVal = parseInt(event.detail.value); if (!isNaN(intVal) && intVal >= 0) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, seed: intVal}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + seed: intVal, + }); } else if (isNaN(intVal)) { - updateSessionConfiguration('modelArgs', {...chatConfiguration.sessionConfiguration.modelArgs, seed: null}); + updateSessionConfiguration('modelArgs', { + ...chatConfiguration.sessionConfiguration.modelArgs, + seed: null, + }); } }} /> diff --git a/lib/user-interface/react/src/components/chatbot/Sessions.tsx b/lib/user-interface/react/src/components/chatbot/Sessions.tsx index 6876acf6..5a8311cd 100644 --- a/lib/user-interface/react/src/components/chatbot/Sessions.tsx +++ b/lib/user-interface/react/src/components/chatbot/Sessions.tsx @@ -36,19 +36,30 @@ import { useNotificationService } from '../../shared/util/hooks'; import { useEffect, useState } from 'react'; import { useAuth } from 'react-oidc-context'; import { IConfiguration } from '../../shared/model/configuration.model'; +import { useNavigate } from 'react-router-dom'; export function Sessions () { const dispatch = useAppDispatch(); const notificationService = useNotificationService(dispatch); const auth = useAuth(); + const navigate = useNavigate(); - const [selectedItems, setSelectedItems] = useState([]); - const [deleteById, { isSuccess: isDeleteByIdSuccess, isError: isDeleteByIdError, error: deleteByIdError, isLoading: isDeleteByIdLoading },] = useDeleteSessionByIdMutation(); - const [deleteUserSessions, { isSuccess: isDeleteUserSessionsSuccess, isError: isDeleteUserSessionsError, error: deleteUserSessionsError, isLoading: isDeleteUserSessionsLoading },] = useDeleteAllSessionsForUserMutation(); + const [deleteById, { + isSuccess: isDeleteByIdSuccess, + isError: isDeleteByIdError, + error: deleteByIdError, + isLoading: isDeleteByIdLoading, + }] = useDeleteSessionByIdMutation(); + const [deleteUserSessions, { + isSuccess: isDeleteUserSessionsSuccess, + isError: isDeleteUserSessionsError, + error: deleteUserSessionsError, + isLoading: isDeleteUserSessionsLoading, + }] = useDeleteAllSessionsForUserMutation(); const [getConfiguration] = useLazyGetConfigurationQuery(); const [config, setConfig] = useState(); - const { data: sessions, isLoading } = useListSessionsQuery(null, {refetchOnMountOrArgChange: 5}); - const { items, collectionProps, paginationProps } = useCollection(sessions ?? [], { + const { data: sessions, isLoading } = useListSessionsQuery(null, { refetchOnMountOrArgChange: 5 }); + const { items, actions, collectionProps, paginationProps } = useCollection(sessions ?? [], { filtering: { empty: ( @@ -67,7 +78,7 @@ export function Sessions () { isDescending: true, }, }, - selection: {}, + selection: { trackBy: 'sessionId' }, }); useEffect(() => { @@ -107,9 +118,9 @@ export function Sessions () { pagination={} loadingText='Loading history' loading={isLoading || isDeleteByIdLoading || isDeleteUserSessionsLoading} - selectedItems={selectedItems} + selectedItems={collectionProps.selectedItems} onSelectionChange={({ detail }) => - setSelectedItems(detail.selectedItems) + actions.setSelectedItems(detail.selectedItems) } resizableColumns sortingDescending={true} @@ -118,7 +129,8 @@ export function Sessions () { { id: 'title', header: 'Title', - cell: (e) => {e.history[0].content || 'No Content'}, + cell: (e) => navigate(`chatbot/${e.sessionId}`)}>{e.history[0].content || 'No Content'}, sortingField: 'title', isRowHeader: true, }, @@ -138,7 +150,7 @@ export function Sessions () {
} + }
} diff --git a/lib/user-interface/react/src/shared/util/chat-memory.ts b/lib/user-interface/react/src/shared/util/chat-memory.ts new file mode 100644 index 00000000..c185a522 --- /dev/null +++ b/lib/user-interface/react/src/shared/util/chat-memory.ts @@ -0,0 +1,44 @@ +/** + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import { BufferWindowMemory, getBufferString } from 'langchain/memory'; +import { LisaChatMessage } from '../../components/types'; +import { BaseMessage } from '@langchain/core/messages'; +import { MemoryVariables } from '@langchain/core/memory'; + +/** + * Class for managing and storing previous chat messages. This extends BufferWindowMemory to add a transform to ensure + * json messages are converted into LISA Chat messages. + */ +export class ChatMemory extends BufferWindowMemory { + + /** + * Override loadMemoryVariables to add type conversion of LisaChatMessage + */ + async loadMemoryVariables (): Promise { + const messages: BaseMessage[] = await this.chatHistory.getMessages(); + const lisaMessages = messages.map((message) => new LisaChatMessage({ ...message, type: message['type'] })); + if (this.returnMessages) { + return { + [this.memoryKey]: lisaMessages.slice(-this.k * 2), + }; + } + + return { + [this.memoryKey]: getBufferString(lisaMessages.slice(-this.k * 2), this.humanPrefix, this.aiPrefix), + }; + } +} From abfb7cb7f2155cbfbf39a4b22de144e5ef080a6a Mon Sep 17 00:00:00 2001 From: Bear Danley Date: Fri, 31 Jan 2025 10:47:43 -0700 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 18 ++++++++++++++++++ .../react/src/components/chatbot/Chat.tsx | 6 +++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80b7e848..c1a6f886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# v3.5.1 + +## Bug Fixes + +### Chat Session Management + +- Resolved url redirect issue that prevented creation of new chat sessions via the New button +- Resolved intermittent loading issues when accessing historical conversations due to LangChain memory object +- Addressed error handling for LLM interactions after multiple prompts + +### Document Summarization + +- Fixed stability issues with document summarization functionality in existing chat sessions + +### UI + +-Corrected display scaling issues in Firefox for large screen resolutions + # v3.5.0 ## Key Features ### User Interface Modernization diff --git a/lib/user-interface/react/src/components/chatbot/Chat.tsx b/lib/user-interface/react/src/components/chatbot/Chat.tsx index 2671279d..55c2c1c2 100644 --- a/lib/user-interface/react/src/components/chatbot/Chat.tsx +++ b/lib/user-interface/react/src/components/chatbot/Chat.tsx @@ -164,7 +164,7 @@ export default function Chat ({ sessionId }) { const handleRagConfiguration = async (chainSteps: any[]) => { const ragStep = { input: ({ input }: { input: string }) => input, - chatHistory: () => memory.loadMemoryVariables({}), + chatHistory: () => memory.loadMemoryVariables(), context: async (input: { input: string; chatHistory?: LisaChatMessage[] }) => { const question = await getContextualizedQuestion(input); const relevantDocs = await fetchRelevantDocuments(question); @@ -224,7 +224,7 @@ export default function Chat ({ sessionId }) { const handleNonRagConfiguration = (chainSteps: any[]) => { const nonRagStep = { input: (initialInput: any) => initialInput.input, - memory: () => memory.loadMemoryVariables({}), + memory: () => memory.loadMemoryVariables(), context: () => fileContext || '', humanPrefix: (initialInput: any) => initialInput.humanPrefix, aiPrefix: (initialInput: any) => initialInput.aiPrefix, @@ -396,7 +396,7 @@ export default function Chat ({ sessionId }) { useEffect(() => { if (selectedModel && auth.isAuthenticated) { - memory.loadMemoryVariables({}).then(async (formattedHistory) => { + memory.loadMemoryVariables().then(async (formattedHistory) => { const promptValues = { input: userPrompt, history: formattedHistory.history,