feat: improve copilot (#2758)

This commit is contained in:
Himself65
2023-06-13 10:29:04 +08:00
committed by GitHub
parent 5ba2dff008
commit ace3c37fcc
20 changed files with 413 additions and 79 deletions
+2
View File
@@ -41,6 +41,8 @@ const allPackages = [
'apps/web', 'apps/web',
'apps/server', 'apps/server',
'apps/electron', 'apps/electron',
'plugins/copilot',
'plugins/bookmark-block',
]; ];
/** /**
@@ -1,5 +1,6 @@
import { globalStyle } from '@vanilla-extract/css'; import { style } from '@vanilla-extract/css';
globalStyle('.mosaic.mosaic-blueprint-theme', { export const pluginContainer = style({
backgroundColor: 'var(--background-color)', height: '100%',
width: '100%',
}); });
@@ -34,6 +34,7 @@ import { pageSettingFamily } from '../atoms';
import { contentLayoutAtom } from '../atoms/layout'; import { contentLayoutAtom } from '../atoms/layout';
import type { AffineOfficialWorkspace } from '../shared'; import type { AffineOfficialWorkspace } from '../shared';
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor'; import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
import { pluginContainer } from './page-detail-editor.css';
export type PageDetailEditorProps = { export type PageDetailEditorProps = {
isPublic?: boolean; isPublic?: boolean;
@@ -122,7 +123,7 @@ const PluginContentAdapter = memo<{
detailContent: PluginUIAdapter['detailContent']; detailContent: PluginUIAdapter['detailContent'];
}>(function PluginContentAdapter({ detailContent }) { }>(function PluginContentAdapter({ detailContent }) {
return ( return (
<div> <div className={pluginContainer}>
{detailContent({ {detailContent({
contentLayoutAtom, contentLayoutAtom,
})} })}
@@ -153,7 +154,12 @@ const LayoutPanel = memo(function LayoutPanel(
} }
} else { } else {
return ( return (
<PanelGroup direction={node.direction}> <PanelGroup
style={{
height: 'calc(100% - 52px)',
}}
direction={node.direction}
>
<Panel defaultSize={node.splitPercentage}> <Panel defaultSize={node.splitPercentage}>
<Suspense> <Suspense>
<LayoutPanel <LayoutPanel
+4 -1
View File
@@ -102,5 +102,8 @@
"@types/cacheable-request": "^6.0.2", "@types/cacheable-request": "^6.0.2",
"@types/responselike": "^1.0.0" "@types/responselike": "^1.0.0"
}, },
"packageManager": "yarn@3.6.0" "packageManager": "yarn@3.6.0",
"dependencies": {
"marked-mangle": "^1.0.1"
}
} }
+7 -4
View File
@@ -8,7 +8,11 @@
}, },
"dependencies": { "dependencies": {
"@affine/component": "workspace:*", "@affine/component": "workspace:*",
"@toeverything/plugin-infra": "workspace:*" "@toeverything/plugin-infra": "workspace:*",
"langchain": "^0.0.92",
"marked": "^5.0.4",
"marked-gfm-heading-id": "^3.0.4",
"marked-mangle": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/marked": "^5.0.0", "@types/marked": "^5.0.0",
@@ -16,10 +20,9 @@
"@types/react-dom": "^18.2.4", "@types/react-dom": "^18.2.4",
"idb": "^7.1.1", "idb": "^7.1.1",
"jotai": "^2.1.1", "jotai": "^2.1.1",
"langchain": "^0.0.90",
"marked": "^5.0.4",
"react": "18.3.0-canary-16d053d59-20230506", "react": "18.3.0-canary-16d053d59-20230506",
"react-dom": "18.3.0-canary-16d053d59-20230506" "react-dom": "18.3.0-canary-16d053d59-20230506",
"zod": "^3.21.4"
}, },
"peerDependencies": { "peerDependencies": {
"react": "*", "react": "*",
+31 -24
View File
@@ -1,14 +1,15 @@
import { Button, Input } from '@affine/component'; import { Button, Input } from '@affine/component';
import { rootStore } from '@toeverything/plugin-infra/manager'; import { rootStore } from '@toeverything/plugin-infra/manager';
import type { PluginUIAdapter } from '@toeverything/plugin-infra/type'; import type { PluginUIAdapter } from '@toeverything/plugin-infra/type';
import { Provider, useAtom, useAtomValue, useSetAtom } from 'jotai'; import { Provider, useAtomValue, useSetAtom } from 'jotai';
import type { ReactElement } from 'react'; import type { ReactElement } from 'react';
import { Fragment, StrictMode, useState } from 'react'; import { StrictMode, Suspense, useCallback, useState } from 'react';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import { Conversation } from '../core/components/conversation'; import { ConversationList } from '../core/components/conversation-list';
import { Divider } from '../core/components/divider'; import { FollowingUp } from '../core/components/following-up';
import { openAIApiKeyAtom, useChatAtoms } from '../core/hooks'; import { openAIApiKeyAtom, useChatAtoms } from '../core/hooks';
import { detailContentActionsStyle, detailContentStyle } from './index.css';
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
import('@blocksuite/blocks').then(({ FormatQuickBar }) => { import('@blocksuite/blocks').then(({ FormatQuickBar }) => {
@@ -54,25 +55,16 @@ if (typeof window === 'undefined') {
}); });
} }
const DetailContentImpl = () => { const Actions = () => {
const { conversationAtom, followingUpAtoms } = useChatAtoms();
const call = useSetAtom(conversationAtom);
const questions = useAtomValue(followingUpAtoms.questionsAtom);
const generateFollowingUp = useSetAtom(followingUpAtoms.generateChatAtom);
const [input, setInput] = useState(''); const [input, setInput] = useState('');
const { conversationAtom } = useChatAtoms();
const [conversations, call] = useAtom(conversationAtom);
return ( return (
<div <>
style={{ <FollowingUp questions={questions} />
width: '300px', <div className={detailContentActionsStyle}>
}}
>
{conversations.map((message, idx) => {
return (
<Fragment key={idx}>
<Conversation text={message.text} />
<Divider />
</Fragment>
);
})}
<div>
<Input <Input
value={input} value={input}
onChange={text => { onChange={text => {
@@ -80,13 +72,28 @@ const DetailContentImpl = () => {
}} }}
/> />
<Button <Button
onClick={() => { onClick={useCallback(async () => {
void call(input); await call(input);
}} await generateFollowingUp();
}, [call, generateFollowingUp, input])}
> >
send send
</Button> </Button>
</div> </div>
</>
);
};
const DetailContentImpl = () => {
const { conversationAtom } = useChatAtoms();
const conversations = useAtomValue(conversationAtom);
return (
<div className={detailContentStyle}>
<ConversationList conversations={conversations} />
<Suspense fallback="generating follow-up question">
<Actions />
</Suspense>
</div> </div>
); );
}; };
+1 -1
View File
@@ -19,7 +19,7 @@ export const HeaderItem: PluginUIAdapter['headerItem'] = ({
direction: 'horizontal', direction: 'horizontal',
first: 'editor', first: 'editor',
second: 'com.affine.copilot', second: 'com.affine.copilot',
splitPercentage: 80, splitPercentage: 70,
}; };
} else { } else {
return 'editor'; return 'editor';
+15
View File
@@ -0,0 +1,15 @@
import { style } from '@vanilla-extract/css';
export const detailContentStyle = style({
backgroundColor: 'rgba(0, 0, 0, 0.04)',
height: '100%',
display: 'flex',
flexDirection: 'column',
overflow: 'auto',
paddingLeft: '9px',
paddingRight: '9px',
});
export const detailContentActionsStyle = style({});
+37 -6
View File
@@ -1,16 +1,17 @@
import { ConversationChain } from 'langchain/chains'; import { ConversationChain, LLMChain } from 'langchain/chains';
import { ChatOpenAI } from 'langchain/chat_models/openai'; import { ChatOpenAI } from 'langchain/chat_models/openai';
import { BufferMemory } from 'langchain/memory'; import { BufferMemory } from 'langchain/memory';
import { import {
ChatPromptTemplate, ChatPromptTemplate,
HumanMessagePromptTemplate, HumanMessagePromptTemplate,
MessagesPlaceholder, MessagesPlaceholder,
PromptTemplate,
SystemMessagePromptTemplate, SystemMessagePromptTemplate,
} from 'langchain/prompts'; } from 'langchain/prompts';
import { type LLMResult } from 'langchain/schema'; import { type LLMResult } from 'langchain/schema';
import { IndexedDBChatMessageHistory } from './langchain/message-history'; import { IndexedDBChatMessageHistory } from './langchain/message-history';
import { chatPrompt } from './prompts'; import { chatPrompt, followupQuestionPrompt } from './prompts';
declare global { declare global {
interface WindowEventMap { interface WindowEventMap {
@@ -22,13 +23,24 @@ declare global {
export async function createChatAI( export async function createChatAI(
room: string, room: string,
openAIApiKey: string openAIApiKey: string
): Promise<ConversationChain> { ): Promise<{
conversationChain: ConversationChain;
followupChain: LLMChain<string>;
chatHistory: IndexedDBChatMessageHistory;
}> {
if (!openAIApiKey) { if (!openAIApiKey) {
console.warn('OpenAI API key not set, chat will not work'); console.warn('OpenAI API key not set, chat will not work');
} }
const followup = new ChatOpenAI({
streaming: false,
modelName: 'gpt-3.5-turbo',
temperature: 0.5,
openAIApiKey: openAIApiKey,
});
const chat = new ChatOpenAI({ const chat = new ChatOpenAI({
streaming: true, streaming: true,
modelName: 'gpt-4', modelName: 'gpt-3.5-turbo',
temperature: 0.5, temperature: 0.5,
openAIApiKey: openAIApiKey, openAIApiKey: openAIApiKey,
callbacks: [ callbacks: [
@@ -77,13 +89,32 @@ export async function createChatAI(
HumanMessagePromptTemplate.fromTemplate('{input}'), HumanMessagePromptTemplate.fromTemplate('{input}'),
]); ]);
return new ConversationChain({ const followupPromptTemplate = new PromptTemplate({
template: followupQuestionPrompt,
inputVariables: ['human_conversation', 'ai_conversation'],
});
const followupChain = new LLMChain({
llm: followup,
prompt: followupPromptTemplate,
memory: undefined,
});
const chatHistory = new IndexedDBChatMessageHistory(room);
const conversationChain = new ConversationChain({
memory: new BufferMemory({ memory: new BufferMemory({
returnMessages: true, returnMessages: true,
memoryKey: 'history', memoryKey: 'history',
chatHistory: new IndexedDBChatMessageHistory(room), chatHistory,
}), }),
prompt: chatPromptTemplate, prompt: chatPromptTemplate,
llm: chat, llm: chat,
}); });
return {
conversationChain,
followupChain,
chatHistory,
} as const;
} }
@@ -0,0 +1,7 @@
import { style } from '@vanilla-extract/css';
export const conversationListStyle = style({
display: 'flex',
flexDirection: 'column',
gap: '30px',
});
@@ -0,0 +1,22 @@
import type { BaseChatMessage } from 'langchain/schema';
import { Conversation } from '../conversation';
import { conversationListStyle } from './index.css';
export type ConversationListProps = {
conversations: BaseChatMessage[];
};
export const ConversationList = (props: ConversationListProps) => {
return (
<div className={conversationListStyle}>
{props.conversations.map((conversation, idx) => (
<Conversation
type={conversation._getType()}
text={conversation.text}
key={idx}
/>
))}
</div>
);
};
@@ -1,19 +0,0 @@
import { marked } from 'marked';
import { type ReactElement, useMemo } from 'react';
export interface ConversationProps {
text: string;
}
export const Conversation = (props: ConversationProps): ReactElement => {
const html = useMemo(() => marked.parse(props.text), [props.text]);
return (
<div>
<div
dangerouslySetInnerHTML={{
__html: html,
}}
/>
</div>
);
};
@@ -0,0 +1,15 @@
import { style } from '@vanilla-extract/css';
export const conversationStyle = style({
padding: '10px 18px',
});
export const aiMessageStyle = style({
backgroundColor: 'rgba(207, 252, 255, 0.3)',
borderRadius: '18px 18px 18px 2px',
});
export const humanMessageStyle = style({
borderRadius: '18px 18px 2px 18px',
backgroundColor: 'white',
});
@@ -0,0 +1,42 @@
import { clsx } from 'clsx';
import type { MessageType } from 'langchain/schema';
import { marked } from 'marked';
import { gfmHeadingId } from 'marked-gfm-heading-id';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
import { mangle } from 'marked-mangle';
import { type ReactElement, useMemo } from 'react';
import {
aiMessageStyle,
conversationStyle,
humanMessageStyle,
} from './index.css';
marked.use(
gfmHeadingId({
prefix: 'affine-',
})
);
marked.use(mangle());
export interface ConversationProps {
type: MessageType;
text: string;
}
export const Conversation = (props: ConversationProps): ReactElement => {
const html = useMemo(() => marked.parse(props.text), [props.text]);
return (
<div
className={clsx(conversationStyle, {
[aiMessageStyle]: props.type === 'ai',
[humanMessageStyle]: props.type === 'human',
})}
dangerouslySetInnerHTML={{
__html: html,
}}
></div>
);
};
@@ -0,0 +1,17 @@
import { style } from '@vanilla-extract/css';
export const followingUpStyle = style({
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
gap: '10px',
alignItems: 'flex-start',
});
export const questionStyle = style({
backgroundColor: 'white',
borderRadius: '8px',
color: '#8E8D91',
padding: '2px 10px',
cursor: 'pointer',
});
@@ -0,0 +1,19 @@
import type { ReactElement } from 'react';
import { followingUpStyle, questionStyle } from './index.css';
export type FollowingUpProps = {
questions: string[];
};
export const FollowingUp = (props: FollowingUpProps): ReactElement => {
return (
<div className={followingUpStyle}>
{props.questions.map((question, index) => (
<div className={questionStyle} key={index}>
{question}
</div>
))}
</div>
);
};
+86 -7
View File
@@ -1,6 +1,9 @@
import type { IndexedDBChatMessageHistory } from '@affine/copilot/core/langchain/message-history';
import { atom, useAtomValue } from 'jotai'; import { atom, useAtomValue } from 'jotai';
import { atomFamily } from 'jotai/utils'; import { atomWithDefault } from 'jotai/utils';
import { atomWithStorage } from 'jotai/utils'; import { atomWithStorage } from 'jotai/utils';
import type { WritableAtom } from 'jotai/vanilla';
import type { LLMChain } from 'langchain/chains';
import { type ConversationChain } from 'langchain/chains'; import { type ConversationChain } from 'langchain/chains';
import { type BufferMemory } from 'langchain/memory'; import { type BufferMemory } from 'langchain/memory';
import { import {
@@ -8,9 +11,12 @@ import {
type BaseChatMessage, type BaseChatMessage,
HumanChatMessage, HumanChatMessage,
} from 'langchain/schema'; } from 'langchain/schema';
import { z } from 'zod';
import { createChatAI } from '../chat'; import { createChatAI } from '../chat';
const followupResponseSchema = z.array(z.string());
export const openAIApiKeyAtom = atomWithStorage<string | null>( export const openAIApiKeyAtom = atomWithStorage<string | null>(
'com.affine.copilot.openai.token', 'com.affine.copilot.openai.token',
null null
@@ -19,12 +25,24 @@ export const openAIApiKeyAtom = atomWithStorage<string | null>(
export const chatAtom = atom(async get => { export const chatAtom = atom(async get => {
const openAIApiKey = get(openAIApiKeyAtom); const openAIApiKey = get(openAIApiKeyAtom);
if (!openAIApiKey) { if (!openAIApiKey) {
return null; throw new Error('OpenAI API key not set, chat will not work');
} }
return createChatAI('default-copilot', openAIApiKey); return createChatAI('default-copilot', openAIApiKey);
}); });
const conversationAtomFamily = atomFamily((chat: ConversationChain | null) => { const conversationWeakMap = new WeakMap<
ConversationChain,
WritableAtom<BaseChatMessage[], [string], Promise<void>>
>();
const getConversationAtom = (chat: ConversationChain) => {
if (conversationWeakMap.has(chat)) {
return conversationWeakMap.get(chat) as WritableAtom<
BaseChatMessage[],
[string],
Promise<void>
>;
}
const conversationBaseAtom = atom<BaseChatMessage[]>([]); const conversationBaseAtom = atom<BaseChatMessage[]>([]);
conversationBaseAtom.onMount = setAtom => { conversationBaseAtom.onMount = setAtom => {
if (!chat) { if (!chat) {
@@ -52,7 +70,7 @@ const conversationAtomFamily = atomFamily((chat: ConversationChain | null) => {
}; };
}; };
return atom<BaseChatMessage[], [string], Promise<void>>( const conversationAtom = atom<BaseChatMessage[], [string], Promise<void>>(
get => get(conversationBaseAtom), get => get(conversationBaseAtom),
async (get, set, input) => { async (get, set, input) => {
if (!chat) { if (!chat) {
@@ -73,14 +91,75 @@ const conversationAtomFamily = atomFamily((chat: ConversationChain | null) => {
}); });
} }
); );
}); conversationWeakMap.set(chat, conversationAtom);
return conversationAtom;
};
const followingUpWeakMap = new WeakMap<
LLMChain<string>,
{
questionsAtom: ReturnType<typeof atomWithDefault<Promise<string[]>>>;
generateChatAtom: WritableAtom<null, [], void>;
}
>();
const getFollowingUpAtoms = (
followupLLMChain: LLMChain<string>,
chatHistory: IndexedDBChatMessageHistory
) => {
if (followingUpWeakMap.has(followupLLMChain)) {
return followingUpWeakMap.get(followupLLMChain) as {
questionsAtom: ReturnType<typeof atomWithDefault<Promise<string[]>>>;
generateChatAtom: WritableAtom<null, [], void>;
};
}
const baseAtom = atomWithDefault<Promise<string[]>>(async () => {
return chatHistory?.getFollowingUp() ?? [];
});
const setAtom = atom<null, [], void>(null, async (get, set) => {
if (!followupLLMChain || !chatHistory) {
throw new Error('followupLLMChain not set');
}
const messages = await chatHistory.getMessages();
const aiMessage = messages.findLast(
message => message._getType() === 'ai'
)?.text;
const humanMessage = messages.findLast(
message => message._getType() === 'human'
)?.text;
const response = await followupLLMChain.call({
ai_conversation: aiMessage,
human_conversation: humanMessage,
});
const followingUp = JSON.parse(response.text);
followupResponseSchema.parse(followingUp);
set(baseAtom, followingUp);
chatHistory.saveFollowingUp(followingUp).catch(() => {
console.error('failed to save followup');
});
});
followingUpWeakMap.set(followupLLMChain, {
questionsAtom: baseAtom,
generateChatAtom: setAtom,
});
return {
questionsAtom: baseAtom,
generateChatAtom: setAtom,
};
};
export function useChatAtoms(): { export function useChatAtoms(): {
conversationAtom: ReturnType<typeof conversationAtomFamily>; conversationAtom: ReturnType<typeof getConversationAtom>;
followingUpAtoms: ReturnType<typeof getFollowingUpAtoms>;
} { } {
const chat = useAtomValue(chatAtom); const chat = useAtomValue(chatAtom);
const conversationAtom = conversationAtomFamily(chat); const conversationAtom = getConversationAtom(chat.conversationChain);
const followingUpAtoms = getFollowingUpAtoms(
chat.followupChain,
chat.chatHistory
);
return { return {
conversationAtom, conversationAtom,
followingUpAtoms,
}; };
} }
@@ -23,25 +23,42 @@ interface ChatMessageDBV1 extends DBSchema {
}; };
} }
interface ChatMessageDBV2 extends ChatMessageDBV1 {
followingUp: {
key: string;
value: {
/**
* ID of the chat
*/
id: string;
question: string[];
};
};
}
export const conversationHistoryDBName = 'affine-copilot-chat'; export const conversationHistoryDBName = 'affine-copilot-chat';
export class IndexedDBChatMessageHistory extends BaseChatMessageHistory { export class IndexedDBChatMessageHistory extends BaseChatMessageHistory {
public id: string; public id: string;
private messages: BaseChatMessage[] = []; private messages: BaseChatMessage[] = [];
private readonly dbPromise: Promise<IDBPDatabase<ChatMessageDBV1>>; private readonly dbPromise: Promise<IDBPDatabase<ChatMessageDBV2>>;
private readonly initPromise: Promise<void>; private readonly initPromise: Promise<void>;
constructor(id: string) { constructor(id: string) {
super(); super();
this.id = id; this.id = id;
this.messages = []; this.messages = [];
this.dbPromise = openDB<ChatMessageDBV1>('affine-copilot-chat', 1, { this.dbPromise = openDB<ChatMessageDBV2>('affine-copilot-chat', 2, {
upgrade(database, oldVersion) { upgrade(database, oldVersion) {
if (oldVersion === 0) { if (oldVersion === 0) {
database.createObjectStore('chat', { database.createObjectStore('chat', {
keyPath: 'id', keyPath: 'id',
}); });
} else if (oldVersion === 1) {
database.createObjectStore('followingUp', {
keyPath: 'id',
});
} }
}, },
}); });
@@ -70,6 +87,31 @@ export class IndexedDBChatMessageHistory extends BaseChatMessageHistory {
}); });
} }
public async saveFollowingUp(question: string[]): Promise<void> {
await this.initPromise;
const db = await this.dbPromise;
const t = db
.transaction('followingUp', 'readwrite')
.objectStore('followingUp');
await t.put({
id: this.id,
question,
});
}
public async getFollowingUp(): Promise<string[]> {
await this.initPromise;
const db = await this.dbPromise;
const t = db
.transaction('followingUp', 'readonly')
.objectStore('followingUp');
const chat = await t.get(this.id);
if (chat != null) {
return chat.question;
}
return [];
}
protected async addMessage(message: BaseChatMessage): Promise<void> { protected async addMessage(message: BaseChatMessage): Promise<void> {
await this.initPromise; await this.initPromise;
this.messages.push(message); this.messages.push(message);
@@ -104,6 +146,6 @@ export class IndexedDBChatMessageHistory extends BaseChatMessageHistory {
} }
async getMessages(): Promise<BaseChatMessage[]> { async getMessages(): Promise<BaseChatMessage[]> {
return await this.initPromise.then(() => this.messages); return this.initPromise.then(() => this.messages);
} }
} }
+14 -3
View File
@@ -14,8 +14,19 @@ Keep your answers short and impersonal.
The user works in an app called AFFiNE, which has a concept for an editor, a page for a single document, workspace for a collection of documents. The user works in an app called AFFiNE, which has a concept for an editor, a page for a single document, workspace for a collection of documents.
The active document is the markdown file the user is looking at. The active document is the markdown file the user is looking at.
Use Markdown formatting in your answers. Use Markdown formatting in your answers.
Wrap your answers into triple backticks.
You can only give one reply for each conversation turn. You can only give one reply for each conversation turn.
You should always generate short suggestions for the next user turns that are relevant to the conversation and not offensive. `;
You should reply to the users within 150 characters.
export const followupQuestionPrompt = `Rules you must follow:
- You only respond in JSON format
- Read the following conversation between AI and Human and generate at most 3 follow-up messages or questions the Human can ask
- Your response MUST be a valid JSON array of strings like this: ["some question", "another question"]
- Each message in your response should be concise, no more than 15 words
- You MUST reply in the same written language as the conversation
- Don't output anything other text
The conversation is inside triple quotes:
\`\`\`
Human: {human_conversation}
AI: {ai_conversation}
\`\`\`
`; `;
+37 -6
View File
@@ -130,10 +130,13 @@ __metadata:
"@types/react-dom": ^18.2.4 "@types/react-dom": ^18.2.4
idb: ^7.1.1 idb: ^7.1.1
jotai: ^2.1.1 jotai: ^2.1.1
langchain: ^0.0.90 langchain: ^0.0.92
marked: ^5.0.4 marked: ^5.0.4
marked-gfm-heading-id: ^3.0.4
marked-mangle: ^1.0.1
react: 18.3.0-canary-16d053d59-20230506 react: 18.3.0-canary-16d053d59-20230506
react-dom: 18.3.0-canary-16d053d59-20230506 react-dom: 18.3.0-canary-16d053d59-20230506
zod: ^3.21.4
peerDependencies: peerDependencies:
react: "*" react: "*"
react-dom: "*" react-dom: "*"
@@ -300,6 +303,7 @@ __metadata:
husky: ^8.0.3 husky: ^8.0.3
lint-staged: ^13.2.2 lint-staged: ^13.2.2
madge: ^6.1.0 madge: ^6.1.0
marked-mangle: ^1.0.1
msw: ^1.2.1 msw: ^1.2.1
nanoid: ^4.0.2 nanoid: ^4.0.2
nx: 16.3.2 nx: 16.3.2
@@ -16830,6 +16834,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"github-slugger@npm:^2.0.0":
version: 2.0.0
resolution: "github-slugger@npm:2.0.0"
checksum: 250375cde2058f21454872c2c79f72c4637340c30c51ff158ca4ec71cbc478f33d54477d787a662f9207aeb095a2060f155bc01f15329ba8a5fb6698e0fc81f8
languageName: node
linkType: hard
"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2":
version: 5.1.2 version: 5.1.2
resolution: "glob-parent@npm:5.1.2" resolution: "glob-parent@npm:5.1.2"
@@ -19787,9 +19798,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"langchain@npm:^0.0.90": "langchain@npm:^0.0.92":
version: 0.0.90 version: 0.0.92
resolution: "langchain@npm:0.0.90" resolution: "langchain@npm:0.0.92"
dependencies: dependencies:
"@anthropic-ai/sdk": ^0.4.3 "@anthropic-ai/sdk": ^0.4.3
ansi-styles: ^5.0.0 ansi-styles: ^5.0.0
@@ -19835,7 +19846,7 @@ __metadata:
cohere-ai: ^5.0.2 cohere-ai: ^5.0.2
d3-dsv: ^2.0.0 d3-dsv: ^2.0.0
epub2: ^3.0.1 epub2: ^3.0.1
faiss-node: ^0.2.0 faiss-node: ^0.2.1
google-auth-library: ^8.8.0 google-auth-library: ^8.8.0
hnswlib-node: ^1.4.2 hnswlib-node: ^1.4.2
html-to-text: ^9.0.5 html-to-text: ^9.0.5
@@ -19947,7 +19958,7 @@ __metadata:
optional: true optional: true
weaviate-ts-client: weaviate-ts-client:
optional: true optional: true
checksum: cbd35a7397b30ad265bf4ce992818ee03a409c33dde7a7a1e17c76e7e875768dbc79ff06618e42b3c688081ff8b0ff5eb34b532a2994d078578de67937a6452b checksum: a9fb6cdf48e971f9327bcf5eb2322eb9b9add63413ecacd90bb064feab40d3ba6024086ccade59c0285dd57249406dda9ba7847cdb02e08312e147618165b49e
languageName: node languageName: node
linkType: hard linkType: hard
@@ -20760,6 +20771,26 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"marked-gfm-heading-id@npm:^3.0.4":
version: 3.0.4
resolution: "marked-gfm-heading-id@npm:3.0.4"
dependencies:
github-slugger: ^2.0.0
peerDependencies:
marked: ^4 || ^5
checksum: 8c65d0fe0f59291d6f4529f49a4af00cad5787a72a59b9397f82d6ab58b1affbf53678f7efdca77fa75c32e80bbdab1c53c2aa5d7ece3e821d2fe35a76fb4930
languageName: node
linkType: hard
"marked-mangle@npm:^1.0.1":
version: 1.0.1
resolution: "marked-mangle@npm:1.0.1"
peerDependencies:
marked: ^4 || ^5
checksum: 7ebdd69eb41907a865141e7cce1cd8c5c24dd6955c63aaf5299710aba2935abdfbca1b1ea0ff30cf527ff20a940c3b5a9311fca9abb84f4d294767b0435213fe
languageName: node
linkType: hard
"marked@npm:^4.2.12": "marked@npm:^4.2.12":
version: 4.3.0 version: 4.3.0
resolution: "marked@npm:4.3.0" resolution: "marked@npm:4.3.0"