Skip to content

Commit

Permalink
full screen chat (#318)
Browse files Browse the repository at this point in the history
* full-screen chat feature

* 3.17.6
  • Loading branch information
rjmacarthy authored Sep 19, 2024
1 parent 407f13e commit ae9fb19
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 32 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

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

21 changes: 18 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "twinny",
"displayName": "twinny - AI Code Completion and Chat",
"description": "Locally hosted AI code completion plugin for vscode",
"version": "3.17.5",
"version": "3.17.6",
"icon": "assets/icon.png",
"keywords": [
"code-inference",
Expand Down Expand Up @@ -118,18 +118,27 @@
"group": "navigation@6"
},
{
"command": "twinny.newConversation",
"command": "twinny.openPanelChat",
"when": "view == twinny.sidebar",
"group": "navigation@7"
},
{
"command": "twinny.settings",
"command": "twinny.newConversation",
"when": "view == twinny.sidebar",
"group": "navigation@8"
},
{
"command": "twinny.settings",
"when": "view == twinny.sidebar",
"group": "navigation@9"
}
]
},
"commands": [
{
"command": "twinny.openPanelChat",
"title": "Twinny - Open full screen panel"
},
{
"command": "twinny.explain",
"title": "Twinny - Explain"
Expand Down Expand Up @@ -201,6 +210,12 @@
"title": "Open twinny conversation history",
"icon": "$(history)"
},
{
"command": "twinny.openPanelChat",
"shortTitle": "Open twinny panel chat",
"title": "Open twinny panel chat",
"icon": "$(screen-full)"
},
{
"command": "twinny.newConversation",
"shortTitle": "New chat",
Expand Down
13 changes: 7 additions & 6 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export const defaultChunkOptions = {
}

export const EVENT_NAME = {
twinngAddMessage: 'twinny-add-message',
twinnyAcceptSolution: 'twinny-accept-solution',
twinnyAddMessage: 'twinny-add-message',
twinnyChat: 'twinny-chat',
twinnyChatMessage: 'twinny-chat-message',
twinnyClickSuggestion: 'twinny-click-suggestion',
Expand All @@ -50,10 +50,13 @@ export const EVENT_NAME = {
twinnyFileListResponse: 'twinny-file-list-response',
twinnyGetConfigValue: 'twinny-get-config-value',
twinnyGetGitChanges: 'twinny-get-git-changes',
twinnyGetWorkspaceContext: 'twinny-workspace-context',
twinnyGithhubReview: 'twinny-githhub-review',
twinnyGlobalContext: 'twinny-global-context',
twinnyHideBackButton: 'twinny-hide-back-button',
twinnyListTemplates: 'twinny-list-templates',
twinnyManageTemplates: 'twinny-manage-templates',
twinnyNewConversation: 'twinny-new-conversation',
twinnyNewDocument: 'twinny-new-document',
twinnyNotification: 'twinny-notification',
twinnyOnCompletion: 'twinny-on-completion',
Expand All @@ -62,24 +65,22 @@ export const EVENT_NAME = {
twinnyOpenDiff: 'twinny-open-diff',
twinnyRerankThresholdChanged: 'twinny-rerank-threshold-changed',
twinnySendLanguage: 'twinny-send-language',
twinnySymmetryModeles: 'twinny-symmetry-models',
twinnySendLoader: 'twinny-send-loader',
twinnySendSymmetryMessage: 'twinny-send-symmetry-message',
twinnySendSystemMessage: 'twinny-send-system-message',
twinnySendTheme: 'twinny-send-theme',
twinnySessionContext: 'twinny-session-context',
twinnyStartSymmetryProvider: 'twinny-start-symmetry-provider',
twinnyStopSymmetryProvider: 'twinny-stop-symmetry-provider',
twinnySetConfigValue: 'twinny-set-config-value',
twinnySetGlobalContext: 'twinny-set-global-context',
twinnySetOllamaModel: 'twinny-set-ollama-model',
twinnySetSessionContext: 'twinny-set-session-context',
twinnySetTab: 'twinny-set-tab',
twinnySetWorkspaceContext: 'twinny-set-workspace-context',
twinnyStartSymmetryProvider: 'twinny-start-symmetry-provider',
twinnyStopGeneration: 'twinny-stop-generation',
twinnyStopSymmetryProvider: 'twinny-stop-symmetry-provider',
twinnySymmetryModeles: 'twinny-symmetry-models',
twinnyTextSelection: 'twinny-text-selection',
twinnyGetWorkspaceContext: 'twinny-workspace-context',
twinnyGithhubReview: 'twinny-githhub-review'
}

export const TWINNY_COMMAND_NAME = {
Expand Down
6 changes: 6 additions & 0 deletions src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,9 @@ export interface MentionType {
name: string
path: string
}

export interface GitHubPr {
number: number
title: string
html_url: string
}
2 changes: 1 addition & 1 deletion src/extension/chat-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ export class ChatService {
type: EVENT_NAME.twinnyOnLoading
})
this._webView?.postMessage({
type: EVENT_NAME.twinngAddMessage,
type: EVENT_NAME.twinnyAddMessage,
value: {
completion: kebabToSentence(template) + '\n\n' + '```\n' + selection,
data: getLanguage()
Expand Down
8 changes: 0 additions & 8 deletions src/extension/conversation-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
SYMMETRY_DATA_MESSAGE,
TITLE_GENERATION_PROMPT_MESAGE,
USER,
ASSISTANT
} from '../common/constants'
import { SessionManager } from './session-manager'
import { SymmetryService } from './symmetry-service'
Expand Down Expand Up @@ -159,13 +158,6 @@ export class ConversationHistory {

const requestOptions = this.getRequestOptions(provider)

if (messages.length === 1 && messages[0].role === ASSISTANT) {
messages.unshift({
role: USER,
content: 'Request to review code.'
})
}

const requestBody = createStreamRequestBody(provider.provider, {
model: provider.modelName,
numPredictChat: this.config.numPredictChat,
Expand Down
9 changes: 9 additions & 0 deletions src/extension/providers/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export class BaseProvider {
[EVENT_NAME.twinnyStopSymmetryProvider]: this.stopSymmetryProvider,
[EVENT_NAME.twinnyTextSelection]: this.getSelectedText,
[EVENT_NAME.twinnyFileListRequest]: this.fileListRequest,
[EVENT_NAME.twinnyNewConversation]: this.twinnyNewConversation,
[TWINNY_COMMAND_NAME.settings]: this.openSettings
}
eventHandlers[message.type as string]?.(message)
Expand All @@ -183,6 +184,14 @@ export class BaseProvider {
)
}

private twinnyNewConversation = () => {
this.conversationHistory?.resetConversation()
this.newConversation()
this.webView?.postMessage({
type: EVENT_NAME.twinnyStopGeneration
} as ServerMessage<string>)
}

public destroyStream = () => {
this._chatService?.destroyStream()
this.webView?.postMessage({
Expand Down
8 changes: 8 additions & 0 deletions src/extension/review-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ export class GithubService extends ConversationHistory {
this.resetConversation()

setTimeout(async () => {

this.webView?.postMessage({
type: EVENT_NAME.twinnyAddMessage,
value: {
completion: prompt
}
})

this.webView?.postMessage({
type: EVENT_NAME.twinnyOnLoading
})
Expand Down
10 changes: 10 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { TemplateProvider } from './extension/template-provider'
import { ServerMessage } from './common/types'
import { FileInteractionCache } from './extension/file-interaction'
import { getLineBreakCount } from './webview/utils'
import { FullScreenProvider } from './extension/providers/panel'

export async function activate(context: ExtensionContext) {
setContext(context)
Expand All @@ -41,6 +42,11 @@ export async function activate(context: ExtensionContext) {
const templateProvider = new TemplateProvider(templateDir)
const fileInteractionCache = new FileInteractionCache()
const sessionManager = new SessionManager()
const fullScreenProvider = new FullScreenProvider(
context,
templateDir,
statusBarItem
)

const homeDir = os.homedir()
const dbDir = path.join(homeDir, '.twinny/embeddings')
Expand Down Expand Up @@ -262,6 +268,10 @@ export async function activate(context: ExtensionContext) {
type: EVENT_NAME.twinnyStopGeneration
} as ServerMessage<string>)
}),
commands.registerCommand(TWINNY_COMMAND_NAME.openPanelChat, () => {
commands.executeCommand('workbench.action.closeSidebar');
fullScreenProvider.createOrShowPanel()
}),
workspace.onDidCloseTextDocument((document) => {
const filePath = document.uri.fsPath
fileInteractionCache.endSession()
Expand Down
43 changes: 37 additions & 6 deletions src/webview/chat.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'

import cn from 'classnames'
import {
VSCodeButton,
VSCodePanelView,
Expand Down Expand Up @@ -49,9 +49,14 @@ import { EmbeddingOptions } from './embedding-options'
import ChatLoader from './loader'
import styles from './styles/index.module.css'

interface ChatProps {
fullScreen?: boolean
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const global = globalThis as any
export const Chat = () => {
export const Chat = (props: ChatProps): JSX.Element => {
const { fullScreen } = props
const generatingRef = useRef(false)
const editorRef = useRef<Editor | null>(null)
const stopRef = useRef(false)
Expand Down Expand Up @@ -158,7 +163,7 @@ export const Chat = () => {
const messageEventHandler = (event: MessageEvent) => {
const message: ServerMessage = event.data
switch (message.type) {
case EVENT_NAME.twinngAddMessage: {
case EVENT_NAME.twinnyAddMessage: {
handleAddTemplateMessage(message)
break
}
Expand Down Expand Up @@ -398,7 +403,10 @@ export const Chat = () => {

const { suggestion, filePaths } = useSuggestion()

const memoizedSuggestion = useMemo(() => suggestion, [JSON.stringify(filePaths)])
const memoizedSuggestion = useMemo(
() => suggestion,
[JSON.stringify(filePaths)]
)

const editor = useEditor(
{
Expand All @@ -422,7 +430,7 @@ export const Chat = () => {
}),
Placeholder.configure({
placeholder: 'How can twinny help you today?'
}),
})
]
},
[memoizedSuggestion]
Expand All @@ -445,15 +453,38 @@ export const Chat = () => {
}
}, [memoizedSuggestion])

const handleNewConversation = () => {
global.vscode.postMessage({
type: EVENT_NAME.twinnyNewConversation
})
}

return (
<VSCodePanelView>
<div className={styles.container}>
{!!fullScreen && (
<div className={styles.fullScreenActions}>
<VSCodeButton
onClick={handleNewConversation}
appearance="icon"
title="New conversation"
>
<i className="codicon codicon-comment-discussion" />
</VSCodeButton>
</div>
)}
<h4 className={styles.title}>
{conversation?.title
? conversation?.title
: generatingRef.current && <span>New conversation</span>}
</h4>
<div className={styles.markdown} ref={markdownRef}>
<div
className={cn({
[styles.markdown]: !fullScreen,
[styles.markdownFullScreen]: fullScreen
})}
ref={markdownRef}
>
{messages?.map((message, index) => (
<Message
key={index}
Expand Down
3 changes: 2 additions & 1 deletion src/webview/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
ClientMessage,
Conversation,
FileItem,
GitHubPr,
LanguageType,
ServerMessage,
SymmetryConnection,
Expand Down Expand Up @@ -223,7 +224,7 @@ export const useTemplates = () => {
}

export const useGithubPRs = () => {
const [prs, setPRs] = useState<Array<{ number: number; title: string }>>([])
const [prs, setPRs] = useState<Array<GitHubPr>>([])
const [isLoading, setIsLoading] = useState<boolean>(false)

useEffect(() => {
Expand Down
6 changes: 6 additions & 0 deletions src/webview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ import { Main } from './main'
(globalThis as any).vscode = window.acquireVsCodeApi()

const container = document.querySelector('#root')
const panelContainer = document.querySelector('#root-panel')

if (container) {
const root = createRoot(container)
root.render(<Main />)
}

if (panelContainer) {
const root = createRoot(panelContainer)
root.render(<Main fullScreen />)
}
15 changes: 12 additions & 3 deletions src/webview/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,23 @@ import { ConversationHistory } from './conversation-history'
import { Review } from './review'

const tabs: Record<string, JSX.Element> = {
[WEBUI_TABS.chat]: <Chat />,
[WEBUI_TABS.settings]: <Settings />,
[WEBUI_TABS.providers]: <Providers />,
[WEBUI_TABS.symmetry]: <Symmetry />,
[WEBUI_TABS.review]: <Review />
}

export const Main = () => {
interface MainProps {
fullScreen?: boolean
}

export const Main = ({ fullScreen }: MainProps) => {
const [tab, setTab] = useState<string | undefined>(WEBUI_TABS.chat)

const tabsWithProps = {
[WEBUI_TABS.chat]: <Chat fullScreen={fullScreen} />,
}

const handler = (event: MessageEvent) => {
const message: ServerMessage<string | undefined> = event.data
if (message?.type === EVENT_NAME.twinnySetTab) {
Expand All @@ -39,7 +46,9 @@ export const Main = () => {
return <ConversationHistory onSelect={() => setTab(WEBUI_TABS.chat)} />
}

const element: JSX.Element = tabs[tab]
const allTabs = { ...tabs, ...tabsWithProps }

const element: JSX.Element = allTabs[tab]

return element || null
}
Loading

0 comments on commit ae9fb19

Please sign in to comment.