Skip to content

Commit

Permalink
Merge pull request #1 from palico-ai/copilot-context
Browse files Browse the repository at this point in the history
FEAT: Added Palico application context
  • Loading branch information
shikdernyc committed Jan 26, 2024
2 parents 11ea25f + 2f23211 commit f1e9992
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 18 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
"react"
],
"rules": {
"@typescript-eslint/no-extraneous-class": "off"
"@typescript-eslint/no-extraneous-class": "off",
"@typescript-eslint/strict-boolean-expressions": "off",
}
}
33 changes: 28 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.33.2",
"react": "^18.2.0",
"rollup": "^4.9.5",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-peer-deps-external": "^2.2.4",
Expand All @@ -49,6 +48,10 @@
"tslib": "^2.6.2",
"typescript": "^4.9.5"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"keywords": [],
"author": "",
"license": "ISC",
Expand Down
3 changes: 1 addition & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ export default [
commonjs(),
typescript({ tsconfig: './tsconfig.json' }),
terser()
],
external: ['react', 'react-dom', 'styled-components']
]
},
{
input: 'src/index.ts',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'

export const CopilotUI : React.FC = () => {
export const CopilotUI: React.FC = () => {
return (
<div>
<h1>CopilotUI</h1>
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './copilot'
132 changes: 132 additions & 0 deletions src/context/application_context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React, { useEffect } from 'react'
import { type ChatCompletionMessageToolCall } from 'openai/resources/chat/completions'
import { AgentAPI, type AgentCallResponse, type AgentMessage, type ToolExecutionMessage } from '../agent_api'

export interface ChatMessage {
content: string
role: 'user' | 'assistant'
}

export interface PalicoContextProps {
loading: boolean
deploymentId: number
conversationHistory: ChatMessage[]
sendMessage: (message: string) => Promise<void>
}

export const PalicoContext = React.createContext<PalicoContextProps>({
loading: false,
deploymentId: -1,
conversationHistory: [],
sendMessage: async () => {}
})

export type ToolHandler<Input, Output> = (input: Input) => Promise<Output>

export interface PalicoContextProviderProps {
tools: Record<string, ToolHandler<any, any>>
deploymentId: number
children?: any
}

export const PalicoContextProvider: React.FC<PalicoContextProviderProps> = ({
deploymentId,
tools,
children
}) => {
const [loading, setLoading] = React.useState<boolean>(false)
const [conversationId, setConversationId] = React.useState<number>()
const [messageHistory, setMessageHistory] = React.useState<ChatMessage[]>([])
// TODO: Convert to step-based pending message (create user reply -> handle user reply -> handle tool call -> end)
const [pendingMessage, setPendingMessage] = React.useState<string>()

useEffect(() => {
const callTool = async (tool: ChatCompletionMessageToolCall): Promise<ToolExecutionMessage> => {
const toolHandler = tools[tool.function.name]
if (toolHandler === null || toolHandler === undefined) {
throw new Error(`Tool ${tool.function.name} not found`)
}
const output = await toolHandler(JSON.parse(tool.function.arguments))
return {
toolId: tool.id,
functionName: tool.function.name,
output
}
}

const handleToolCall = async (message: AgentMessage, conversationId: number): Promise<void> => {
if (!message.toolCalls) return
const toolCallResponse = await Promise.all(message.toolCalls.map(callTool))
const response = await AgentAPI.replyToToolCall({
deploymentId,
conversationId,
toolOutputs: toolCallResponse
})
await handleAgentResponse(response, conversationId)
}

const handleAgentResponse = async (response: AgentCallResponse, conversationId: number): Promise<void> => {
if (response.message.toolCalls) {
await handleToolCall(response.message, conversationId)
}
if (response.message.content) {
setMessageHistory([
...messageHistory,
{
content: response.message.content.toString(),
role: 'assistant'
}
])
}
}

const handlePendingMessage = async (): Promise<void> => {
console.log('Handle pending message')
if (!pendingMessage) return
try {
setPendingMessage(undefined)
if (!conversationId) {
const response = await AgentAPI.newConversation({
deploymentId,
message: pendingMessage
})
setConversationId(response.conversationId)
await handleAgentResponse(response, response.conversationId)
} else {
const response = await AgentAPI.replyAsUser({
deploymentId,
conversationId,
message: pendingMessage
})
await handleAgentResponse(response, conversationId)
}
} catch (e) {
console.log(e)
} finally {
setLoading(false)
}
}

void handlePendingMessage()
}, [conversationId, deploymentId, messageHistory, pendingMessage, tools])

const sendMessage = async (message: string): Promise<void> => {
setLoading(true)
setPendingMessage(message)
setMessageHistory([
...messageHistory,
{
content: message,
role: 'user'
}
])
}

return (
<PalicoContext.Provider
value={{ deploymentId, conversationHistory: messageHistory, sendMessage, loading }}
>
{children}
</PalicoContext.Provider>
)
}
1 change: 1 addition & 0 deletions src/context/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './application_context'
5 changes: 0 additions & 5 deletions src/hello_world.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './hello_world'
export * from './ui'
export * from './context'
export * from './components'
export * from './agent_api'
1 change: 0 additions & 1 deletion src/ui/index.ts

This file was deleted.

0 comments on commit f1e9992

Please sign in to comment.