-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Start implementing new agentic layout
Implement basic chat and first agent function that suggests pipelines based on user documents Addresses #21
- Loading branch information
Showing
11 changed files
with
276 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { PipelineBuilder } from '../pipeline/PipelineBuilder'; | ||
import { Chat } from './Chat'; | ||
|
||
export function AgentUI() { | ||
return ( | ||
<div className="flex flex-1 w-screen h-screen"> | ||
<div className="flex flex-1"> | ||
<Chat /> | ||
</div> | ||
<div className="flex flex-1"> | ||
<PipelineBuilder className="w-full h-full pt-6 p-3" /> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { PaperAirplaneIcon } from '@heroicons/react/24/solid'; | ||
import { useAtomValue, useSetAtom } from 'jotai'; | ||
import { useState } from 'react'; | ||
import { litlyticsAtom, pipelineAtom } from '~/store/store'; | ||
import { Button } from '../catalyst/button'; | ||
import { Input } from '../catalyst/input'; | ||
import { CustomMarkdown } from '../markdown/Markdown'; | ||
import { askAgent, Message } from './agent'; | ||
|
||
function MessageRender({ message }: { message: Message }) { | ||
if (message.from === 'user') { | ||
return ( | ||
<div className="bg-neutral-100 dark:bg-neutral-900 p-2 rounded-xl w-fit self-end"> | ||
{message.text} | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<div className="flex gap-3"> | ||
<div className="w-fit"> | ||
<span className="rounded-full border p-1 border-neutral-300 dark:border-neutral-700"> | ||
🔥 | ||
</span> | ||
</div> | ||
<div className="flex flex-1"> | ||
<div className="prose dark:prose-invert"> | ||
<CustomMarkdown>{message.text}</CustomMarkdown> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export function Chat() { | ||
const litlytics = useAtomValue(litlyticsAtom); | ||
const setPipeline = useSetAtom(pipelineAtom); | ||
const [input, setInput] = useState<string>(''); | ||
const [messages, setMessages] = useState<Message[]>([ | ||
{ | ||
id: '0', | ||
from: 'assistant', | ||
text: `Hi! I'm Lit. Ask me to do anything for you.`, | ||
}, | ||
]); | ||
|
||
const sendMessage = async () => { | ||
const inputMessage = input; | ||
// reset input | ||
setInput(''); | ||
// append user message to messages | ||
const messagesWithUser: Message[] = [ | ||
...messages, | ||
{ | ||
id: String(messages.length), | ||
from: 'user', | ||
text: inputMessage, | ||
}, | ||
]; | ||
setMessages(messagesWithUser); | ||
|
||
// TODO: show loading state | ||
|
||
// run new messages through agent | ||
const newMessages = await askAgent({ | ||
messages: messagesWithUser, | ||
litlytics, | ||
setPipeline, | ||
}); | ||
setMessages(newMessages); | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col w-full h-full"> | ||
<div className="flex flex-1 flex-col gap-4 p-3 pt-20"> | ||
{messages.map((m) => ( | ||
<MessageRender key={m.id} message={m} /> | ||
))} | ||
</div> | ||
<div className="flex items-center min-h-16 p-2"> | ||
<Input | ||
wrapperClassName="h-fit after:hidden sm:after:focus-within:ring-2 sm:after:focus-within:ring-blue-500" | ||
className="rounded-r-none" | ||
placeholder="Ask Lit to do things for you" | ||
value={input} | ||
onChange={(e) => setInput(e.target.value)} | ||
onKeyDown={(e) => { | ||
if (e.key === 'Enter') { | ||
sendMessage(); | ||
} | ||
}} | ||
/> | ||
<Button | ||
className="h-9 rounded-l-none" | ||
title="Send" | ||
onClick={sendMessage} | ||
> | ||
<PaperAirplaneIcon /> | ||
</Button> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { Pipeline, tool, type LLMArgs, type LitLytics } from 'litlytics'; | ||
import { RunPromptFromMessagesArgs } from 'litlytics/engine/runPrompt'; | ||
import { z } from 'zod'; | ||
|
||
const systemPrompt = ` | ||
You are Lit - a friendly assistant and an expert in data science. | ||
Your task is to help user design a text document processing pipeline using low-code platform called LitLytics. | ||
LitLytics allows creating custom text document processing pipelines using custom processing steps. | ||
You have access to following LitLytics functions: | ||
- Suggest a list of possible pipelines that can be applied to user's documents | ||
- Generate a suggested pipeline for processing documents | ||
- Refine suggested pipeline for processing documents | ||
- Add a new step to pipeline | ||
- Edit a step in the pipeline | ||
- Test a step in the pipeline | ||
- Execute a pipeline | ||
If you can execute one of the functions listed above - do so and let user know you are on it. | ||
`; | ||
|
||
export interface Message { | ||
id: string; | ||
from: 'user' | 'assistant'; | ||
text: string; | ||
} | ||
|
||
export const askAgent = async ({ | ||
messages, | ||
litlytics, | ||
setPipeline, | ||
}: { | ||
messages: Message[]; | ||
litlytics: LitLytics; | ||
setPipeline: (p: Pipeline) => void; | ||
}): Promise<Message[]> => { | ||
// create a promise we will use as result | ||
const { promise, resolve, reject } = Promise.withResolvers<Message[]>(); | ||
|
||
// generate input messages | ||
const inputMessages: RunPromptFromMessagesArgs['messages'] = messages.map( | ||
(m) => ({ | ||
content: m.text, | ||
role: m.from, | ||
}) | ||
); | ||
const agentMessages: RunPromptFromMessagesArgs['messages'] = [ | ||
{ | ||
role: 'system', | ||
content: systemPrompt.trim(), | ||
}, | ||
...inputMessages, | ||
]; | ||
console.log(agentMessages); | ||
|
||
// generate tools | ||
const tools: LLMArgs['tools'] = { | ||
analyzeDocuments: tool({ | ||
description: `Suggest a list of possible pipelines that can be applied to user's documents.`, | ||
parameters: z.object({ | ||
suggest: z.boolean(), | ||
}), | ||
execute: async () => { | ||
// run task | ||
const newPipeline = await litlytics.suggestTasks(); | ||
setPipeline(newPipeline); | ||
// generate a response | ||
const agentMessagesWithResult = agentMessages.concat([ | ||
{ | ||
content: `Suggested tasks from function execution: | ||
${newPipeline.pipelineTasks?.map((task) => '- ' + task)?.join('\n')} | ||
Generate a text description for user.`, | ||
role: 'system', | ||
}, | ||
]); | ||
const result = await litlytics.runPromptFromMessages({ | ||
messages: agentMessagesWithResult, | ||
}); | ||
resolve( | ||
messages.concat({ | ||
id: String(messages.length), | ||
from: 'assistant', | ||
text: result.result, | ||
}) | ||
); | ||
}, | ||
}), | ||
}; | ||
|
||
// execute request | ||
const result = await litlytics.runPromptFromMessages({ | ||
messages: agentMessages, | ||
args: { | ||
tools, | ||
}, | ||
}); | ||
|
||
console.log(result); | ||
if (result.result.length) { | ||
resolve( | ||
messages.concat({ | ||
id: String(messages.length), | ||
from: 'assistant', | ||
text: result.result, | ||
}) | ||
); | ||
} | ||
|
||
return promise; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters