Skip to content

Commit

Permalink
connect as symmetry provider inside vscode
Browse files Browse the repository at this point in the history
  • Loading branch information
rjmacarthy committed Aug 21, 2024
1 parent 36e648b commit 88a6536
Show file tree
Hide file tree
Showing 8 changed files with 1,572 additions and 168 deletions.
1,288 changes: 1,208 additions & 80 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@
"devDependencies": {
"@hyrious/esbuild-plugin-commonjs": "^0.2.4",
"@types/async-lock": "^1.4.2",
"@types/js-yaml": "^4.0.9",
"@types/minimatch": "^5.1.2",
"@types/mocha": "^10.0.6",
"@types/node": "^16.18.68",
Expand Down Expand Up @@ -464,6 +465,7 @@
"handlebars-loader": "^1.7.3",
"hypercore-crypto": "^3.4.2",
"hyperswarm": "^4.7.15",
"js-yaml": "^4.1.0",
"minimatch": "^9.0.4",
"node-polyfill-webpack-plugin": "^3.0.0",
"onnxruntime-web": "^1.18.0",
Expand All @@ -476,6 +478,7 @@
"remark-gfm": "^4.0.0",
"stream-http": "^3.2.0",
"string_score": "^0.1.22",
"symmetry-client": "^1.0.2",
"tippy.js": "^6.3.7",
"tiptap-markdown": "^0.8.10",
"toxe": "^1.1.0",
Expand Down
20 changes: 11 additions & 9 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,12 @@ export const EVENT_NAME = {
twinnyRerankThresholdChanged: 'twinny-rerank-threshold-changed',
twinnySendLanguage: 'twinny-send-language',
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',
Expand Down Expand Up @@ -132,6 +135,10 @@ export const ACTIVE_FIM_PROVIDER_STORAGE_KEY = 'twinny.active-fim-provider'
export const CONVERSATION_STORAGE_KEY = 'twinny.conversations'
export const INFERENCE_PROVIDERS_STORAGE_KEY = 'twinny.inference-providers'

export const GLOBAL_STORAGE_KEY = {
autoConnectSymmetryProvider: 'twinny.autoConnectSymmetryProvider'
}

export const WORKSPACE_STORAGE_KEY = {
autoScroll: 'autoScroll',
chatMessage: 'chatMessage',
Expand Down Expand Up @@ -160,13 +167,14 @@ export const EXTENSION_CONTEXT_NAME = {
twinnyOverlapSize: 'twinnyOverlapSize',
twinnyRelevantFilePaths: 'twinnyRelevantFilePaths',
twinnyRelevantCodeSnippets: 'twinnyRelevantCodeSnippets',
twinnyVectorSearchMetric : 'twinnyVectorSearchMetric',
twinnyVectorSearchMetric: 'twinnyVectorSearchMetric',
twinnySymmetryTab: 'twinnySymmetryTab',
twinnyEnableRag: 'twinnyEnableRag'
}

export const EXTENSION_SESSION_NAME = {
twinnySymmetryConnection: 'twinnySymmetryConnection'
twinnySymmetryConnection: 'twinnySymmetryConnection',
twinnySymmetryConnectionProvider: 'twinnySymmetryConnectionProvider'
}

export const WEBUI_TABS = {
Expand Down Expand Up @@ -409,11 +417,7 @@ export const DEFAULT_RELEVANT_FILE_COUNT = 10
export const DEFAULT_RELEVANT_CODE_COUNT = 5
export const DEFAULT_VECTOR_SEARCH_METRIC = 'l2'

export const EMBEDDING_METRICS = [
'cosine',
'l2',
'dot'
]
export const EMBEDDING_METRICS = ['cosine', 'l2', 'dot']

export const MULTILINE_OUTSIDE = [
'class_body',
Expand Down Expand Up @@ -442,8 +446,6 @@ export const MULTILINE_TYPES = [...MULTILINE_OUTSIDE, ...MULTILINE_INSIDE]

export const MULTI_LINE_DELIMITERS = ['\n\n', '\r\n\r\n']



export const SYMMETRY_DATA_MESSAGE = {
disconnect: 'disconnect',
heartbeat: 'heartbeat',
Expand Down
13 changes: 12 additions & 1 deletion src/extension/providers/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
[EVENT_NAME.twinnyConnectSymmetry]: this.connectToSymmetry,
[EVENT_NAME.twinnyDisconnectSymmetry]: this.disconnectSymmetry,
[EVENT_NAME.twinnySessionContext]: this.getSessionContext,
[EVENT_NAME.twinnyStartSymmetryProvider]: this.createSymmetryProvider,
[EVENT_NAME.twinnyStopSymmetryProvider]: this.stopSymmetryProvider,

}
eventHandlers[message.type as string]?.(message)
}
Expand Down Expand Up @@ -252,7 +255,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider {

const messages = [systemMessage, ...(data.data as Message[])]

updateLoadingMessage(this.view, 'Using symmetry for inference...')
updateLoadingMessage(this.view, 'Using symmetry for inference')

logger.log(`
Using symmetry for inference
Expand Down Expand Up @@ -434,6 +437,14 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
}
}

public createSymmetryProvider = () => {
this.symmetryService?.startSymmetryProvider()
}

public stopSymmetryProvider = () => {
this.symmetryService?.stopSymmetryProvider()
}

private twinnyHideBackButton() {
vscode.commands.executeCommand(TWINNY_COMMAND_NAME.hideBackButton)
}
Expand Down
119 changes: 112 additions & 7 deletions src/extension/symmetry-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
import { workspace, commands, WebviewView, ExtensionContext } from 'vscode'
import Hyperswarm from 'hyperswarm'
import crypto from 'hypercore-crypto'
import { SymmetryProvider } from 'symmetry-client'
import path from 'path'
import os from 'os'
import fs from 'fs'
import yaml from 'js-yaml'

import b4a from 'b4a'
import {
createSymmetryMessage,
safeParseJson,
safeParseJsonResponse
safeParseJsonResponse,
updateSymmetryStatus
} from './utils'
import { getChatDataFromProvider } from './utils'
import {
Expand All @@ -23,10 +29,13 @@ import {
EXTENSION_SESSION_NAME,
SYMMETRY_EMITTER_KEY,
SYMMETRY_DATA_MESSAGE,
WEBUI_TABS
WEBUI_TABS,
ACTIVE_CHAT_PROVIDER_STORAGE_KEY,
GLOBAL_STORAGE_KEY
} from '../common/constants'
import { SessionManager } from './session-manager'
import { EventEmitter } from 'stream'
import { TwinnyProvider } from './provider-manager'

export class SymmetryService extends EventEmitter {
private _config = workspace.getConfiguration('twinny')
Expand All @@ -40,6 +49,7 @@ export class SymmetryService extends EventEmitter {
private _context: ExtensionContext
private _providerTopic: Buffer | undefined
private _emitterKey = ''
private _provider: SymmetryProvider | undefined

constructor(
view: WebviewView | undefined,
Expand All @@ -53,6 +63,10 @@ export class SymmetryService extends EventEmitter {
this._providerPeer
this._context = context
this._providerTopic
const autoConnectProvider = this._context.globalState.get(
`${EVENT_NAME.twinnyGlobalContext}-${GLOBAL_STORAGE_KEY.autoConnectSymmetryProvider}`
)
if (autoConnectProvider) this.startSymmetryProvider()
}

public connect = async (key: string) => {
Expand All @@ -76,8 +90,10 @@ export class SymmetryService extends EventEmitter {
if (data && data.key) {
switch (data?.key) {
case SYMMETRY_DATA_MESSAGE.ping:
this._providerPeer?.write(createSymmetryMessage(SYMMETRY_DATA_MESSAGE.pong));
break;
this._providerPeer?.write(
createSymmetryMessage(SYMMETRY_DATA_MESSAGE.pong)
)
break
case SYMMETRY_DATA_MESSAGE.providerDetails:
peer.write(
createSymmetryMessage(
Expand Down Expand Up @@ -122,20 +138,25 @@ export class SymmetryService extends EventEmitter {
data: {
modelName: connection.modelName,
name: connection.name,
provider: connection.provider,
provider: connection.provider
}
}
})
this.view?.webview.postMessage({
type: EVENT_NAME.twinnySetTab,
value: {
data: WEBUI_TABS.chat,
data: WEBUI_TABS.chat
}
})
this._sessionManager?.set(
EXTENSION_SESSION_NAME.twinnySymmetryConnection,
connection
)
commands.executeCommand(
'setContext',
EXTENSION_CONTEXT_NAME.twinnySymmetryTab,
false
)
})
return this
}
Expand All @@ -152,7 +173,10 @@ export class SymmetryService extends EventEmitter {
this.handleInferenceEnd()

this.handleIncomingData(chunk, (response: StreamResponse) => {
const data = getChatDataFromProvider(this._config.symmetryProvider, response)
const data = getChatDataFromProvider(
this._config.symmetryProvider,
response
)
this._completion = this._completion + data
if (!data) return
this.emit(this._emitterKey, this._completion)
Expand Down Expand Up @@ -198,6 +222,87 @@ export class SymmetryService extends EventEmitter {
}
}

public getChatProvider() {
const provider = this._context?.globalState.get<TwinnyProvider>(
ACTIVE_CHAT_PROVIDER_STORAGE_KEY
)
return provider
}

private getSymmetryConfigPath(): string {
const homeDir = os.homedir()
return path.join(homeDir, '.config', 'symmetry', 'provider.yaml')
}

private createOrUpdateProviderConfig(providerConfig: TwinnyProvider): void {
const configPath = this.getSymmetryConfigPath()
const configDir = path.dirname(configPath)

if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true })
}

const symmetryConfiguration = yaml.dump({
apiHostname: providerConfig.apiHostname,
apiKey: providerConfig.apiKey,
apiPath: providerConfig.apiPath,
apiPort: providerConfig.apiPort,
apiProtocol: providerConfig.apiProtocol,
apiProvider: providerConfig.provider,
dataCollectionEnabled: false,
maxConnections: 10,
modelName: providerConfig.modelName,
name: os.hostname(),
path: configPath,
public: true,
serverKey: this._config.symmetryServerKey,
systemMessage: ''
})

fs.writeFileSync(configPath, symmetryConfiguration, 'utf8')
}

public async startSymmetryProvider() {
const providerConfig = this.getChatProvider()

if (!providerConfig) return

const configPath = this.getSymmetryConfigPath()

if (!fs.existsSync(configPath)) {
this.createOrUpdateProviderConfig(providerConfig)
}

this._provider = new SymmetryProvider(configPath)

const sessionKey = EXTENSION_SESSION_NAME.twinnySymmetryConnectionProvider

this._sessionManager?.set(sessionKey, 'connecting')

const sessionTypeName = `${EVENT_NAME.twinnySessionContext}-${sessionKey}`

this.view?.webview.postMessage({
type: sessionTypeName,
value: 'connecting'
})

await this._provider.init()

this._sessionManager?.set(sessionKey, 'connected')

this.view?.webview.postMessage({
type: sessionTypeName,
value: 'connected'
})
}

public async stopSymmetryProvider() {
await this._provider?.destroySwarms()
updateSymmetryStatus(this.view, 'disconnected')
const sessionKey = EXTENSION_SESSION_NAME.twinnySymmetryConnectionProvider
this._sessionManager?.set(sessionKey, 'disconnected')
}

public write(message: string) {
this._providerPeer?.write(message)
}
Expand Down
12 changes: 12 additions & 0 deletions src/extension/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,18 @@ export const updateLoadingMessage = (
} as ServerMessage<string>)
}

export const updateSymmetryStatus = (
view: WebviewView | undefined,
message: string
) => {
view?.webview.postMessage({
type: EVENT_NAME.twinnySendSymmetryMessage,
value: {
data: message
}
} as ServerMessage<string>)
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const logStreamOptions = (opts: any) => {
logger.log(
Expand Down
Loading

0 comments on commit 88a6536

Please sign in to comment.