From 2b91b27b258749ae4b51ebf41cd074a0b5c8f7e0 Mon Sep 17 00:00:00 2001 From: rjmacarthy Date: Tue, 19 Nov 2024 19:30:49 +0000 Subject: [PATCH 1/5] refactor symmetry service --- src/common/constants.ts | 2 +- src/extension/symmetry-service.ts | 180 +++++++++++++++--------------- 2 files changed, 88 insertions(+), 94 deletions(-) diff --git a/src/common/constants.ts b/src/common/constants.ts index fbdac2b..b590280 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -25,7 +25,7 @@ export const SKIP_IMPORT_KEYWORDS_AFTER = ["from", "as", "import"] export const MIN_COMPLETION_CHUNKS = 2 export const MAX_EMPTY_COMPLETION_CHARS = 250 export const DEFAULT_RERANK_THRESHOLD = 0.5 -export const URL_SYMMETRY_WS = "wss://twinny.dev/ws" +export const URL_SYMMETRY_WS = "http://twinny.dev/ws" export const defaultChunkOptions = { maxSize: 500, diff --git a/src/extension/symmetry-service.ts b/src/extension/symmetry-service.ts index c7d9d1c..2055549 100644 --- a/src/extension/symmetry-service.ts +++ b/src/extension/symmetry-service.ts @@ -8,8 +8,7 @@ import os from "os" import path from "path" import { EventEmitter } from "stream" import { serverMessageKeys, SymmetryProvider } from "symmetry-core" -import * as vscode from "vscode" -import { commands, ExtensionContext, Webview, window, workspace } from "vscode" +import { commands, ExtensionContext, Webview, workspace } from "vscode" import { ACTIVE_CHAT_PROVIDER_STORAGE_KEY, @@ -45,7 +44,6 @@ export class SymmetryService extends EventEmitter { private _config = workspace.getConfiguration("twinny") private _completion = "" private _context: ExtensionContext - private _emitterKey = "" private _provider: SymmetryProvider | undefined private _providerPeer: undefined | Peer private _providerSwarm: undefined | typeof Hyperswarm @@ -107,38 +105,40 @@ export class SymmetryService extends EventEmitter { this._providerTopic = discoveryKey this._serverSwarm.join(this._providerTopic, { client: true, server: false }) this._serverSwarm.flush() - this._serverSwarm.on("connection", (peer: Peer) => { - this._serverPeer = peer - peer.write( - createSymmetryMessage(serverMessageKeys.requestProvider, { - modelName: model - }) - ) - peer.on("data", (message: Buffer) => { - const data = safeParseJson>( - message.toString() - ) - if (data && data.key) { - switch (data?.key) { - case serverMessageKeys.ping: - this._providerPeer?.write( - createSymmetryMessage(serverMessageKeys.pong) - ) - break - case serverMessageKeys.providerDetails: - peer.write( - createSymmetryMessage( - serverMessageKeys.verifySession, - data.data?.sessionToken - ) - ) - break - case serverMessageKeys.sessionValid: - this.connectToProvider(data.data) - } - } + this._serverSwarm.on("connection", (peer: Peer) => + this.handleServerConnection(peer, model) + ) + } + + private handleServerConnection = (peer: Peer, model: string | undefined) => { + this._serverPeer = peer + peer.write( + createSymmetryMessage(serverMessageKeys.requestProvider, { + modelName: model }) - }) + ) + peer.on("data", this.handleServerData) + } + + private handleServerData = (message: Buffer) => { + const data = safeParseJson>( + message.toString() + ) + if (!data || !data.key) return + + switch (data.key) { + case serverMessageKeys.providerDetails: + this._serverPeer?.write( + createSymmetryMessage( + serverMessageKeys.verifySession, + data.data?.sessionToken + ) + ) + break + case serverMessageKeys.sessionValid: + this.connectToProvider(data.data) + break + } } public disconnect = async () => { @@ -160,59 +160,51 @@ export class SymmetryService extends EventEmitter { server: false }) this._providerSwarm.flush() - this._providerSwarm.on("connection", (peer: any) => { - this._providerPeer = peer - this.providerListeners(peer) - this._webView?.postMessage({ - type: EVENT_NAME.twinnyConnectedToSymmetry, - value: { - data: { - modelName: connection.modelName, - name: connection.name, - provider: connection.provider - } - } - }) - this._webView?.postMessage({ - type: EVENT_NAME.twinnySetTab, - value: { - data: WEBUI_TABS.chat - } - }) - this._sessionManager?.set( - EXTENSION_SESSION_NAME.twinnySymmetryConnection, - connection - ) - commands.executeCommand( - "setContext", - EXTENSION_CONTEXT_NAME.twinnySymmetryTab, - false - ) + this._providerSwarm.on("connection", (peer: any) => + this.handleProviderConnection(peer, connection) + ) + } + + private handleProviderConnection(peer: Peer, connection: SymmetryConnection) { + this._providerPeer = peer + this.setupProviderListeners(peer) + this.notifyWebView(EVENT_NAME.twinnyConnectedToSymmetry, { + data: { + modelName: connection.modelName, + name: connection.name, + provider: connection.provider + } }) - return this + this.notifyWebView(EVENT_NAME.twinnySetTab, { data: WEBUI_TABS.chat }) + this._sessionManager?.set( + EXTENSION_SESSION_NAME.twinnySymmetryConnection, + connection + ) + commands.executeCommand( + "setContext", + EXTENSION_CONTEXT_NAME.twinnySymmetryTab, + false + ) } - private providerListeners = (peer: any) => { + private setupProviderListeners(peer: Peer) { peer.on("data", (chunk: Buffer) => { const str = chunk.toString() - if (str.includes("symmetryEmitterKey")) - this._emitterKey = JSON.parse(str).symmetryEmitterKey - - if (!this._emitterKey) return - if (str.includes(serverMessageKeys.inferenceEnded)) this.handleInferenceEnd() - - this.handleIncomingData(chunk, (response: StreamResponse) => { - if (!this._symmetryProvider) return - const data = getChatDataFromProvider(this._symmetryProvider, response) - this._completion = this._completion + data - if (!data) return - this.emit(this._emitterKey, this._completion) - }) + this.handleIncomingData(chunk, (response: StreamResponse) => + this.processResponseData(response) + ) }) } + private processResponseData(response: StreamResponse) { + if (!this._symmetryProvider) return + const data = getChatDataFromProvider(this._symmetryProvider, response) + this._completion += data + if (data) this.emit(SYMMETRY_EMITTER_KEY.inference, this._completion) + } + private handleInferenceEnd() { commands.executeCommand( "setContext", @@ -221,14 +213,12 @@ export class SymmetryService extends EventEmitter { ) if (!this._completion) return - if (this._emitterKey === SYMMETRY_EMITTER_KEY.inference) { - this._webView?.postMessage({ - type: EVENT_NAME.twinnyOnEnd, - value: { - completion: this._completion.trimStart() - } - } as ServerMessage) - } + this._webView?.postMessage({ + type: EVENT_NAME.twinnyOnEnd, + value: { + completion: this._completion.trimStart() + } + } as ServerMessage) this._completion = "" } @@ -251,13 +241,6 @@ export class SymmetryService extends EventEmitter { } } - public getChatProvider() { - const provider = this._context?.globalState.get( - ACTIVE_CHAT_PROVIDER_STORAGE_KEY - ) - return provider - } - private getSymmetryConfigPath(): string { const homeDir = os.homedir() return path.join(homeDir, ".config", "symmetry", "provider.yaml") @@ -288,7 +271,7 @@ export class SymmetryService extends EventEmitter { systemMessage: "" }) - return fs.promises.writeFile(configPath, symmetryConfiguration, "utf8"); + return fs.promises.writeFile(configPath, symmetryConfiguration, "utf8") } public startSymmetryProvider = async () => { @@ -325,6 +308,17 @@ export class SymmetryService extends EventEmitter { }) } + private notifyWebView(type: string, value: any = {}) { + this._webView?.postMessage({ type, value }) + } + + public getChatProvider() { + const provider = this._context?.globalState.get( + ACTIVE_CHAT_PROVIDER_STORAGE_KEY + ) + return provider + } + public stopSymmetryProvider = async () => { await this._provider?.destroySwarms() updateSymmetryStatus(this._webView, "disconnected") From 73db5f9fbf8994e8ad9fb505230ace187321d098 Mon Sep 17 00:00:00 2001 From: rjmacarthy Date: Tue, 19 Nov 2024 19:30:54 +0000 Subject: [PATCH 2/5] 3.19.8 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index bdd19b5..a6366a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "twinny", - "version": "3.19.7", + "version": "3.19.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twinny", - "version": "3.19.7", + "version": "3.19.8", "cpu": [ "x64", "arm64" diff --git a/package.json b/package.json index 488412f..8a87063 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "twinny", "displayName": "twinny - AI Code Completion and Chat", "description": "Locally hosted AI code completion plugin for vscode", - "version": "3.19.7", + "version": "3.19.8", "icon": "assets/icon.png", "keywords": [ "code-inference", From d7c82f6d561072a849802e9c3e87df8af5db9564 Mon Sep 17 00:00:00 2001 From: rjmacarthy Date: Tue, 19 Nov 2024 19:31:43 +0000 Subject: [PATCH 3/5] update symmetry-core --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a6366a9..51f4388 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.0", "string_score": "^0.1.22", - "symmetry-core": "^1.0.13", + "symmetry-core": "^1.0.14", "tippy.js": "^6.3.7", "tiptap-markdown": "^0.8.10", "toxe": "^1.1.0", @@ -15968,9 +15968,9 @@ } }, "node_modules/symmetry-core": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/symmetry-core/-/symmetry-core-1.0.13.tgz", - "integrity": "sha512-szkqvTvzkcZzDbdYcqaoMNwjRqXtjyw2OBtzCjX2xwZbROy5tlVA8Trsi71Xfenybrzj/SgdHzvDhWuTYumiYg==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/symmetry-core/-/symmetry-core-1.0.14.tgz", + "integrity": "sha512-1KW9Mpgx8ZPgW77Jwv1X/qf7eaVjI8pJ/nCo8F+9QPWfy7BSTX0Bcx1iZhxy+iR7Dm1uyExiTzvp/G0/UlhlGw==", "dependencies": { "chalk": "^4.1.2", "commander": "^12.1.0", diff --git a/package.json b/package.json index 8a87063..8194f35 100644 --- a/package.json +++ b/package.json @@ -512,7 +512,7 @@ "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.0", "string_score": "^0.1.22", - "symmetry-core": "^1.0.13", + "symmetry-core": "^1.0.14", "tippy.js": "^6.3.7", "tiptap-markdown": "^0.8.10", "toxe": "^1.1.0", From f0d8307994bd39d7b79137038edef652d0f26706 Mon Sep 17 00:00:00 2001 From: rjmacarthy Date: Tue, 19 Nov 2024 19:38:13 +0000 Subject: [PATCH 4/5] https --- src/common/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/constants.ts b/src/common/constants.ts index b590280..201fcbd 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -25,7 +25,7 @@ export const SKIP_IMPORT_KEYWORDS_AFTER = ["from", "as", "import"] export const MIN_COMPLETION_CHUNKS = 2 export const MAX_EMPTY_COMPLETION_CHARS = 250 export const DEFAULT_RERANK_THRESHOLD = 0.5 -export const URL_SYMMETRY_WS = "http://twinny.dev/ws" +export const URL_SYMMETRY_WS = "https://twinny.dev/ws" export const defaultChunkOptions = { maxSize: 500, From e9709d908681565d51ecffa153d81bc406e7cf74 Mon Sep 17 00:00:00 2001 From: ZhongGs Date: Sun, 1 Dec 2024 19:09:43 +0800 Subject: [PATCH 5/5] translate/de --- src/webview/assets/locales/de.json | 91 ++++++++++++++++++++++++++++++ src/webview/assets/locales/en.json | 1 + 2 files changed, 92 insertions(+) create mode 100644 src/webview/assets/locales/de.json diff --git a/src/webview/assets/locales/de.json b/src/webview/assets/locales/de.json new file mode 100644 index 0000000..00bf3a0 --- /dev/null +++ b/src/webview/assets/locales/de.json @@ -0,0 +1,91 @@ +{ + "accept-solution": "Akzeptiere Lösung", + "api-key-placeholder": "Geben Sie hier Ihren API-Schlüssel ein", + "api-key": "API-Schlüssel", + "api-path-placeholder": "Geben Sie einen Hostnamen ein, z.B. 'localhost'", + "api-path": "API-Pfad", + "applicable-ollama": "Für einige Anbieter wie Ollama anwendbar", + "auto-connect-as-provider": "Automatisch als Anbieter verbinden", + "automatic": "Automatisch", + "cancel-edit": "Bearbeitung abbrechen", + "cancel": "Abbrechen", + "chat": "Chat", + "clear-conversations": "Unterhaltungen löschen", + "connect": "Verbinden", + "connected": "Verbunden!", + "connecting": "Verbindung wird hergestellt...", + "connection-failed": "Verbindung fehlgeschlagen! Bitte überprüfen Sie Ihre Verbindung und versuchen Sie es erneut.", + "consumer-connection": "Kundenverbindung", + "conversation-history": "Gesprächsverlauf", + "copy-code": "Code kopieren", + "copy-provider": "Anbieter kopieren", + "delete-message": "Nachricht löschen", + "delete-provider": "Anbieter löschen", + "disconnect": "Trennen", + "edit-default-templates-description": "Bearbeiten Sie die Standardvorlagen, die in der Twinny-Erweiterung verwendet werden.", + "edit-default-templates": "Standardvorlagen bearbeiten", + "edit-message": "Nachricht bearbeiten", + "edit-provider": "Anbieter bearbeiten", + "embed-documents": "Dokumente einbetten", + "embedding-provider": "Anbieter einbetten", + "fim-template": "FIM-Vorlage", + "fim": "Füll-in-Mitte", + "hostname-placeholder": "Geben Sie einen Hostnamen ein, z.B. 'localhost'", + "hostname": "Hostname", + "label-placeholder": "Geben Sie eine Beschriftung für Ihren Anbieter ein.", + "label": "Beschriftung", + "loading-available-models": "Verfügbare Modelle werden geladen...", + "max-chunk-size": "Maximale Stückgröße", + "min-chunk-size": "Minimale Stückgröße", + "model-name-placeholder": "Geben Sie einen Modellnamen ein, z.B. 'llama3'", + "model-name": "Modellname", + "new-conversation": "Neue Unterhaltung", + "new-document": "Neues Dokument", + "no-connections-found": "Keine Verbindungen gefunden. Bitte fügen Sie eine neue Verbindung hinzu, um zu beginnen.", + "no-result": "Kein Ergebnis", + "nothing-to-see-here": "Hier gibt es nichts zu sehen.", + "number-code-filepaths": "Anzahl der als Kontext zu verwendenden Dateipfade.", + "number-code-snippets": "Anzahl der als Kontext zu verwendenden Code-Schnipsel.", + "open-diff": "Differenz-Ansicht öffnen", + "open-template-editor": "Vorlagen-Editor öffnen", + "overlap-size": "Überlappungsgröße", + "owner-repo-name": "Dieser Tab hilft Ihnen, Pull Requests in Ihrem Repository zu überprüfen, geben Sie den Besitzer und Repository-Namen ein, um zu beginnen. Derzeit wird nur GitHub unterstützt, setzen Sie Ihren GitHub-Token in der Einstellungen, um zu beginnen.", + "path": "Pfad", + "placeholder": "Wie kann Twinny Ihnen heute helfen?", + "port-placeholder": "Geben Sie eine Portnummer ein, z.B. '11434'", + "port": "Port", + "protocol": "Protokoll", + "provider-connection": "Anbieterverbindung", + "provider-name": "Anbietername", + "provider-placeholder": "Geben Sie einen Anbieternamen ein", + "provider-type": "Anbietertyp", + "provider": "Anbieter", + "providers": "Anbieter", + "pull-requests": "Pull Requests", + "regenerate-message": "Nachricht neu generieren", + "relevant-code-snippets": "Relevante Code-Schnipsel", + "relevant-file-paths": "Relevante Dateipfade", + "repository-level": "Repositoryebene", + "rerank-probability-threshold": "Wahrscheinlichkeitsschwelle für Neusortierung", + "rerank-threshold-description": "Je niedriger der Schwellenwert, desto wahrscheinlicher, dass Ergebnisse enthalten sind.", + "rerank-threshold": "Neusortierungsschwelle", + "reset-providers": "Anbieter zurücksetzen", + "reset-to-default": "Auf Standard zurücksetzen", + "review-pull-requests": "Pull Requests überprüfen", + "save-edit": "Bearbeitung speichern", + "save": "Speichern", + "scroll-down": "Nach unten scrollen", + "share-gpu-resources": "Sie können Ihre GPU-Ressourcen auch teilen, indem Sie sich als Anbieter mit Symmetry verbinden, indem Sie Ihre aktive Twinny-Anbieterkonfiguration verwenden. Alle Verbindungen sind peer-to-peer, verschlüsselt und sicher.", + "status": "Status", + "stop-generation": "Generierung stoppen", + "symmetry-description": "Symmetry ist ein peer-to-peer AI-Schlussfolgerungsnetzwerk, das es Benutzern ermöglicht, sich sicher und direkt miteinander zu verbinden. Wenn Sie sich als Verbraucher verbinden, wird Symmetry Ihnen basierend auf Ihrer Modellauswahl einen Anbieter zuweisen.", + "symmetry-inference-network": "Symmetry-Schlussfolgerungsnetzwerk", + "template-settings-description": "Wählen Sie die Vorlagen, die Sie in der Chat-Oberfläche verwenden möchten.", + "template-settings": "Vorlagen-Einstellungen", + "thinking": "Überlege...", + "toggle-auto-scroll": "Auto-Scroll ein-/ausschalten", + "toggle-embedding-options": "Einbettungsoptionen ein-/ausschalten", + "toggle-provider-selection": "Anbieterauswahl umschalten", + "type": "Typ" +} + \ No newline at end of file diff --git a/src/webview/assets/locales/en.json b/src/webview/assets/locales/en.json index e7c5132..cb95389 100644 --- a/src/webview/assets/locales/en.json +++ b/src/webview/assets/locales/en.json @@ -88,3 +88,4 @@ "toggle-provider-selection": "Toggle provider selection", "type": "Type" } + \ No newline at end of file